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/.clang-format b/.clang-format new file mode 100644 index 0000000000000..f97f1bb27aa74 --- /dev/null +++ b/.clang-format @@ -0,0 +1,35 @@ +# Defines the Chromium style for automatic reformatting. +# http://clang.llvm.org/docs/ClangFormatStyleOptions.html +BasedOnStyle: Chromium +# This defaults to 'Auto'. Explicitly set it for a while, so that +# 'vector >' in existing files gets formatted to +# 'vector>'. ('Auto' means that clang-format will only use +# 'int>>' if the file already contains at least one such instance.) +Standard: Cpp11 +# Make sure code like: +# IPC_BEGIN_MESSAGE_MAP() +# IPC_MESSAGE_HANDLER(WidgetHostViewHost_Update, OnUpdate) +# IPC_END_MESSAGE_MAP() +# gets correctly indented. +MacroBlockBegin: "^\ +BEGIN_MSG_MAP|\ +BEGIN_MSG_MAP_EX|\ +BEGIN_SAFE_MSG_MAP_EX|\ +CR_BEGIN_MSG_MAP_EX|\ +IPC_BEGIN_MESSAGE_MAP|\ +IPC_BEGIN_MESSAGE_MAP_WITH_PARAM|\ +IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN|\ +IPC_STRUCT_BEGIN|\ +IPC_STRUCT_BEGIN_WITH_PARENT|\ +IPC_STRUCT_TRAITS_BEGIN|\ +POLPARAMS_BEGIN|\ +PPAPI_BEGIN_MESSAGE_MAP$" +MacroBlockEnd: "^\ +CR_END_MSG_MAP|\ +END_MSG_MAP|\ +IPC_END_MESSAGE_MAP|\ +IPC_PROTOBUF_MESSAGE_TRAITS_END|\ +IPC_STRUCT_END|\ +IPC_STRUCT_TRAITS_END|\ +POLPARAMS_END|\ +PPAPI_END_MESSAGE_MAP$" 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..0d837fefb8d1b --- /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"` +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..b0d96b374fae5 --- /dev/null +++ b/.claude/skills/electron-chromium-upgrade/references/phase-one-commit-guidelines.md @@ -0,0 +1,147 @@ +# 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. + +## Lint Enforcement + +Commits on `roller/chromium/*` branches are validated by `script/lint-roller-chromium-changes.mjs`. Every commit MUST match one of the allowed patterns below — there is no fallback. If a commit cannot be made to match an allowed pattern, add a `Skip-Lint: ` trailer as a last-resort escape hatch. + +Allowed commit patterns: + +1. `fixup! ` — fixup against another commit on the branch +2. `chore: bump chromium in DEPS to ` — must be the *only* change to `DEPS`, no other files +3. `chore: update patches` — exact title, no commit body, only non-content patch changes (index hashes, line numbers, hunk headers) +4. A commit referencing one Chromium CL: title must be exactly `: ` +5. A commit referencing multiple Chromium CLs: title is not enforced + +A Chromium CL is referenced by including the full Gerrit URL anywhere in the commit message, e.g. `Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7536483`. Appending `#nolint` to the URL excludes that CL from validation (and from the single-CL title check). + +## 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: `). + +### Patch conflict fixes + +Use the upstream CL number and original title as the commit title: + +``` +: + +Ref: + +Co-Authored-By: +``` + +Use the **upstream CL's original commit title** verbatim — do not paraphrase or rewrite it. To find it: `git log -1 --format=%s `. + +For a CL link in the format `https://chromium-review.googlesource.com/c/chromium/src/+/7536483` the `CL-Number` is `7536483`. + +Only add a description body if it provides clarity beyond the title (e.g., when the patch adaptation is non-obvious). For straightforward context drift or simple API renames, the title + Ref is sufficient. + +### 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 patches + +Ref: +Ref: +... + +Co-Authored-By: +``` + +Including multiple `Ref:` lines satisfies the linter (multi-CL commits skip the title format check). Extract each CL URL from the patch file's `Reviewed-on:` trailer (for cherry-picks) or by searching the upstream history (for non-cherry-pick patches). + +If only one patch is being removed and you can identify its corresponding CL, prefer the single-CL format from "Patch conflict fixes" above so the commit conforms to the standard `: ` pattern. Fall back to `chore: remove upstreamed patches` (plural) only when grouping multiple removals. + +### Trivial patch updates + +After all fix commits, stage remaining trivial changes (index hashes, line numbers, context lines only): + +```bash +git add patches +git commit -m "chore: update patches" +``` + +The commit message MUST be exactly `chore: update patches` — no qualifier, no body, no trailers. The linter rejects this commit if any patch file contains `+`/`-` content lines (lines that are not diff headers, hunk markers, or `index` lines). + +**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 `: ` 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 can be found after thorough searching, the commit must use a `Skip-Lint` trailer (it will otherwise fail lint): + +``` + + +Co-Authored-By: +Skip-Lint: +``` + +Skip-Lint is a last resort. Do not reach for it before genuinely exhausting the search. + +## Example Commits + +### Patch conflict fix (simple — title is sufficient) + +``` +7536483: [DomStorage] Share PurgeOrigins() between LevelDB and SQLite + +Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7536483 + +Co-Authored-By: +``` + +### Patch conflict fix (complex — description adds value) + +``` +7540447: Cleanup Keychain V1 + +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: +``` + +### Upstreamed patch removal (multiple) + +``` +chore: remove upstreamed patches + +Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7531001 +Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7531234 + +Co-Authored-By: +``` + +### Trivial patch updates + +``` +chore: update patches +``` + +(No body, no trailers.) 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..cbb44ffab6083 --- /dev/null +++ b/.claude/skills/electron-chromium-upgrade/references/phase-two-commit-guidelines.md @@ -0,0 +1,109 @@ +# 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. + +## Lint Enforcement + +Commits on `roller/chromium/*` branches are validated by `script/lint-roller-chromium-changes.mjs`. Every commit MUST match one of the allowed patterns below — there is no fallback. If a commit cannot be made to match an allowed pattern, add a `Skip-Lint: ` trailer as a last-resort escape hatch. + +Allowed commit patterns: + +1. `fixup! ` — fixup against another commit on the branch +2. `chore: bump chromium in DEPS to ` — must be the *only* change to `DEPS`, no other files +3. `chore: update patches` — exact title, no commit body, only non-content patch changes (index hashes, line numbers, hunk headers) +4. A commit referencing one Chromium CL: title must be exactly `: ` +5. A commit referencing multiple Chromium CLs: title is not enforced + +A Chromium CL is referenced by including the full Gerrit URL anywhere in the commit message, e.g. `Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7536483`. Appending `#nolint` to the URL excludes that CL from validation (and from the single-CL title check). + +## 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 (`: `). + +## 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" +``` + +The commit message MUST be exactly `chore: update patches` — no qualifier, no body, no trailers. The linter rejects this commit if any patch file contains `+`/`-` content lines (lines that are not diff headers, hunk markers, or `index` lines). + +## 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 can be found after thorough searching, the commit must use a `Skip-Lint` trailer (it will otherwise fail lint): + +``` + + +Co-Authored-By: +Skip-Lint: +``` + +Skip-Lint is a last resort. Do not reach for it before genuinely exhausting the search. + +## 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 new file mode 100644 index 0000000000000..7307e769482a1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +* +!tools/xvfb-init.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000000..333d92c3eda23 --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +# These env vars are only necessary for creating Electron releases. +# See docs/development/releasing.md + +ELECTRON_GITHUB_TOKEN= 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 new file mode 100644 index 0000000000000..f4542e6b25f8f --- /dev/null +++ b/.gitattributes @@ -0,0 +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 +*.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 +*.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 +*.sh text eol=lf +*.ts text eol=lf +*.txt text eol=lf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000000..f88c732a0feec --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,22 @@ +# Order is important. The LAST matching pattern has the MOST precedence. +# gitignore style patterns are used, not globs. +# https://help.github.com/articles/about-codeowners +# https://git-scm.com/docs/gitignore + +# Upgrades WG +/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 + +# Infra WG +/.claude/ @electron/wg-infra diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000000..54dc46395d3c0 --- /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 and include whether you use Wayland or X11. + placeholder: "e.g. Windows 11 25H2, macOS Tahoe 26.4.1, or Ubuntu 26.04 (Wayland)" + 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.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 new file mode 100644 index 0000000000000..ea5e97697b4f4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ +#### Description of Change + + + +#### Checklist + + +- [ ] 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/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: diff --git a/.github/actions/build-electron/action.yml b/.github/actions/build-electron/action.yml new file mode 100644 index 0000000000000..4751eb6ce56ec --- /dev/null +++ b/.github/actions/build-electron/action.yml @@ -0,0 +1,344 @@ +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 + + export NINJA_SUMMARIZE_BUILD=1 + export NO_COLOR=1 + if [ "${{ inputs.is-release }}" = "true" ]; then + e build --target electron:release_build + else + 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 .. + + $env:NINJA_SUMMARIZE_BUILD = 1 + $env:NO_COLOR = 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..0a91703cac8ae --- /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=c22d659a081014dc1b847bd3af23c449fdba09ca + 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/install-homebrew/action.yml b/.github/actions/install-homebrew/action.yml new file mode 100644 index 0000000000000..1564ebf63eb2f --- /dev/null +++ b/.github/actions/install-homebrew/action.yml @@ -0,0 +1,81 @@ +name: 'Install Homebrew' +description: 'Installs a pinned Homebrew release on macOS runners' +inputs: + version: + description: 'Homebrew release tag to install' + required: false + default: '5.1.10' + sha256: + description: 'SHA256 checksum of the Homebrew package' + required: false + default: 'ece2e1c1f8e34683bd29b324f70c405b48c210c47f2b71c06131fde5492f2462' +runs: + using: 'composite' + steps: + - name: Install pinned Homebrew + shell: bash + run: | + set -euo pipefail + + if [[ "$(uname -s)" != "Darwin" ]]; then + echo "This action only supports macOS runners." >&2 + exit 1 + fi + + target_version='${{ inputs.version }}' + brew_bin='' + + for candidate in /opt/homebrew/bin/brew /usr/local/bin/brew; do + if [[ -x "${candidate}" ]]; then + current_version="$("${candidate}" --version | awk 'NR == 1 { print $2 }')" + if [[ "${current_version}" == "${target_version}" ]]; then + brew_bin="${candidate}" + break + fi + fi + done + + if [[ -z "${brew_bin}" ]]; then + pkg_path="${RUNNER_TEMP}/Homebrew.pkg" + download_url="https://github.com/Homebrew/brew/releases/download/${target_version}/Homebrew.pkg" + + curl --fail --location --silent --show-error \ + --output "${pkg_path}" \ + "${download_url}" + + echo "Verifying Homebrew package SHA256 checksum..." + if ! printf '%s %s\n' "${{ inputs.sha256 }}" "${pkg_path}" | shasum -a 256 -c; then + echo "Homebrew package SHA256 checksum failed, aborting." >&2 + exit 1 + fi + + echo "Verifying Homebrew package with spctl..." + if ! spctl -a -vv --type install "${pkg_path}"; then + echo "Homebrew package installation verification failed, aborting." >&2 + exit 1 + fi + + echo "Homebrew package verification passed, installing..." + + sudo installer -pkg "${pkg_path}" -target / + + for candidate in /opt/homebrew/bin/brew /usr/local/bin/brew; do + if [[ -x "${candidate}" ]]; then + current_version="$("${candidate}" --version | awk 'NR == 1 { print $2 }')" + if [[ "${current_version}" == "${target_version}" ]]; then + brew_bin="${candidate}" + break + fi + fi + done + fi + + if [[ -z "${brew_bin}" ]]; then + echo "Pinned Homebrew ${target_version} was not installed successfully." >&2 + exit 1 + fi + + echo "$(dirname "${brew_bin}")" >> "${GITHUB_PATH}" + echo "HOMEBREW_NO_AUTO_UPDATE=1" >> "${GITHUB_ENV}" + + "${brew_bin}" --version 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 new file mode 100644 index 0000000000000..e1b6e49e1777b --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,36 @@ +# Comment to be posted to on PRs from first time contributors in your repository +newPRWelcomeComment: | + 💖 Thanks for opening this pull request! 💖 + + ### 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: + + - `fix: don't overwrite prevent_default if default wasn't prevented` + - `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/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/main/docs/styleguide.md). + - Include tests when adding/changing behavior. + - Include screenshots and animated GIFs whenever possible. + + We get a lot of pull requests on this repo, so please be patient and we will get back to you as soon as we can. + +# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge + +# Comment to be posted to on pull requests merged by a first time user +firstPRMergeComment: > + Congrats on merging your first pull request! 🎉🎉🎉 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/faraday.yml b/.github/faraday.yml new file mode 100644 index 0000000000000..02af5d4c0d5c2 --- /dev/null +++ b/.github/faraday.yml @@ -0,0 +1,12 @@ +# faraday trust configuration for electron/electron. +# A bot listed here is "trusted": its pull requests need 1 maintainer +# approval instead of 2, provided every commit is verifiably the bot's own. +# See: https://github.com/electron/faraday + +trusted-bots: + # Backport PRs to release branches. + - login: trop[bot] + id: 37223003 + # Chromium / Node.js roll PRs. + - login: electron-roller[bot] + id: 84116207 diff --git a/.github/problem-matchers/clang.json b/.github/problem-matchers/clang.json new file mode 100644 index 0000000000000..8bcac526661e5 --- /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+(?:fatal )?(warning|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/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..c0cae587024c7 --- /dev/null +++ b/.github/siso-patches/0002-siso-retry-transient-ERROR_INVALID_PARAMETER-when-op.patch @@ -0,0 +1,145 @@ +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. Without a +retry a single transient failure aborts the entire manifest load. + +Wrap the 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. + +diff --git a/siso/hashfs/state.go b/siso/hashfs/state.go +index 1be99639..abe2fbcc 100644 +--- a/siso/hashfs/state.go ++++ b/siso/hashfs/state.go +@@ -250,7 +250,7 @@ func loadFile(ctx context.Context, opts Option) ([]byte, error) { + if opts.UseMmap { + // Use mmap to read the compressed file. The data is backed by the + // OS page cache rather than the Go heap, avoiding a large allocation. +- data, err := mmapfile.Read(opts.StateFile) ++ data, err := mmapfile.Read(ctx, opts.StateFile) + if err != nil { + return nil, err + } +diff --git a/siso/mmapfile/mmap_unix.go b/siso/mmapfile/mmap_unix.go +index 345c02de..9bafe560 100644 +--- a/siso/mmapfile/mmap_unix.go ++++ b/siso/mmapfile/mmap_unix.go +@@ -7,6 +7,7 @@ + package mmapfile + + import ( ++ "context" + "fmt" + "os" + +@@ -16,7 +17,7 @@ import ( + // Read maps path read-only into memory. The returned slice is page-cache + // backed and stays valid until Unmap is called. An empty file returns + // (nil, nil). +-func Read(path string) ([]byte, error) { ++func Read(_ context.Context, path string) ([]byte, error) { + f, err := os.Open(path) + if err != nil { + return nil, err +diff --git a/siso/mmapfile/mmap_windows.go b/siso/mmapfile/mmap_windows.go +index fc00bc9e..31e16150 100644 +--- a/siso/mmapfile/mmap_windows.go ++++ b/siso/mmapfile/mmap_windows.go +@@ -7,6 +7,7 @@ + package mmapfile + + import ( ++ "context" + "fmt" + "os" + "unsafe" +@@ -17,8 +18,8 @@ import ( + // Read maps path read-only into memory. The returned slice is page-cache + // backed and stays valid until Unmap is called. An empty file returns + // (nil, nil). +-func Read(path string) ([]byte, error) { +- f, err := os.Open(path) ++func Read(ctx context.Context, path string) ([]byte, error) { ++ f, err := openFile(ctx, path) + if err != nil { + return nil, err + } +diff --git a/siso/mmapfile/openfile_windows.go b/siso/mmapfile/openfile_windows.go +new file mode 100644 +index 00000000..2c71562c +--- /dev/null ++++ b/siso/mmapfile/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 mmapfile ++ ++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 ++ } ++} +diff --git a/siso/toolsupport/ninjautil/file_parser.go b/siso/toolsupport/ninjautil/file_parser.go +index 39ed7af6..a81fc9a5 100644 +--- a/siso/toolsupport/ninjautil/file_parser.go ++++ b/siso/toolsupport/ninjautil/file_parser.go +@@ -110,7 +110,7 @@ func (p *fileParser) parseFile(ctx context.Context, fname string) error { + // not outlive Load, which releases all mappings before returning. + func (p *fileParser) readFile(ctx context.Context, fname string) ([]byte, error) { + defer trace.StartRegion(ctx, "ninja.read").End() +- buf, err := mmapfile.Read(fname) ++ buf, err := mmapfile.Read(ctx, fname) + if err != nil { + return nil, err + } 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..30ba66bc1046d --- /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@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3 + 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..0c7c21b64d694 --- /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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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..1d80cc303e959 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,467 @@ +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/**' + - '.github/ISSUE_TEMPLATE/**' + - '.github/PULL_REQUEST_TEMPLATE.md' + - '.github/config.yml' + - 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-xlarge + 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-16core + 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-16core + 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-16core + 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..f444a9eae4fcb --- /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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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..bf6f40b8ee43c --- /dev/null +++ b/.github/workflows/issue-labeled.yml @@ -0,0 +1,94 @@ +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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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 gh issue comment 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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - name: Create comment + if: ${{ steps.check-for-comment.outputs.SHOULD_COMMENT }} + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + GH_REPO: electron/electron + ISSUE_NUMBER: ${{ github.event.issue.number }} + run: | + gh issue comment "$ISSUE_NUMBER" --body-file - <<'EOF' + + + 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. + EOF diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml new file mode 100644 index 0000000000000..ca600ca6f98e4 --- /dev/null +++ b/.github/workflows/issue-opened.yml @@ -0,0 +1,162 @@ +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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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 }} + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + GH_REPO: electron/electron + ISSUE_NUMBER: ${{ github.event.issue.number }} + run: | + gh issue comment "$ISSUE_NUMBER" --body-file - <<'EOF' + + + 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. + EOF diff --git a/.github/workflows/issue-transferred.yml b/.github/workflows/issue-transferred.yml new file mode 100644 index 0000000000000..777c5a2ef3a0f --- /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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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..638246b75b76f --- /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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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..ef2cf5925382c --- /dev/null +++ b/.github/workflows/macos-disk-cleanup.yml @@ -0,0 +1,109 @@ +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/install-homebrew + .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: Install pinned Homebrew + uses: ./.github/actions/install-homebrew + + - 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..584866af8d464 --- /dev/null +++ b/.github/workflows/pipeline-electron-lint.yml @@ -0,0 +1,99 @@ +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 + - 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 + + # Clean things up so `depot_tools/gclient_paths.py` finds src/buildtools properly + rm -f .gclient_entries + + 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..adea4d3922960 --- /dev/null +++ b/.github/workflows/pipeline-segment-build-siso-windows.yml @@ -0,0 +1,104 @@ +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 + shopt -s nullglob + patches=("${GITHUB_WORKSPACE}/.github/siso-patches"/*.patch) + if [ ${#patches[@]} -eq 0 ]; then + echo "No siso patches to apply" + exit 0 + fi + cd chromium-build + git -c user.name=electron-ci -c user.email=ci@electronjs.org \ + am --3way "${patches[@]}" + - 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..5d0698ca75644 --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-build.yml @@ -0,0 +1,242 @@ +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: Install pinned Homebrew + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/install-homebrew + - 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: 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..ac6672a0e613d --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-clang-tidy.yml @@ -0,0 +1,179 @@ +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: 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 + env: + # macOS runners have fewer CPU cores, so use fewer jobs for better results + CLANG_TIDY_JOBS: ${{ case(inputs.target-platform == 'macos', 5, 8) }} + 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 --gen=only + + # Copy macOS framework headers so clang-tidy can find them via -F. + # This must happen after e build 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 ${CLANG_TIDY_JOBS} --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..7b5364008cdab --- /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: 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/electron + 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 --gen=only + + 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 script/gen-hunspell-filenames.js --check + + node script/gen-libc++-filenames.js --check + node script/yarn.js ts-node script/gen-filenames.ts -- --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..456ff38736493 --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-publish.yml @@ -0,0 +1,259 @@ +# 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: Install pinned Homebrew + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/install-homebrew + - 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: 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..84f801324d947 --- /dev/null +++ b/.github/workflows/pipeline-segment-electron-test.yml @@ -0,0 +1,342 @@ +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: Turn off the reopen windows prompt on macOS + if: ${{ inputs.target-platform == 'macos' }} + # Tests spawn Electron child apps and SIGINT them; after enough abnormal + # exits AppKit shows a modal "...unexpectedly quit while reopening + # windows. Do you want to try to reopen its windows again?" alert inside + # the open-application AppleEvent handler, which blocks before + # applicationDidFinishLaunching: and hangs app.whenReady() forever. + # See https://github.com/electron/electron/issues/51462. + run: defaults write com.github.Electron ApplePersistenceIgnoreState YES + - 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: Install pinned Homebrew + if: ${{ inputs.target-platform == 'macos' }} + uses: ./src/electron/.github/actions/install-homebrew + - 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..bc2d9b08944df --- /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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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..313462b65d0a1 --- /dev/null +++ b/.github/workflows/pull-request-labeled.yml @@ -0,0 +1,77 @@ +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@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3 + 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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.0 + id: generate-token + with: + creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }} + - name: Comment and 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 comment "$PR_NUMBER" --body-file - <<'EOF' + + + *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. + EOF + 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..01444e6101399 --- /dev/null +++ b/.github/workflows/rerun-apply-patches.yml @@ -0,0 +1,81 @@ +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 + + # Skip runs older than 25 days (GitHub does not allow rerunning after ~1 month) + RUN_CREATED=$(gh run view "$RUN_ID" --json createdAt --jq '.createdAt') + RUN_AGE_DAYS=$(( ($(date +%s) - $(date -d "$RUN_CREATED" +%s 2>/dev/null || date -jf "%Y-%m-%dT%H:%M:%SZ" "$RUN_CREATED" +%s)) / 86400 )) + + if [ "$RUN_AGE_DAYS" -gt 25 ]; then + echo " Skipping run ${RUN_ID} for PR #${PR_NUMBER}: run is ${RUN_AGE_DAYS} days old (max 25)" + 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..98b35b8a970e2 --- /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@e46ed2cbd01164d986452f91f178727624ae40d7 # 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..18f2b57ca6884 --- /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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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..1340a8177c629 --- /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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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@5f70a3726af01b612f29aac96d05aa524389c9e9 # v2.1.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..d156488ffa90a --- /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-16core + 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-16core + 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-16core + 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 a92239801a454..84644de3540ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,58 @@ .DS_Store +.env +.gclient_done +**/.npmrc .tags* +.vs/ +.vscode/ +*.log +*.pyc +*.sln +*.swp +*.VC.db +*.VC.VC.opendb +*.vcxproj +*.vcxproj.filters +*.vcxproj.user +*.xcodeproj /.idea/ -/build/ /dist/ -/external_binaries/ -/out/ -/vendor/brightray/vendor/download/ -/vendor/debian_wheezy_amd64-sysroot/ -/vendor/debian_wheezy_arm-sysroot/ -/vendor/debian_wheezy_i386-sysroot/ -/vendor/python_26/ -/vendor/npm/ -/vendor/llvm/ -/vendor/llvm-build/ -/vendor/.gclient node_modules/ -*.xcodeproj -*.swp -*.pyc -debug.log -npm-debug.log +SHASUMS256.txt +**/package-lock.json +compile_commands.json +.envrc + +# npm package +/npm/dist +/npm/path.txt +/npm/checksums.json + +.npmrc + +# Generated API definitions +electron-api.json +electron.d.ts + +# Spec hash calculation +spec/.hash + +# Eslint Cache +.eslintcache* + +# Generated native addon files +/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 + +# Used to accelerate builds after sync +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 6164ed8b97063..0000000000000 --- a/.gitmodules +++ /dev/null @@ -1,24 +0,0 @@ -[submodule "vendor/brightray"] - path = vendor/brightray - url = https://github.com/electron/brightray.git -[submodule "vendor/node"] - path = vendor/node - url = https://github.com/electron/node.git -[submodule "vendor/depot_tools"] - path = vendor/depot_tools - url = https://chromium.googlesource.com/chromium/tools/depot_tools.git -[submodule "vendor/breakpad"] - path = vendor/breakpad - url = https://github.com/electron/chromium-breakpad.git -[submodule "vendor/native_mate"] - path = vendor/native_mate - url = https://github.com/zcbenz/native-mate.git -[submodule "vendor/crashpad"] - path = vendor/crashpad - url = https://github.com/electron/crashpad.git -[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/.node-version b/.node-version deleted file mode 100644 index dffc266d6a8ba..0000000000000 --- a/.node-version +++ /dev/null @@ -1 +0,0 @@ -v6.3.0 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/.travis.yml b/.travis.yml deleted file mode 100644 index 75a5a26c6c714..0000000000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -git: - depth: 10 -notifications: - email: false - -language: cpp -compiler: clang -os: - - linux - - osx -env: - - TARGET_ARCH=x64 -osx_image: xcode7 - -matrix: - include: - - os: linux - env: TARGET_ARCH=arm - - os: linux - env: TARGET_ARCH=ia32 - allow_failures: - - os: osx - -script: './script/cibuild' - -branches: - only: - - master 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/patches/abstract-socket-npm-2.0.0-b025d8ca5a.patch b/.yarn/patches/abstract-socket-npm-2.0.0-b025d8ca5a.patch new file mode 100644 index 0000000000000..9e7e7e778c2ef --- /dev/null +++ b/.yarn/patches/abstract-socket-npm-2.0.0-b025d8ca5a.patch @@ -0,0 +1,351 @@ +diff --git a/binding.gyp b/binding.gyp +index 61f1d0bd5b2fe4f43874f1115cd2fa0dced03207..13e34fd6a17d698449063f22456f43e445246959 100644 +--- a/binding.gyp ++++ b/binding.gyp +@@ -1,10 +1,17 @@ + { + 'targets': [ + { +- 'target_name': 'abstract_socket', +- 'sources': [ 'src/abstract_socket.cc' ], ++ 'target_name': 'bindings', ++ 'conditions': [ ++ ['OS=="linux"', { ++ 'cflags!': [ '-fno-exceptions' ], ++ 'cflags_cc!': [ '-fno-exceptions' ], ++ 'defines': [ '_GNU_SOURCE=1' ], ++ 'sources': [ 'src/abstract_socket.cc' ], ++ }], ++ ], + 'include_dirs': [ +- ' ++#include + ++#include + #include + #include + #include +@@ -17,76 +14,33 @@ + + namespace { + +-using v8::FunctionTemplate; +-using v8::Local; +-using v8::Object; +-using v8::String; +-using v8::Value; +- +- +-#if !defined(SOCK_NONBLOCK) +-void SetNonBlock(int fd) { +- int flags; +- int r; +- +- flags = fcntl(fd, F_GETFL); +- assert(flags != -1); +- +- r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); +- assert(r != -1); +-} +-#endif +- +- +-#if !defined(SOCK_CLOEXEC) +-void SetCloExec(int fd) { +- int flags; +- int r; +- +- flags = fcntl(fd, F_GETFD); +- assert(flags != -1); +- +- r = fcntl(fd, F_SETFD, flags | FD_CLOEXEC); +- assert(r != -1); +-} +-#endif ++using Napi::FunctionReference; ++using Napi::Object; ++using Napi::String; ++using Napi::Value; + + +-NAN_METHOD(Socket) { +- Nan::HandleScope scope; ++Napi::Value Socket(const Napi::CallbackInfo& info) { ++ Napi::Env env(info.Env()); + int fd; + int type; + + assert(info.Length() == 0); + + type = SOCK_STREAM; +-#if defined(SOCK_NONBLOCK) +- type |= SOCK_NONBLOCK; +-#endif +-#if defined(SOCK_CLOEXEC) +- type |= SOCK_CLOEXEC; +-#endif ++ type |= SOCK_NONBLOCK | SOCK_CLOEXEC; + + fd = socket(AF_UNIX, type, 0); + if (fd == -1) { + fd = -errno; +- goto out; + } + +-#if !defined(SOCK_NONBLOCK) +- SetNonBlock(fd); +-#endif +-#if !defined(SOCK_CLOEXEC) +- SetCloExec(fd); +-#endif +- +-out: +- info.GetReturnValue().Set(fd); ++ return Napi::Number::New(env, fd); + } + + +-NAN_METHOD(Bind) { +- Nan::HandleScope scope; ++Napi::Value Bind(const Napi::CallbackInfo& info) { ++ Napi::Env env(info.Env()); + sockaddr_un s; + socklen_t namelen; + int err; +@@ -95,10 +49,10 @@ NAN_METHOD(Bind) { + + assert(info.Length() == 2); + +- fd = info[0]->Int32Value(); +- String::Utf8Value path(info[1]); ++ fd = info[0].As().Int32Value(); ++ std::string path = info[1].As(); + +- if ((*path)[0] != '\0') { ++ if ((path)[0] != '\0') { + err = -EINVAL; + goto out; + } +@@ -110,7 +64,7 @@ NAN_METHOD(Bind) { + } + + memset(&s, 0, sizeof s); +- memcpy(s.sun_path, *path, len); ++ memcpy(s.sun_path, path.c_str(), len); + s.sun_family = AF_UNIX; + namelen = offsetof(struct sockaddr_un, sun_path) + len; + +@@ -119,12 +73,12 @@ NAN_METHOD(Bind) { + err = -errno; + + out: +- info.GetReturnValue().Set(err); ++ return Napi::Number::New(env, err); + } + + +-NAN_METHOD(Connect) { +- Nan::HandleScope scope; ++Napi::Value Connect(const Napi::CallbackInfo& info) { ++ Napi::Env env(info.Env()); + sockaddr_un s; + socklen_t namelen; + int err; +@@ -133,10 +87,10 @@ NAN_METHOD(Connect) { + + assert(info.Length() == 2); + +- fd = info[0]->Int32Value(); +- String::Utf8Value path(info[1]); ++ fd = info[0].As().Int32Value(); ++ std::string path = info[1].As(); + +- if ((*path)[0] != '\0') { ++ if ((path)[0] != '\0') { + err = -EINVAL; + goto out; + } +@@ -148,7 +102,7 @@ NAN_METHOD(Connect) { + } + + memset(&s, 0, sizeof s); +- memcpy(s.sun_path, *path, len); ++ memcpy(s.sun_path, path.c_str(), len); + s.sun_family = AF_UNIX; + namelen = offsetof(struct sockaddr_un, sun_path) + len; + +@@ -157,59 +111,70 @@ NAN_METHOD(Connect) { + err = -errno; + + out: +- info.GetReturnValue().Set(err); ++ return Napi::Number::New(env, err); + } + + +-NAN_METHOD(Close) { +- Nan::HandleScope scope; ++Napi::Value Close(const Napi::CallbackInfo& info) { ++ Napi::Env env(info.Env()); + int err; + int fd; + + assert(info.Length() == 1); +- fd = info[0]->Int32Value(); +- +- // Suppress EINTR and EINPROGRESS. EINTR means that the close() system call +- // was interrupted by a signal. According to POSIX, the file descriptor is +- // in an undefined state afterwards. It's not safe to try closing it again +- // because it may have been closed, despite the signal. If we call close() +- // again, then it would either: ++ fd = info[0].As().Int32Value(); ++ ++ // POSIX 2008 states that it unspecified what the state of a file descriptor ++ // is if close() is interrupted by a signal and fails with EINTR. This is a ++ // problem for multi-threaded programs since if the fd was actually closed ++ // it may already be reused by another thread hence it is unsafe to attempt ++ // to close it again. In 2012, POSIX approved a clarification that aimed ++ // to deal with this mess: http://austingroupbugs.net/view.php?id=529#c1200 ++ // ++ // The short summary is that if the fd is never valid after close(), as is ++ // the case in Linux, then should add: + // +- // a) fail with EBADF, or ++ // #define POSIX_CLOSE_RESTART 0 + // +- // b) close the wrong file descriptor if another thread or a signal handler +- // has reused it in the mean time. ++ // and the new posix_close() should be implemented as something like: + // +- // Neither is what we want but scenario B is particularly bad. Not retrying +- // the close() could, in theory, lead to file descriptor leaks but, in +- // practice, operating systems do the right thing and close the file +- // descriptor, regardless of whether the operation was interrupted by +- // a signal. ++ // int posix_close(int fd, int flags) { ++ // int r = close(fd); ++ // if (r < 0 && errno == EINTR) ++ // return 0 or set errno to EINPROGRESS; ++ // return r; ++ // } + // +- // EINPROGRESS is benign. It means the close operation was interrupted but +- // that the file descriptor has been closed or is being closed in the +- // background. It's informative, not an error. ++ // In contrast, on systems where EINTR means the close() didn't happen (like ++ // HP-UX), POSIX_CLOSE_RESTART should be non-zero and if passed as flag to ++ // posix_close() it should automatically retry close() on EINTR. ++ // ++ // Of course this is nice and all, but apparently adding one constant and ++ // a trivial wrapper was way too much effort for the glibc project: ++ // https://sourceware.org/bugzilla/show_bug.cgi?id=16302 ++ // ++ // But since we actually only care about Linux, we don't have to worry about ++ // all this anyway. close() always means the fd is gone, even if an error ++ // occurred. This elevates EINTR to the status of real error, since it ++ // implies behaviour associated with close (e.g. flush) was aborted and can ++ // not be retried since the fd is gone. ++ + err = 0; + if (close(fd)) +- if (errno != EINTR && errno != EINPROGRESS) + err = -errno; + +- info.GetReturnValue().Set(err); ++ return Napi::Number::New(env, err); + } + + +-void Initialize(Local target) { +- target->Set(Nan::New("socket").ToLocalChecked(), +- Nan::New(Socket)->GetFunction()); +- target->Set(Nan::New("bind").ToLocalChecked(), +- Nan::New(Bind)->GetFunction()); +- target->Set(Nan::New("connect").ToLocalChecked(), +- Nan::New(Connect)->GetFunction()); +- target->Set(Nan::New("close").ToLocalChecked(), +- Nan::New(Close)->GetFunction()); ++Napi::Object Initialize(Napi::Env env, Napi::Object exports) { ++ exports.Set("socket", Napi::Function::New(env, Socket)); ++ exports.Set("bind", Napi::Function::New(env, Bind)); ++ exports.Set("connect", Napi::Function::New(env, Connect)); ++ exports.Set("close", Napi::Function::New(env, Close)); ++ return exports; + } + + + } // anonymous namespace + +-NODE_MODULE(abstract_socket, Initialize) ++NODE_API_MODULE(abstract_socket, Initialize) 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/IAMoAkggAWoFQQALIAMoAmggAWtBARAPIAMgAygCaDYCWCADKAIAEApBA0ECIAMoAgAoAhAbDAILIAMoAvAtBEBBACEEIAMgAygCWCIBQQBOBH8gAygCSCABagVBAAsgAygCaCABa0EAEA8gAyADKAJoNgJYIAMoAgAQCiADKAIAKAIQRQ0BC0EBIQQLIAQLDAILAn8CQANAAkACQAJAAkACQCADKAI8Ig1BggJLDQAgAxAvAkAgAygCPCINQYICSw0AIAoNAEEADAgLIA1FDQQgDUECSw0AIAMoAmghCAwBCyADKAJoIghFBEBBACEIDAELIAMoAkggCGoiAUEBayIELQAAIgYgAS0AAEcNACAGIAQtAAJHDQAgBEEDaiEEQQAhCQJAA0AgBiAELQAARw0BIAQtAAEgBkcEQCAJQQFyIQkMAgsgBC0AAiAGRwRAIAlBAnIhCQwCCyAELQADIAZHBEAgCUEDciEJDAILIAQtAAQgBkcEQCAJQQRyIQkMAgsgBC0ABSAGRwRAIAlBBXIhCQwCCyAELQAGIAZHBEAgCUEGciEJDAILIAQtAAcgBkcEQCAJQQdyIQkMAgsgBEEIaiEEIAlB+AFJIQEgCUEIaiEJIAENAAtBgAIhCQtBggIhBCANIAlBAmoiASABIA1LGyIBQYECSw0BIAEiBEECSw0BCyADKAJIIAhqLQAAIQQgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtakEAOgAAIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qIAQ6AAAgAyAEQQJ0aiIBIAEvAeQBQQFqOwHkASADIAMoAjxBAWs2AjwgAyADKAJoQQFqIgQ2AmgMAQsgAyADKALwLSIBQQFqNgLwLSABIAMoAuwtakEBOgAAIAMgAygC8C0iAUEBajYC8C0gASADKALsLWpBADoAACADIAMoAvAtIgFBAWo2AvAtIAEgAygC7C1qIARBA2s6AAAgAyADKAKALkEBajYCgC4gBEH9zgBqLQAAQQJ0IANqQegJaiIBIAEvAQBBAWo7AQAgA0GAywAtAABBAnRqQdgTaiIBIAEvAQBBAWo7AQAgAyADKAI8IARrNgI8IAMgAygCaCAEaiIENgJoCyADKALwLSADKAL0LUcNAUEAIQggAyADKAJYIgFBAE4EfyADKAJIIAFqBUEACyAEIAFrQQAQDyADIAMoAmg2AlggAygCABAKIAMoAgAoAhANAQwCCwsgA0EANgKELiAKQQRGBEAgAyADKAJYIgFBAE4EfyADKAJIIAFqBUEACyADKAJoIAFrQQEQDyADIAMoAmg2AlggAygCABAKQQNBAiADKAIAKAIQGwwCCyADKALwLQRAQQAhCCADIAMoAlgiAUEATgR/IAMoAkggAWoFQQALIAMoAmggAWtBABAPIAMgAygCaDYCWCADKAIAEAogAygCACgCEEUNAQtBASEICyAICwwBCyADIAogAUEMbEG42ABqKAIAEQIACyIBQX5xQQJGBEAgA0GaBTYCIAsgAUF9cUUEQEEAIQQgBSgCEA0CDAQLIAFBAUcNAAJAAkACQCAKQQFrDgUAAQEBAgELIAMpA5guISICfwJ+IAMoAqAuIgFBA2oiCUE/TQRAQgIgAa2GICKEDAELIAFBwABGBEAgAygCBCADKAIQaiAiNwAAIAMgAygCEEEIajYCEEICISJBCgwCCyADKAIEIAMoAhBqQgIgAa2GICKENwAAIAMgAygCEEEIajYCECABQT1rIQlCAkHAACABa62ICyEiIAlBB2ogCUE5SQ0AGiADKAIEIAMoAhBqICI3AAAgAyADKAIQQQhqNgIQQgAhIiAJQTlrCyEBIAMgIjcDmC4gAyABNgKgLiADEDAMAQsgA0EAQQBBABA5IApBA0cNACADKAJQQQBBgIAIEBkgAygCPA0AIANBADYChC4gA0EANgJYIANBADYCaAsgBRAKIAUoAhANAAwDC0EAIQQgCkEERw0AAkACfwJAAkAgAygCFEEBaw4CAQADCyAFIANBoAFqQeCAASgCABEBACIBNgIwIAMoAgQgAygCEGogATYAACADIAMoAhBBBGoiATYCECADKAIEIAFqIQQgBSgCCAwBCyADKAIEIAMoAhBqIQQgBSgCMCIBQRh0IAFBCHRBgID8B3FyIAFBCHZBgP4DcSABQRh2cnILIQEgBCABNgAAIAMgAygCEEEEajYCEAsgBRAKIAMoAhQiAUEBTgRAIANBACABazYCFAsgAygCEEUhBAsgBAwCCyAFQezAACgCADYCGEF7DAELIANBfzYCJEEACwwBCyMAQRBrIhQkAEF+IRcCQCABIgxFDQAgDCgCIEUNACAMKAIkRQ0AIAwoAhwiB0UNACAHKAIAIAxHDQAgBygCBCIIQbT+AGtBH0sNACAMKAIMIhBFDQAgDCgCACIBRQRAIAwoAgQNAQsgCEG//gBGBEAgB0HA/gA2AgRBwP4AIQgLIAdBpAFqIR8gB0G8BmohGSAHQbwBaiEcIAdBoAFqIR0gB0G4AWohGiAHQfwKaiEYIAdBQGshHiAHKAKIASEFIAwoAgQiICEGIAcoAoQBIQogDCgCECIPIRYCfwJAAkACQANAAkBBfSEEQQEhCQJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAhBtP4Aaw4fBwYICQolJicoBSwtLQsZGgQMAjIzATUANw0OAzlISUwLIAcoApQBIQMgASEEIAYhCAw1CyAHKAKUASEDIAEhBCAGIQgMMgsgBygCtAEhCAwuCyAHKAIMIQgMQQsgBUEOTw0pIAZFDUEgBUEIaiEIIAFBAWohBCAGQQFrIQkgAS0AACAFdCAKaiEKIAVBBkkNDCAEIQEgCSEGIAghBQwpCyAFQSBPDSUgBkUNQCABQQFqIQQgBkEBayEIIAEtAAAgBXQgCmohCiAFQRhJDQ0gBCEBIAghBgwlCyAFQRBPDRUgBkUNPyAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEISQ0NIAQhASAJIQYgCCEFDBULIAcoAgwiC0UNByAFQRBPDSIgBkUNPiAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEISQ0NIAQhASAJIQYgCCEFDCILIAVBH0sNFQwUCyAFQQ9LDRYMFQsgBygCFCIEQYAIcUUEQCAFIQgMFwsgCiEIIAVBD0sNGAwXCyAKIAVBB3F2IQogBUF4cSIFQR9LDQwgBkUNOiAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEYSQ0GIAQhASAJIQYgCCEFDAwLIAcoArQBIgggBygCqAEiC08NIwwiCyAPRQ0qIBAgBygCjAE6AAAgB0HI/gA2AgQgD0EBayEPIBBBAWohECAHKAIEIQgMOQsgBygCDCIDRQRAQQAhCAwJCyAFQR9LDQcgBkUNNyAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEYSQ0BIAQhASAJIQYgCCEFDAcLIAdBwP4ANgIEDCoLIAlFBEAgBCEBQQAhBiAIIQUgDSEEDDgLIAVBEGohCSABQQJqIQQgBkECayELIAEtAAEgCHQgCmohCiAFQQ9LBEAgBCEBIAshBiAJIQUMBgsgC0UEQCAEIQFBACEGIAkhBSANIQQMOAsgBUEYaiEIIAFBA2ohBCAGQQNrIQsgAS0AAiAJdCAKaiEKIAVBB0sEQCAEIQEgCyEGIAghBQwGCyALRQRAIAQhAUEAIQYgCCEFIA0hBAw4CyAFQSBqIQUgBkEEayEGIAEtAAMgCHQgCmohCiABQQRqIQEMBQsgCUUEQCAEIQFBACEGIAghBSANIQQMNwsgBUEQaiEFIAZBAmshBiABLQABIAh0IApqIQogAUECaiEBDBwLIAlFBEAgBCEBQQAhBiAIIQUgDSEEDDYLIAVBEGohCSABQQJqIQQgBkECayELIAEtAAEgCHQgCmohCiAFQQ9LBEAgBCEBIAshBiAJIQUMBgsgC0UEQCAEIQFBACEGIAkhBSANIQQMNgsgBUEYaiEIIAFBA2ohBCAGQQNrIQsgAS0AAiAJdCAKaiEKIAUEQCAEIQEgCyEGIAghBQwGCyALRQRAIAQhAUEAIQYgCCEFIA0hBAw2CyAFQSBqIQUgBkEEayEGIAEtAAMgCHQgCmohCiABQQRqIQEMBQsgBUEIaiEJIAhFBEAgBCEBQQAhBiAJIQUgDSEEDDULIAFBAmohBCAGQQJrIQggAS0AASAJdCAKaiEKIAVBD0sEQCAEIQEgCCEGDBgLIAVBEGohCSAIRQRAIAQhAUEAIQYgCSEFIA0hBAw1CyABQQNqIQQgBkEDayEIIAEtAAIgCXQgCmohCiAFQQdLBEAgBCEBIAghBgwYCyAFQRhqIQUgCEUEQCAEIQFBACEGIA0hBAw1CyAGQQRrIQYgAS0AAyAFdCAKaiEKIAFBBGohAQwXCyAJDQYgBCEBQQAhBiAIIQUgDSEEDDMLIAlFBEAgBCEBQQAhBiAIIQUgDSEEDDMLIAVBEGohBSAGQQJrIQYgAS0AASAIdCAKaiEKIAFBAmohAQwUCyAMIBYgD2siCSAMKAIUajYCFCAHIAcoAiAgCWo2AiACQCADQQRxRQ0AIAkEQAJAIBAgCWshBCAMKAIcIggoAhQEQCAIQUBrIAQgCUEAQdiAASgCABEIAAwBCyAIIAgoAhwgBCAJQcCAASgCABEAACIENgIcIAwgBDYCMAsLIAcoAhRFDQAgByAeQeCAASgCABEBACIENgIcIAwgBDYCMAsCQCAHKAIMIghBBHFFDQAgBygCHCAKIApBCHRBgID8B3EgCkEYdHIgCkEIdkGA/gNxIApBGHZyciAHKAIUG0YNACAHQdH+ADYCBCAMQaQMNgIYIA8hFiAHKAIEIQgMMQtBACEKQQAhBSAPIRYLIAdBz/4ANgIEDC0LIApB//8DcSIEIApBf3NBEHZHBEAgB0HR/gA2AgQgDEGOCjYCGCAHKAIEIQgMLwsgB0HC/gA2AgQgByAENgKMAUEAIQpBACEFCyAHQcP+ADYCBAsgBygCjAEiBARAIA8gBiAEIAQgBksbIgQgBCAPSxsiCEUNHiAQIAEgCBAHIQQgByAHKAKMASAIazYCjAEgBCAIaiEQIA8gCGshDyABIAhqIQEgBiAIayEGIAcoAgQhCAwtCyAHQb/+ADYCBCAHKAIEIQgMLAsgBUEQaiEFIAZBAmshBiABLQABIAh0IApqIQogAUECaiEBCyAHIAo2AhQgCkH/AXFBCEcEQCAHQdH+ADYCBCAMQYIPNgIYIAcoAgQhCAwrCyAKQYDAA3EEQCAHQdH+ADYCBCAMQY0JNgIYIAcoAgQhCAwrCyAHKAIkIgQEQCAEIApBCHZBAXE2AgALAkAgCkGABHFFDQAgBy0ADEEEcUUNACAUIAo7AAwgBwJ/IAcoAhwhBUEAIBRBDGoiBEUNABogBSAEQQJB1IABKAIAEQAACzYCHAsgB0G2/gA2AgRBACEFQQAhCgsgBkUNKCABQQFqIQQgBkEBayEIIAEtAAAgBXQgCmohCiAFQRhPBEAgBCEBIAghBgwBCyAFQQhqIQkgCEUEQCAEIQFBACEGIAkhBSANIQQMKwsgAUECaiEEIAZBAmshCCABLQABIAl0IApqIQogBUEPSwRAIAQhASAIIQYMAQsgBUEQaiEJIAhFBEAgBCEBQQAhBiAJIQUgDSEEDCsLIAFBA2ohBCAGQQNrIQggAS0AAiAJdCAKaiEKIAVBB0sEQCAEIQEgCCEGDAELIAVBGGohBSAIRQRAIAQhAUEAIQYgDSEEDCsLIAZBBGshBiABLQADIAV0IApqIQogAUEEaiEBCyAHKAIkIgQEQCAEIAo2AgQLAkAgBy0AFUECcUUNACAHLQAMQQRxRQ0AIBQgCjYADCAHAn8gBygCHCEFQQAgFEEMaiIERQ0AGiAFIARBBEHUgAEoAgARAAALNgIcCyAHQbf+ADYCBEEAIQVBACEKCyAGRQ0mIAFBAWohBCAGQQFrIQggAS0AACAFdCAKaiEKIAVBCE8EQCAEIQEgCCEGDAELIAVBCGohBSAIRQRAIAQhAUEAIQYgDSEEDCkLIAZBAmshBiABLQABIAV0IApqIQogAUECaiEBCyAHKAIkIgQEQCAEIApBCHY2AgwgBCAKQf8BcTYCCAsCQCAHLQAVQQJxRQ0AIActAAxBBHFFDQAgFCAKOwAMIAcCfyAHKAIcIQVBACAUQQxqIgRFDQAaIAUgBEECQdSAASgCABEAAAs2AhwLIAdBuP4ANgIEQQAhCEEAIQVBACEKIAcoAhQiBEGACHENAQsgBygCJCIEBEAgBEEANgIQCyAIIQUMAgsgBkUEQEEAIQYgCCEKIA0hBAwmCyABQQFqIQkgBkEBayELIAEtAAAgBXQgCGohCiAFQQhPBEAgCSEBIAshBgwBCyAFQQhqIQUgC0UEQCAJIQFBACEGIA0hBAwmCyAGQQJrIQYgAS0AASAFdCAKaiEKIAFBAmohAQsgByAKQf//A3EiCDYCjAEgBygCJCIFBEAgBSAINgIUC0EAIQUCQCAEQYAEcUUNACAHLQAMQQRxRQ0AIBQgCjsADCAHAn8gBygCHCEIQQAgFEEMaiIERQ0AGiAIIARBAkHUgAEoAgARAAALNgIcC0EAIQoLIAdBuf4ANgIECyAHKAIUIglBgAhxBEAgBiAHKAKMASIIIAYgCEkbIg4EQAJAIAcoAiQiA0UNACADKAIQIgRFDQAgAygCGCILIAMoAhQgCGsiCE0NACAEIAhqIAEgCyAIayAOIAggDmogC0sbEAcaIAcoAhQhCQsCQCAJQYAEcUUNACAHLQAMQQRxRQ0AIAcCfyAHKAIcIQRBACABRQ0AGiAEIAEgDkHUgAEoAgARAAALNgIcCyAHIAcoAowBIA5rIgg2AowBIAYgDmshBiABIA5qIQELIAgNEwsgB0G6/gA2AgQgB0EANgKMAQsCQCAHLQAVQQhxBEBBACEIIAZFDQQDQCABIAhqLQAAIQMCQCAHKAIkIgtFDQAgCygCHCIERQ0AIAcoAowBIgkgCygCIE8NACAHIAlBAWo2AowBIAQgCWogAzoAAAsgA0EAIAYgCEEBaiIISxsNAAsCQCAHLQAVQQJxRQ0AIActAAxBBHFFDQAgBwJ/IAcoAhwhBEEAIAFFDQAaIAQgASAIQdSAASgCABEAAAs2AhwLIAEgCGohASAGIAhrIQYgA0UNAQwTCyAHKAIkIgRFDQAgBEEANgIcCyAHQbv+ADYCBCAHQQA2AowBCwJAIActABVBEHEEQEEAIQggBkUNAwNAIAEgCGotAAAhAwJAIAcoAiQiC0UNACALKAIkIgRFDQAgBygCjAEiCSALKAIoTw0AIAcgCUEBajYCjAEgBCAJaiADOgAACyADQQAgBiAIQQFqIghLGw0ACwJAIActABVBAnFFDQAgBy0ADEEEcUUNACAHAn8gBygCHCEEQQAgAUUNABogBCABIAhB1IABKAIAEQAACzYCHAsgASAIaiEBIAYgCGshBiADRQ0BDBILIAcoAiQiBEUNACAEQQA2AiQLIAdBvP4ANgIECyAHKAIUIgtBgARxBEACQCAFQQ9LDQAgBkUNHyAFQQhqIQggAUEBaiEEIAZBAWshCSABLQAAIAV0IApqIQogBUEITwRAIAQhASAJIQYgCCEFDAELIAlFBEAgBCEBQQAhBiAIIQUgDSEEDCILIAVBEGohBSAGQQJrIQYgAS0AASAIdCAKaiEKIAFBAmohAQsCQCAHLQAMQQRxRQ0AIAogBy8BHEYNACAHQdH+ADYCBCAMQdcMNgIYIAcoAgQhCAwgC0EAIQpBACEFCyAHKAIkIgQEQCAEQQE2AjAgBCALQQl2QQFxNgIsCwJAIActAAxBBHFFDQAgC0UNACAHIB5B5IABKAIAEQEAIgQ2AhwgDCAENgIwCyAHQb/+ADYCBCAHKAIEIQgMHgtBACEGDA4LAkAgC0ECcUUNACAKQZ+WAkcNACAHKAIoRQRAIAdBDzYCKAtBACEKIAdBADYCHCAUQZ+WAjsADCAHIBRBDGoiBAR/QQAgBEECQdSAASgCABEAAAVBAAs2AhwgB0G1/gA2AgRBACEFIAcoAgQhCAwdCyAHKAIkIgQEQCAEQX82AjALAkAgC0EBcQRAIApBCHRBgP4DcSAKQQh2akEfcEUNAQsgB0HR/gA2AgQgDEH2CzYCGCAHKAIEIQgMHQsgCkEPcUEIRwRAIAdB0f4ANgIEIAxBgg82AhggBygCBCEIDB0LIApBBHYiBEEPcSIJQQhqIQsgCUEHTUEAIAcoAigiCAR/IAgFIAcgCzYCKCALCyALTxtFBEAgBUEEayEFIAdB0f4ANgIEIAxB+gw2AhggBCEKIAcoAgQhCAwdCyAHQQE2AhxBACEFIAdBADYCFCAHQYACIAl0NgIYIAxBATYCMCAHQb3+AEG//gAgCkGAwABxGzYCBEEAIQogBygCBCEIDBwLIAcgCkEIdEGAgPwHcSAKQRh0ciAKQQh2QYD+A3EgCkEYdnJyIgQ2AhwgDCAENgIwIAdBvv4ANgIEQQAhCkEAIQULIAcoAhBFBEAgDCAPNgIQIAwgEDYCDCAMIAY2AgQgDCABNgIAIAcgBTYCiAEgByAKNgKEAUECIRcMIAsgB0EBNgIcIAxBATYCMCAHQb/+ADYCBAsCfwJAIAcoAghFBEAgBUEDSQ0BIAUMAgsgB0HO/gA2AgQgCiAFQQdxdiEKIAVBeHEhBSAHKAIEIQgMGwsgBkUNGSAGQQFrIQYgAS0AACAFdCAKaiEKIAFBAWohASAFQQhqCyEEIAcgCkEBcTYCCAJAAkACQAJAAkAgCkEBdkEDcUEBaw4DAQIDAAsgB0HB/gA2AgQMAwsgB0Gw2wA2ApgBIAdCiYCAgNAANwOgASAHQbDrADYCnAEgB0HH/gA2AgQMAgsgB0HE/gA2AgQMAQsgB0HR/gA2AgQgDEHXDTYCGAsgBEEDayEFIApBA3YhCiAHKAIEIQgMGQsgByAKQR9xIghBgQJqNgKsASAHIApBBXZBH3EiBEEBajYCsAEgByAKQQp2QQ9xQQRqIgs2AqgBIAVBDmshBSAKQQ52IQogCEEdTUEAIARBHkkbRQRAIAdB0f4ANgIEIAxB6gk2AhggBygCBCEIDBkLIAdBxf4ANgIEQQAhCCAHQQA2ArQBCyAIIQQDQCAFQQJNBEAgBkUNGCAGQQFrIQYgAS0AACAFdCAKaiEKIAVBCGohBSABQQFqIQELIAcgBEEBaiIINgK0ASAHIARBAXRBsOwAai8BAEEBdGogCkEHcTsBvAEgBUEDayEFIApBA3YhCiALIAgiBEsNAAsLIAhBEk0EQEESIAhrIQ1BAyAIa0EDcSIEBEADQCAHIAhBAXRBsOwAai8BAEEBdGpBADsBvAEgCEEBaiEIIARBAWsiBA0ACwsgDUEDTwRAA0AgB0G8AWoiDSAIQQF0IgRBsOwAai8BAEEBdGpBADsBACANIARBsuwAai8BAEEBdGpBADsBACANIARBtOwAai8BAEEBdGpBADsBACANIARBtuwAai8BAEEBdGpBADsBACAIQQRqIghBE0cNAAsLIAdBEzYCtAELIAdBBzYCoAEgByAYNgKYASAHIBg2ArgBQQAhCEEAIBxBEyAaIB0gGRBOIg0EQCAHQdH+ADYCBCAMQfQINgIYIAcoAgQhCAwXCyAHQcb+ADYCBCAHQQA2ArQBQQAhDQsgBygCrAEiFSAHKAKwAWoiESAISwRAQX8gBygCoAF0QX9zIRIgBygCmAEhGwNAIAYhCSABIQsCQCAFIgMgGyAKIBJxIhNBAnRqLQABIg5PBEAgBSEEDAELA0AgCUUNDSALLQAAIAN0IQ4gC0EBaiELIAlBAWshCSADQQhqIgQhAyAEIBsgCiAOaiIKIBJxIhNBAnRqLQABIg5JDQALIAshASAJIQYLAkAgGyATQQJ0ai8BAiIFQQ9NBEAgByAIQQFqIgk2ArQBIAcgCEEBdGogBTsBvAEgBCAOayEFIAogDnYhCiAJIQgMAQsCfwJ/AkACQAJAIAVBEGsOAgABAgsgDkECaiIFIARLBEADQCAGRQ0bIAZBAWshBiABLQAAIAR0IApqIQogAUEBaiEBIARBCGoiBCAFSQ0ACwsgBCAOayEFIAogDnYhBCAIRQRAIAdB0f4ANgIEIAxBvAk2AhggBCEKIAcoAgQhCAwdCyAFQQJrIQUgBEECdiEKIARBA3FBA2ohCSAIQQF0IAdqLwG6AQwDCyAOQQNqIgUgBEsEQANAIAZFDRogBkEBayEGIAEtAAAgBHQgCmohCiABQQFqIQEgBEEIaiIEIAVJDQALCyAEIA5rQQNrIQUgCiAOdiIEQQN2IQogBEEHcUEDagwBCyAOQQdqIgUgBEsEQANAIAZFDRkgBkEBayEGIAEtAAAgBHQgCmohCiABQQFqIQEgBEEIaiIEIAVJDQALCyAEIA5rQQdrIQUgCiAOdiIEQQd2IQogBEH/AHFBC2oLIQlBAAshAyAIIAlqIBFLDRMgCUEBayEEIAlBA3EiCwRAA0AgByAIQQF0aiADOwG8ASAIQQFqIQggCUEBayEJIAtBAWsiCw0ACwsgBEEDTwRAA0AgByAIQQF0aiIEIAM7Ab4BIAQgAzsBvAEgBCADOwHAASAEIAM7AcIBIAhBBGohCCAJQQRrIgkNAAsLIAcgCDYCtAELIAggEUkNAAsLIAcvAbwFRQRAIAdB0f4ANgIEIAxB0Qs2AhggBygCBCEIDBYLIAdBCjYCoAEgByAYNgKYASAHIBg2ArgBQQEgHCAVIBogHSAZEE4iDQRAIAdB0f4ANgIEIAxB2Ag2AhggBygCBCEIDBYLIAdBCTYCpAEgByAHKAK4ATYCnAFBAiAHIAcoAqwBQQF0akG8AWogBygCsAEgGiAfIBkQTiINBEAgB0HR/gA2AgQgDEGmCTYCGCAHKAIEIQgMFgsgB0HH/gA2AgRBACENCyAHQcj+ADYCBAsCQCAGQQ9JDQAgD0GEAkkNACAMIA82AhAgDCAQNgIMIAwgBjYCBCAMIAE2AgAgByAFNgKIASAHIAo2AoQBIAwgFkHogAEoAgARBwAgBygCiAEhBSAHKAKEASEKIAwoAgQhBiAMKAIAIQEgDCgCECEPIAwoAgwhECAHKAIEQb/+AEcNByAHQX82ApBHIAcoAgQhCAwUCyAHQQA2ApBHIAUhCSAGIQggASEEAkAgBygCmAEiEiAKQX8gBygCoAF0QX9zIhVxIg5BAnRqLQABIgsgBU0EQCAFIQMMAQsDQCAIRQ0PIAQtAAAgCXQhCyAEQQFqIQQgCEEBayEIIAlBCGoiAyEJIAMgEiAKIAtqIgogFXEiDkECdGotAAEiC0kNAAsLIBIgDkECdGoiAS8BAiETAkBBACABLQAAIhEgEUHwAXEbRQRAIAshBgwBCyAIIQYgBCEBAkAgAyIFIAsgEiAKQX8gCyARanRBf3MiFXEgC3YgE2oiEUECdGotAAEiDmpPBEAgAyEJDAELA0AgBkUNDyABLQAAIAV0IQ4gAUEBaiEBIAZBAWshBiAFQQhqIgkhBSALIBIgCiAOaiIKIBVxIAt2IBNqIhFBAnRqLQABIg5qIAlLDQALIAEhBCAGIQgLIBIgEUECdGoiAS0AACERIAEvAQIhEyAHIAs2ApBHIAsgDmohBiAJIAtrIQMgCiALdiEKIA4hCwsgByAGNgKQRyAHIBNB//8DcTYCjAEgAyALayEFIAogC3YhCiARRQRAIAdBzf4ANgIEDBALIBFBIHEEQCAHQb/+ADYCBCAHQX82ApBHDBALIBFBwABxBEAgB0HR/gA2AgQgDEHQDjYCGAwQCyAHQcn+ADYCBCAHIBFBD3EiAzYClAELAkAgA0UEQCAHKAKMASELIAQhASAIIQYMAQsgBSEJIAghBiAEIQsCQCADIAVNBEAgBCEBDAELA0AgBkUNDSAGQQFrIQYgCy0AACAJdCAKaiEKIAtBAWoiASELIAlBCGoiCSADSQ0ACwsgByAHKAKQRyADajYCkEcgByAHKAKMASAKQX8gA3RBf3NxaiILNgKMASAJIANrIQUgCiADdiEKCyAHQcr+ADYCBCAHIAs2ApRHCyAFIQkgBiEIIAEhBAJAIAcoApwBIhIgCkF/IAcoAqQBdEF/cyIVcSIOQQJ0ai0AASIDIAVNBEAgBSELDAELA0AgCEUNCiAELQAAIAl0IQMgBEEBaiEEIAhBAWshCCAJQQhqIgshCSALIBIgAyAKaiIKIBVxIg5BAnRqLQABIgNJDQALCyASIA5BAnRqIgEvAQIhEwJAIAEtAAAiEUHwAXEEQCAHKAKQRyEGIAMhCQwBCyAIIQYgBCEBAkAgCyIFIAMgEiAKQX8gAyARanRBf3MiFXEgA3YgE2oiEUECdGotAAEiCWpPBEAgCyEODAELA0AgBkUNCiABLQAAIAV0IQkgAUEBaiEBIAZBAWshBiAFQQhqIg4hBSADIBIgCSAKaiIKIBVxIAN2IBNqIhFBAnRqLQABIglqIA5LDQALIAEhBCAGIQgLIBIgEUECdGoiAS0AACERIAEvAQIhEyAHIAcoApBHIANqIgY2ApBHIA4gA2shCyAKIAN2IQoLIAcgBiAJajYCkEcgCyAJayEFIAogCXYhCiARQcAAcQRAIAdB0f4ANgIEIAxB7A42AhggBCEBIAghBiAHKAIEIQgMEgsgB0HL/gA2AgQgByARQQ9xIgM2ApQBIAcgE0H//wNxNgKQAQsCQCADRQRAIAQhASAIIQYMAQsgBSEJIAghBiAEIQsCQCADIAVNBEAgBCEBDAELA0AgBkUNCCAGQQFrIQYgCy0AACAJdCAKaiEKIAtBAWoiASELIAlBCGoiCSADSQ0ACwsgByAHKAKQRyADajYCkEcgByAHKAKQASAKQX8gA3RBf3NxajYCkAEgCSADayEFIAogA3YhCgsgB0HM/gA2AgQLIA9FDQACfyAHKAKQASIIIBYgD2siBEsEQAJAIAggBGsiCCAHKAIwTQ0AIAcoAoxHRQ0AIAdB0f4ANgIEIAxBuQw2AhggBygCBCEIDBILAn8CQAJ/IAcoAjQiBCAISQRAIAcoAjggBygCLCAIIARrIghragwBCyAHKAI4IAQgCGtqCyILIBAgDyAQaiAQa0EBaqwiISAPIAcoAowBIgQgCCAEIAhJGyIEIAQgD0sbIgitIiIgISAiVBsiIqciCWoiBEkgCyAQT3ENACALIBBNIAkgC2ogEEtxDQAgECALIAkQBxogBAwBCyAQIAsgCyAQayIEIARBH3UiBGogBHMiCRAHIAlqIQQgIiAJrSIkfSIjUEUEQCAJIAtqIQkDQAJAICMgJCAjICRUGyIiQiBUBEAgIiEhDAELICIiIUIgfSImQgWIQgF8QgODIiVQRQRAA0AgBCAJKQAANwAAIAQgCSkAGDcAGCAEIAkpABA3ABAgBCAJKQAINwAIICFCIH0hISAJQSBqIQkgBEEgaiEEICVCAX0iJUIAUg0ACwsgJkLgAFQNAANAIAQgCSkAADcAACAEIAkpABg3ABggBCAJKQAQNwAQIAQgCSkACDcACCAEIAkpADg3ADggBCAJKQAwNwAwIAQgCSkAKDcAKCAEIAkpACA3ACAgBCAJKQBYNwBYIAQgCSkAUDcAUCAEIAkpAEg3AEggBCAJKQBANwBAIAQgCSkAYDcAYCAEIAkpAGg3AGggBCAJKQBwNwBwIAQgCSkAeDcAeCAJQYABaiEJIARBgAFqIQQgIUKAAX0iIUIfVg0ACwsgIUIQWgRAIAQgCSkAADcAACAEIAkpAAg3AAggIUIQfSEhIAlBEGohCSAEQRBqIQQLICFCCFoEQCAEIAkpAAA3AAAgIUIIfSEhIAlBCGohCSAEQQhqIQQLICFCBFoEQCAEIAkoAAA2AAAgIUIEfSEhIAlBBGohCSAEQQRqIQQLICFCAloEQCAEIAkvAAA7AAAgIUICfSEhIAlBAmohCSAEQQJqIQQLICMgIn0hIyAhUEUEQCAEIAktAAA6AAAgCUEBaiEJIARBAWohBAsgI0IAUg0ACwsgBAsMAQsgECAIIA8gBygCjAEiBCAEIA9LGyIIIA9ByIABKAIAEQQACyEQIAcgBygCjAEgCGsiBDYCjAEgDyAIayEPIAQNAiAHQcj+ADYCBCAHKAIEIQgMDwsgDSEJCyAJIQQMDgsgBygCBCEIDAwLIAEgBmohASAFIAZBA3RqIQUMCgsgBCAIaiEBIAUgCEEDdGohBQwJCyAEIAhqIQEgCyAIQQN0aiEFDAgLIAEgBmohASAFIAZBA3RqIQUMBwsgBCAIaiEBIAUgCEEDdGohBQwGCyAEIAhqIQEgAyAIQQN0aiEFDAULIAEgBmohASAFIAZBA3RqIQUMBAsgB0HR/gA2AgQgDEG8CTYCGCAHKAIEIQgMBAsgBCEBIAghBiAHKAIEIQgMAwtBACEGIAQhBSANIQQMAwsCQAJAIAhFBEAgCiEJDAELIAcoAhRFBEAgCiEJDAELAkAgBUEfSw0AIAZFDQMgBUEIaiEJIAFBAWohBCAGQQFrIQsgAS0AACAFdCAKaiEKIAVBGE8EQCAEIQEgCyEGIAkhBQwBCyALRQRAIAQhAUEAIQYgCSEFIA0hBAwGCyAFQRBqIQsgAUECaiEEIAZBAmshAyABLQABIAl0IApqIQogBUEPSwRAIAQhASADIQYgCyEFDAELIANFBEAgBCEBQQAhBiALIQUgDSEEDAYLIAVBGGohCSABQQNqIQQgBkEDayEDIAEtAAIgC3QgCmohCiAFQQdLBEAgBCEBIAMhBiAJIQUMAQsgA0UEQCAEIQFBACEGIAkhBSANIQQMBgsgBUEgaiEFIAZBBGshBiABLQADIAl0IApqIQogAUEEaiEBC0EAIQkgCEEEcQRAIAogBygCIEcNAgtBACEFCyAHQdD+ADYCBEEBIQQgCSEKDAMLIAdB0f4ANgIEIAxBjQw2AhggBygCBCEIDAELC0EAIQYgDSEECyAMIA82AhAgDCAQNgIMIAwgBjYCBCAMIAE2AgAgByAFNgKIASAHIAo2AoQBAkAgBygCLA0AIA8gFkYNAiAHKAIEIgFB0P4ASw0CIAFBzv4ASQ0ACwJ/IBYgD2shCiAHKAIMQQRxIQkCQAJAAkAgDCgCHCIDKAI4Ig1FBEBBASEIIAMgAygCACIBKAIgIAEoAiggAygCmEdBASADKAIodGpBARAoIg02AjggDUUNAQsgAygCLCIGRQRAIANCADcDMCADQQEgAygCKHQiBjYCLAsgBiAKTQRAAkAgCQRAAkAgBiAKTw0AIAogBmshBSAQIAprIQEgDCgCHCIGKAIUBEAgBkFAayABIAVBAEHYgAEoAgARCAAMAQsgBiAGKAIcIAEgBUHAgAEoAgARAAAiATYCHCAMIAE2AjALIAMoAiwiDUUNASAQIA1rIQUgAygCOCEBIAwoAhwiBigCFARAIAZBQGsgASAFIA1B3IABKAIAEQgADAILIAYgBigCHCABIAUgDUHEgAEoAgARBAAiATYCHCAMIAE2AjAMAQsgDSAQIAZrIAYQBxoLIANBADYCNCADIAMoAiw2AjBBAAwECyAKIAYgAygCNCIFayIBIAEgCksbIQsgECAKayEGIAUgDWohBQJAIAkEQAJAIAtFDQAgDCgCHCIBKAIUBEAgAUFAayAFIAYgC0HcgAEoAgARCAAMAQsgASABKAIcIAUgBiALQcSAASgCABEEACIBNgIcIAwgATYCMAsgCiALayIFRQ0BIBAgBWshBiADKAI4IQEgDCgCHCINKAIUBEAgDUFAayABIAYgBUHcgAEoAgARCAAMBQsgDSANKAIcIAEgBiAFQcSAASgCABEEACIBNgIcIAwgATYCMAwECyAFIAYgCxAHGiAKIAtrIgUNAgtBACEIIANBACADKAI0IAtqIgUgBSADKAIsIgFGGzYCNCABIAMoAjAiAU0NACADIAEgC2o2AjALIAgMAgsgAygCOCAQIAVrIAUQBxoLIAMgBTYCNCADIAMoAiw2AjBBAAtFBEAgDCgCECEPIAwoAgQhFyAHKAKIAQwDCyAHQdL+ADYCBAtBfCEXDAILIAYhFyAFCyEFIAwgICAXayIBIAwoAghqNgIIIAwgFiAPayIGIAwoAhRqNgIUIAcgBygCICAGajYCICAMIAcoAghBAEdBBnQgBWogBygCBCIFQb/+AEZBB3RqQYACIAVBwv4ARkEIdCAFQcf+AEYbajYCLCAEIARBeyAEGyABIAZyGyEXCyAUQRBqJAAgFwshASACIAIpAwAgADUCIH03AwACQAJAAkACQCABQQVqDgcBAgICAgMAAgtBAQ8LIAAoAhQNAEEDDwsgACgCACIABEAgACABNgIEIABBDTYCAAtBAiEBCyABCwkAIABBAToADAtEAAJAIAJC/////w9YBEAgACgCFEUNAQsgACgCACIABEAgAEEANgIEIABBEjYCAAtBAA8LIAAgATYCECAAIAI+AhRBAQu5AQEEfyAAQRBqIQECfyAALQAEBEAgARCEAQwBC0F+IQMCQCABRQ0AIAEoAiBFDQAgASgCJCIERQ0AIAEoAhwiAkUNACACKAIAIAFHDQAgAigCBEG0/gBrQR9LDQAgAigCOCIDBEAgBCABKAIoIAMQHiABKAIkIQQgASgCHCECCyAEIAEoAiggAhAeQQAhAyABQQA2AhwLIAMLIgEEQCAAKAIAIgAEQCAAIAE2AgQgAEENNgIACwsgAUUL0gwBBn8gAEIANwIQIABCADcCHCAAQRBqIQICfyAALQAEBEAgACgCCCEBQesMLQAAQTFGBH8Cf0F+IQMCQCACRQ0AIAJBADYCGCACKAIgIgRFBEAgAkEANgIoIAJBJzYCIEEnIQQLIAIoAiRFBEAgAkEoNgIkC0EGIAEgAUF/RhsiBUEASA0AIAVBCUoNAEF8IQMgBCACKAIoQQFB0C4QKCIBRQ0AIAIgATYCHCABIAI2AgAgAUEPNgI0IAFCgICAgKAFNwIcIAFBADYCFCABQYCAAjYCMCABQf//ATYCOCABIAIoAiAgAigCKEGAgAJBAhAoNgJIIAEgAigCICACKAIoIAEoAjBBAhAoIgM2AkwgA0EAIAEoAjBBAXQQGSACKAIgIAIoAihBgIAEQQIQKCEDIAFBgIACNgLoLSABQQA2AkAgASADNgJQIAEgAigCICACKAIoQYCAAkEEECgiAzYCBCABIAEoAugtIgRBAnQ2AgwCQAJAIAEoAkhFDQAgASgCTEUNACABKAJQRQ0AIAMNAQsgAUGaBTYCICACQejAACgCADYCGCACEIQBGkF8DAILIAFBADYCjAEgASAFNgKIASABQgA3AyggASADIARqNgLsLSABIARBA2xBA2s2AvQtQX4hAwJAIAJFDQAgAigCIEUNACACKAIkRQ0AIAIoAhwiAUUNACABKAIAIAJHDQACQAJAIAEoAiAiBEE5aw45AQICAgICAgICAgICAQICAgECAgICAgICAgICAgICAgICAgECAgICAgICAgICAgECAgICAgICAgIBAAsgBEGaBUYNACAEQSpHDQELIAJBAjYCLCACQQA2AgggAkIANwIUIAFBADYCECABIAEoAgQ2AgggASgCFCIDQX9MBEAgAUEAIANrIgM2AhQLIAFBOUEqIANBAkYbNgIgIAIgA0ECRgR/IAFBoAFqQeSAASgCABEBAAVBAQs2AjAgAUF+NgIkIAFBADYCoC4gAUIANwOYLiABQYgXakGg0wA2AgAgASABQcwVajYCgBcgAUH8FmpBjNMANgIAIAEgAUHYE2o2AvQWIAFB8BZqQfjSADYCACABIAFB5AFqNgLoFiABEIgBQQAhAwsgAw0AIAIoAhwiAiACKAIwQQF0NgJEQQAhAyACKAJQQQBBgIAIEBkgAiACKAKIASIEQQxsIgFBtNgAai8BADYClAEgAiABQbDYAGovAQA2ApABIAIgAUGy2ABqLwEANgJ4IAIgAUG22ABqLwEANgJ0QfiAASgCACEFQeyAASgCACEGQYCBASgCACEBIAJCADcCbCACQgA3AmQgAkEANgI8IAJBADYChC4gAkIANwJUIAJBKSABIARBCUYiARs2AnwgAkEqIAYgARs2AoABIAJBKyAFIAEbNgKEAQsgAwsFQXoLDAELAn9BekHrDC0AAEExRw0AGkF+IAJFDQAaIAJBADYCGCACKAIgIgNFBEAgAkEANgIoIAJBJzYCIEEnIQMLIAIoAiRFBEAgAkEoNgIkC0F8IAMgAigCKEEBQaDHABAoIgRFDQAaIAIgBDYCHCAEQQA2AjggBCACNgIAIARBtP4ANgIEIARBzIABKAIAEQkANgKYR0F+IQMCQCACRQ0AIAIoAiBFDQAgAigCJCIFRQ0AIAIoAhwiAUUNACABKAIAIAJHDQAgASgCBEG0/gBrQR9LDQACQAJAIAEoAjgiBgRAIAEoAihBD0cNAQsgAUEPNgIoIAFBADYCDAwBCyAFIAIoAiggBhAeIAFBADYCOCACKAIgIQUgAUEPNgIoIAFBADYCDCAFRQ0BCyACKAIkRQ0AIAIoAhwiAUUNACABKAIAIAJHDQAgASgCBEG0/gBrQR9LDQBBACEDIAFBADYCNCABQgA3AiwgAUEANgIgIAJBADYCCCACQgA3AhQgASgCDCIFBEAgAiAFQQFxNgIwCyABQrT+ADcCBCABQgA3AoQBIAFBADYCJCABQoCAgoAQNwMYIAFCgICAgHA3AxAgAUKBgICAcDcCjEcgASABQfwKaiIFNgK4ASABIAU2ApwBIAEgBTYCmAELQQAgA0UNABogAigCJCACKAIoIAQQHiACQQA2AhwgAwsLIgIEQCAAKAIAIgAEQCAAIAI2AgQgAEENNgIACwsgAkULKQEBfyAALQAERQRAQQAPC0ECIQEgACgCCCIAQQNOBH8gAEEHSgVBAgsLBgAgABAGC2MAQcgAEAkiAEUEQEGEhAEoAgAhASACBEAgAiABNgIEIAJBATYCAAsgAA8LIABBADoADCAAQQE6AAQgACACNgIAIABBADYCOCAAQgA3AzAgACABQQkgAUEBa0EJSRs2AgggAAukCgIIfwF+QfCAAUH0gAEgACgCdEGBCEkbIQYCQANAAkACfwJAIAAoAjxBhQJLDQAgABAvAkAgACgCPCICQYUCSw0AIAENAEEADwsgAkUNAiACQQRPDQBBAAwBCyAAIAAoAmggACgChAERAgALIQMgACAAKAJsOwFgQQIhAgJAIAA1AmggA619IgpCAVMNACAKIAAoAjBBhgJrrVUNACAAKAJwIAAoAnhPDQAgA0UNACAAIAMgBigCABECACICQQVLDQBBAiACIAAoAowBQQFGGyECCwJAIAAoAnAiA0EDSQ0AIAIgA0sNACAAIAAoAvAtIgJBAWo2AvAtIAAoAjwhBCACIAAoAuwtaiAAKAJoIgcgAC8BYEF/c2oiAjoAACAAIAAoAvAtIgVBAWo2AvAtIAUgACgC7C1qIAJBCHY6AAAgACAAKALwLSIFQQFqNgLwLSAFIAAoAuwtaiADQQNrOgAAIAAgACgCgC5BAWo2AoAuIANB/c4Aai0AAEECdCAAakHoCWoiAyADLwEAQQFqOwEAIAAgAkEBayICIAJBB3ZBgAJqIAJBgAJJG0GAywBqLQAAQQJ0akHYE2oiAiACLwEAQQFqOwEAIAAgACgCcCIFQQFrIgM2AnAgACAAKAI8IANrNgI8IAAoAvQtIQggACgC8C0hCSAEIAdqQQNrIgQgACgCaCICSwRAIAAgAkEBaiAEIAJrIgIgBUECayIEIAIgBEkbIAAoAoABEQUAIAAoAmghAgsgAEEANgJkIABBADYCcCAAIAIgA2oiBDYCaCAIIAlHDQJBACECIAAgACgCWCIDQQBOBH8gACgCSCADagVBAAsgBCADa0EAEA8gACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQDQIMAwsgACgCZARAIAAoAmggACgCSGpBAWstAAAhAyAAIAAoAvAtIgRBAWo2AvAtIAQgACgC7C1qQQA6AAAgACAAKALwLSIEQQFqNgLwLSAEIAAoAuwtakEAOgAAIAAgACgC8C0iBEEBajYC8C0gBCAAKALsLWogAzoAACAAIANBAnRqIgMgAy8B5AFBAWo7AeQBIAAoAvAtIAAoAvQtRgRAIAAgACgCWCIDQQBOBH8gACgCSCADagVBAAsgACgCaCADa0EAEA8gACAAKAJoNgJYIAAoAgAQCgsgACACNgJwIAAgACgCaEEBajYCaCAAIAAoAjxBAWs2AjwgACgCACgCEA0CQQAPBSAAQQE2AmQgACACNgJwIAAgACgCaEEBajYCaCAAIAAoAjxBAWs2AjwMAgsACwsgACgCZARAIAAoAmggACgCSGpBAWstAAAhAiAAIAAoAvAtIgNBAWo2AvAtIAMgACgC7C1qQQA6AAAgACAAKALwLSIDQQFqNgLwLSADIAAoAuwtakEAOgAAIAAgACgC8C0iA0EBajYC8C0gAyAAKALsLWogAjoAACAAIAJBAnRqIgIgAi8B5AFBAWo7AeQBIAAoAvAtIAAoAvQtRhogAEEANgJkCyAAIAAoAmgiA0ECIANBAkkbNgKELiABQQRGBEAgACAAKAJYIgFBAE4EfyAAKAJIIAFqBUEACyADIAFrQQEQDyAAIAAoAmg2AlggACgCABAKQQNBAiAAKAIAKAIQGw8LIAAoAvAtBEBBACECIAAgACgCWCIBQQBOBH8gACgCSCABagVBAAsgAyABa0EAEA8gACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQRQ0BC0EBIQILIAIL2BACEH8BfiAAKAKIAUEFSCEOA0ACQAJ/AkACQAJAAn8CQAJAIAAoAjxBhQJNBEAgABAvIAAoAjwiA0GFAksNASABDQFBAA8LIA4NASAIIQMgBSEHIAohDSAGQf//A3FFDQEMAwsgA0UNA0EAIANBBEkNARoLIAAgACgCaEH4gAEoAgARAgALIQZBASECQQAhDSAAKAJoIgOtIAatfSISQgFTDQIgEiAAKAIwQYYCa61VDQIgBkUNAiAAIAZB8IABKAIAEQIAIgZBASAGQfz/A3EbQQEgACgCbCINQf//A3EgA0H//wNxSRshBiADIQcLAkAgACgCPCIEIAZB//8DcSICQQRqTQ0AIAZB//8DcUEDTQRAQQEgBkEBa0H//wNxIglFDQQaIANB//8DcSIEIAdBAWpB//8DcSIDSw0BIAAgAyAJIAQgA2tBAWogAyAJaiAESxtB7IABKAIAEQUADAELAkAgACgCeEEEdCACSQ0AIARBBEkNACAGQQFrQf//A3EiDCAHQQFqQf//A3EiBGohCSAEIANB//8DcSIDTwRAQeyAASgCACELIAMgCUkEQCAAIAQgDCALEQUADAMLIAAgBCADIARrQQFqIAsRBQAMAgsgAyAJTw0BIAAgAyAJIANrQeyAASgCABEFAAwBCyAGIAdqQf//A3EiA0UNACAAIANBAWtB+IABKAIAEQIAGgsgBgwCCyAAIAAoAmgiBUECIAVBAkkbNgKELiABQQRGBEBBACEDIAAgACgCWCIBQQBOBH8gACgCSCABagVBAAsgBSABa0EBEA8gACAAKAJoNgJYIAAoAgAQCkEDQQIgACgCACgCEBsPCyAAKALwLQRAQQAhAkEAIQMgACAAKAJYIgFBAE4EfyAAKAJIIAFqBUEACyAFIAFrQQAQDyAAIAAoAmg2AlggACgCABAKIAAoAgAoAhBFDQMLQQEhAgwCCyADIQdBAQshBEEAIQYCQCAODQAgACgCPEGHAkkNACACIAdB//8DcSIQaiIDIAAoAkRBhgJrTw0AIAAgAzYCaEEAIQogACADQfiAASgCABECACEFAn8CQCAAKAJoIgitIAWtfSISQgFTDQAgEiAAKAIwQYYCa61VDQAgBUUNACAAIAVB8IABKAIAEQIAIQYgAC8BbCIKIAhB//8DcSIFTw0AIAZB//8DcSIDQQRJDQAgCCAEQf//A3FBAkkNARogCCACIApBAWpLDQEaIAggAiAFQQFqSw0BGiAIIAAoAkgiCSACa0EBaiICIApqLQAAIAIgBWotAABHDQEaIAggCUEBayICIApqIgwtAAAgAiAFaiIPLQAARw0BGiAIIAUgCCAAKAIwQYYCayICa0H//wNxQQAgAiAFSRsiEU0NARogCCADQf8BSw0BGiAGIQUgCCECIAQhAyAIIAoiCUECSQ0BGgNAAkAgA0EBayEDIAVBAWohCyAJQQFrIQkgAkEBayECIAxBAWsiDC0AACAPQQFrIg8tAABHDQAgA0H//wNxRQ0AIBEgAkH//wNxTw0AIAVB//8DcUH+AUsNACALIQUgCUH//wNxQQFLDQELCyAIIANB//8DcUEBSw0BGiAIIAtB//8DcUECRg0BGiAIQQFqIQggAyEEIAshBiAJIQogAgwBC0EBIQYgCAshBSAAIBA2AmgLAn8gBEH//wNxIgNBA00EQCAEQf//A3EiA0UNAyAAKAJIIAdB//8DcWotAAAhBCAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qQQA6AAAgACAAKALwLSICQQFqNgLwLSACIAAoAuwtakEAOgAAIAAgACgC8C0iAkEBajYC8C0gAiAAKALsLWogBDoAACAAIARBAnRqIgRB5AFqIAQvAeQBQQFqOwEAIAAgACgCPEEBazYCPCAAKALwLSICIAAoAvQtRiIEIANBAUYNARogACgCSCAHQQFqQf//A3FqLQAAIQkgACACQQFqNgLwLSAAKALsLSACakEAOgAAIAAgACgC8C0iAkEBajYC8C0gAiAAKALsLWpBADoAACAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qIAk6AAAgACAJQQJ0aiICQeQBaiACLwHkAUEBajsBACAAIAAoAjxBAWs2AjwgBCAAKALwLSICIAAoAvQtRmoiBCADQQJGDQEaIAAoAkggB0ECakH//wNxai0AACEHIAAgAkEBajYC8C0gACgC7C0gAmpBADoAACAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qQQA6AAAgACAAKALwLSICQQFqNgLwLSACIAAoAuwtaiAHOgAAIAAgB0ECdGoiB0HkAWogBy8B5AFBAWo7AQAgACAAKAI8QQFrNgI8IAQgACgC8C0gACgC9C1GagwBCyAAIAAoAvAtIgJBAWo2AvAtIAIgACgC7C1qIAdB//8DcSANQf//A3FrIgc6AAAgACAAKALwLSICQQFqNgLwLSACIAAoAuwtaiAHQQh2OgAAIAAgACgC8C0iAkEBajYC8C0gAiAAKALsLWogBEEDazoAACAAIAAoAoAuQQFqNgKALiADQf3OAGotAABBAnQgAGpB6AlqIgQgBC8BAEEBajsBACAAIAdBAWsiBCAEQQd2QYACaiAEQYACSRtBgMsAai0AAEECdGpB2BNqIgQgBC8BAEEBajsBACAAIAAoAjwgA2s2AjwgACgC8C0gACgC9C1GCyEEIAAgACgCaCADaiIHNgJoIARFDQFBACECQQAhBCAAIAAoAlgiA0EATgR/IAAoAkggA2oFQQALIAcgA2tBABAPIAAgACgCaDYCWCAAKAIAEAogACgCACgCEA0BCwsgAgu0BwIEfwF+AkADQAJAAkACQAJAIAAoAjxBhQJNBEAgABAvAkAgACgCPCICQYUCSw0AIAENAEEADwsgAkUNBCACQQRJDQELIAAgACgCaEH4gAEoAgARAgAhAiAANQJoIAKtfSIGQgFTDQAgBiAAKAIwQYYCa61VDQAgAkUNACAAIAJB8IABKAIAEQIAIgJBBEkNACAAIAAoAvAtIgNBAWo2AvAtIAMgACgC7C1qIAAoAmggACgCbGsiAzoAACAAIAAoAvAtIgRBAWo2AvAtIAQgACgC7C1qIANBCHY6AAAgACAAKALwLSIEQQFqNgLwLSAEIAAoAuwtaiACQQNrOgAAIAAgACgCgC5BAWo2AoAuIAJB/c4Aai0AAEECdCAAakHoCWoiBCAELwEAQQFqOwEAIAAgA0EBayIDIANBB3ZBgAJqIANBgAJJG0GAywBqLQAAQQJ0akHYE2oiAyADLwEAQQFqOwEAIAAgACgCPCACayIFNgI8IAAoAvQtIQMgACgC8C0hBCAAKAJ4IAJPQQAgBUEDSxsNASAAIAAoAmggAmoiAjYCaCAAIAJBAWtB+IABKAIAEQIAGiADIARHDQQMAgsgACgCSCAAKAJoai0AACECIAAgACgC8C0iA0EBajYC8C0gAyAAKALsLWpBADoAACAAIAAoAvAtIgNBAWo2AvAtIAMgACgC7C1qQQA6AAAgACAAKALwLSIDQQFqNgLwLSADIAAoAuwtaiACOgAAIAAgAkECdGoiAkHkAWogAi8B5AFBAWo7AQAgACAAKAI8QQFrNgI8IAAgACgCaEEBajYCaCAAKALwLSAAKAL0LUcNAwwBCyAAIAAoAmhBAWoiBTYCaCAAIAUgAkEBayICQeyAASgCABEFACAAIAAoAmggAmo2AmggAyAERw0CC0EAIQNBACECIAAgACgCWCIEQQBOBH8gACgCSCAEagVBAAsgACgCaCAEa0EAEA8gACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQDQEMAgsLIAAgACgCaCIEQQIgBEECSRs2AoQuIAFBBEYEQEEAIQIgACAAKAJYIgFBAE4EfyAAKAJIIAFqBUEACyAEIAFrQQEQDyAAIAAoAmg2AlggACgCABAKQQNBAiAAKAIAKAIQGw8LIAAoAvAtBEBBACEDQQAhAiAAIAAoAlgiAUEATgR/IAAoAkggAWoFQQALIAQgAWtBABAPIAAgACgCaDYCWCAAKAIAEAogACgCACgCEEUNAQtBASEDCyADC80JAgl/An4gAUEERiEGIAAoAiwhAgJAAkACQCABQQRGBEAgAkECRg0CIAIEQCAAQQAQUCAAQQA2AiwgACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQRQ0ECyAAIAYQTyAAQQI2AiwMAQsgAg0BIAAoAjxFDQEgACAGEE8gAEEBNgIsCyAAIAAoAmg2AlgLQQJBASABQQRGGyEKA0ACQCAAKAIMIAAoAhBBCGpLDQAgACgCABAKIAAoAgAiAigCEA0AQQAhAyABQQRHDQIgAigCBA0CIAAoAqAuDQIgACgCLEVBAXQPCwJAAkAgACgCPEGFAk0EQCAAEC8CQCAAKAI8IgNBhQJLDQAgAQ0AQQAPCyADRQ0CIAAoAiwEfyADBSAAIAYQTyAAIAo2AiwgACAAKAJoNgJYIAAoAjwLQQRJDQELIAAgACgCaEH4gAEoAgARAgAhBCAAKAJoIgKtIAStfSILQgFTDQAgCyAAKAIwQYYCa61VDQAgAiAAKAJIIgJqIgMvAAAgAiAEaiICLwAARw0AIANBAmogAkECakHQgAEoAgARAgBBAmoiA0EESQ0AIAAoAjwiAiADIAIgA0kbIgJBggIgAkGCAkkbIgdB/c4Aai0AACICQQJ0IgRBhMkAajMBACEMIARBhskAai8BACEDIAJBCGtBE00EQCAHQQNrIARBgNEAaigCAGutIAOthiAMhCEMIARBsNYAaigCACADaiEDCyAAKAKgLiEFIAMgC6dBAWsiCCAIQQd2QYACaiAIQYACSRtBgMsAai0AACICQQJ0IglBgsoAai8BAGohBCAJQYDKAGozAQAgA62GIAyEIQsgACkDmC4hDAJAIAUgAkEESQR/IAQFIAggCUGA0gBqKAIAa60gBK2GIAuEIQsgCUGw1wBqKAIAIARqCyICaiIDQT9NBEAgCyAFrYYgDIQhCwwBCyAFQcAARgRAIAAoAgQgACgCEGogDDcAACAAIAAoAhBBCGo2AhAgAiEDDAELIAAoAgQgACgCEGogCyAFrYYgDIQ3AAAgACAAKAIQQQhqNgIQIANBQGohAyALQcAAIAVrrYghCwsgACALNwOYLiAAIAM2AqAuIAAgACgCPCAHazYCPCAAIAAoAmggB2o2AmgMAgsgACgCSCAAKAJoai0AAEECdCICQYDBAGozAQAhCyAAKQOYLiEMAkAgACgCoC4iBCACQYLBAGovAQAiAmoiA0E/TQRAIAsgBK2GIAyEIQsMAQsgBEHAAEYEQCAAKAIEIAAoAhBqIAw3AAAgACAAKAIQQQhqNgIQIAIhAwwBCyAAKAIEIAAoAhBqIAsgBK2GIAyENwAAIAAgACgCEEEIajYCECADQUBqIQMgC0HAACAEa62IIQsLIAAgCzcDmC4gACADNgKgLiAAIAAoAmhBAWo2AmggACAAKAI8QQFrNgI8DAELCyAAIAAoAmgiAkECIAJBAkkbNgKELiAAKAIsIQIgAUEERgRAAkAgAkUNACAAQQEQUCAAQQA2AiwgACAAKAJoNgJYIAAoAgAQCiAAKAIAKAIQDQBBAg8LQQMPCyACBEBBACEDIABBABBQIABBADYCLCAAIAAoAmg2AlggACgCABAKIAAoAgAoAhBFDQELQQEhAwsgAwucAQEFfyACQQFOBEAgAiAAKAJIIAFqIgNqQQJqIQQgA0ECaiECIAAoAlQhAyAAKAJQIQUDQCAAIAItAAAgA0EFdEHg/wFxcyIDNgJUIAUgA0EBdGoiBi8BACIHIAFB//8DcUcEQCAAKAJMIAEgACgCOHFB//8DcUEBdGogBzsBACAGIAE7AQALIAFBAWohASACQQFqIgIgBEkNAAsLC1sBAn8gACAAKAJIIAFqLQACIAAoAlRBBXRB4P8BcXMiAjYCVCABIAAoAlAgAkEBdGoiAy8BACICRwRAIAAoAkwgACgCOCABcUEBdGogAjsBACADIAE7AQALIAILEwAgAUEFdEHg/wFxIAJB/wFxcwsGACABEAYLLwAjAEEQayIAJAAgAEEMaiABIAJsEIwBIQEgACgCDCECIABBEGokAEEAIAIgARsLjAoCAX4CfyMAQfAAayIGJAACQAJAAkACQAJAAkACQAJAIAQODwABBwIEBQYGBgYGBgYGAwYLQn8hBQJAIAAgBkHkAGpCDBARIgNCf1cEQCABBEAgASAAKAIMNgIAIAEgACgCEDYCBAsMAQsCQCADQgxSBEAgAQRAIAFBADYCBCABQRE2AgALDAELIAEoAhQhBEEAIQJCASEFA0AgBkHkAGogAmoiAiACLQAAIARB/f8DcSICQQJyIAJBA3NsQQh2cyICOgAAIAYgAjoAKCABAn8gASgCDEF/cyECQQAgBkEoaiIERQ0AGiACIARBAUHUgAEoAgARAAALQX9zIgI2AgwgASABKAIQIAJB/wFxakGFiKLAAGxBAWoiAjYCECAGIAJBGHY6ACggAQJ/IAEoAhRBf3MhAkEAIAZBKGoiBEUNABogAiAEQQFB1IABKAIAEQAAC0F/cyIENgIUIAVCDFIEQCAFpyECIAVCAXwhBQwBCwtCACEFIAAgBkEoahAhQQBIDQEgBigCUCEAIwBBEGsiAiQAIAIgADYCDCAGAn8gAkEMahCNASIARQRAIAZBITsBJEEADAELAn8gACgCFCIEQdAATgRAIARBCXQMAQsgAEHQADYCFEGAwAILIQQgBiAAKAIMIAQgACgCEEEFdGpqQaDAAWo7ASQgACgCBEEFdCAAKAIIQQt0aiAAKAIAQQF2ags7ASYgAkEQaiQAIAYtAG8iACAGLQBXRg0BIAYtACcgAEYNASABBEAgAUEANgIEIAFBGzYCAAsLQn8hBQsgBkHwAGokACAFDwtCfyEFIAAgAiADEBEiA0J/VwRAIAEEQCABIAAoAgw2AgAgASAAKAIQNgIECwwGCyMAQRBrIgAkAAJAIANQDQAgASgCFCEEIAJFBEBCASEFA0AgACACIAdqLQAAIARB/f8DcSIEQQJyIARBA3NsQQh2czoADyABAn8gASgCDEF/cyEEQQAgAEEPaiIHRQ0AGiAEIAdBAUHUgAEoAgARAAALQX9zIgQ2AgwgASABKAIQIARB/wFxakGFiKLAAGxBAWoiBDYCECAAIARBGHY6AA8gAQJ/IAEoAhRBf3MhBEEAIABBD2oiB0UNABogBCAHQQFB1IABKAIAEQAAC0F/cyIENgIUIAMgBVENAiAFpyEHIAVCAXwhBQwACwALQgEhBQNAIAAgAiAHai0AACAEQf3/A3EiBEECciAEQQNzbEEIdnMiBDoADyACIAdqIAQ6AAAgAQJ/IAEoAgxBf3MhBEEAIABBD2oiB0UNABogBCAHQQFB1IABKAIAEQAAC0F/cyIENgIMIAEgASgCECAEQf8BcWpBhYiiwABsQQFqIgQ2AhAgACAEQRh2OgAPIAECfyABKAIUQX9zIQRBACAAQQ9qIgdFDQAaIAQgB0EBQdSAASgCABEAAAtBf3MiBDYCFCADIAVRDQEgBachByAFQgF8IQUMAAsACyAAQRBqJAAgAyEFDAULIAJBADsBMiACIAIpAwAiA0KAAYQ3AwAgA0IIg1ANBCACIAIpAyBCDH03AyAMBAsgBkKFgICAcDcDECAGQoOAgIDAADcDCCAGQoGAgIAgNwMAQQAgBhAkIQUMAwsgA0IIWgR+IAIgASgCADYCACACIAEoAgQ2AgRCCAVCfwshBQwCCyABEAYMAQsgAQRAIAFBADYCBCABQRI2AgALQn8hBQsgBkHwAGokACAFC60DAgJ/An4jAEEQayIGJAACQAJAAkAgBEUNACABRQ0AIAJBAUYNAQtBACEDIABBCGoiAARAIABBADYCBCAAQRI2AgALDAELIANBAXEEQEEAIQMgAEEIaiIABEAgAEEANgIEIABBGDYCAAsMAQtBGBAJIgVFBEBBACEDIABBCGoiAARAIABBADYCBCAAQQ42AgALDAELIAVBADYCCCAFQgA3AgAgBUGQ8dmiAzYCFCAFQvis0ZGR8dmiIzcCDAJAIAQQIiICRQ0AIAKtIQhBACEDQYfTru5+IQJCASEHA0AgBiADIARqLQAAOgAPIAUgBkEPaiIDBH8gAiADQQFB1IABKAIAEQAABUEAC0F/cyICNgIMIAUgBSgCECACQf8BcWpBhYiiwABsQQFqIgI2AhAgBiACQRh2OgAPIAUCfyAFKAIUQX9zIQJBACAGQQ9qIgNFDQAaIAIgA0EBQdSAASgCABEAAAtBf3M2AhQgByAIUQ0BIAUoAgxBf3MhAiAHpyEDIAdCAXwhBwwACwALIAAgAUElIAUQQiIDDQAgBRAGQQAhAwsgBkEQaiQAIAMLnRoCBn4FfyMAQdAAayILJAACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADDhQFBhULAwQJDgACCBAKDw0HEQERDBELAkBByAAQCSIBBEAgAUIANwMAIAFCADcDMCABQQA2AiggAUIANwMgIAFCADcDGCABQgA3AxAgAUIANwMIIAFCADcDOCABQQgQCSIDNgIEIAMNASABEAYgAARAIABBADYCBCAAQQ42AgALCyAAQQA2AhQMFAsgA0IANwMAIAAgATYCFCABQUBrQgA3AwAgAUIANwM4DBQLAkACQCACUARAQcgAEAkiA0UNFCADQgA3AwAgA0IANwMwIANBADYCKCADQgA3AyAgA0IANwMYIANCADcDECADQgA3AwggA0IANwM4IANBCBAJIgE2AgQgAQ0BIAMQBiAABEAgAEEANgIEIABBDjYCAAsMFAsgAiAAKAIQIgEpAzBWBEAgAARAIABBADYCBCAAQRI2AgALDBQLIAEoAigEQCAABEAgAEEANgIEIABBHTYCAAsMFAsgASgCBCEDAkAgASkDCCIGQgF9IgdQDQADQAJAIAIgAyAHIAR9QgGIIAR8IgWnQQN0aikDAFQEQCAFQgF9IQcMAQsgBSAGUQRAIAYhBQwDCyADIAVCAXwiBKdBA3RqKQMAIAJWDQILIAQhBSAEIAdUDQALCwJAIAIgAyAFpyIKQQN0aikDAH0iBFBFBEAgASgCACIDIApBBHRqKQMIIQcMAQsgASgCACIDIAVCAX0iBadBBHRqKQMIIgchBAsgAiAHIAR9VARAIAAEQCAAQQA2AgQgAEEcNgIACwwUCyADIAVCAXwiBUEAIAAQiQEiA0UNEyADKAIAIAMoAggiCkEEdGpBCGsgBDcDACADKAIEIApBA3RqIAI3AwAgAyACNwMwIAMgASkDGCIGIAMpAwgiBEIBfSIHIAYgB1QbNwMYIAEgAzYCKCADIAE2AiggASAENwMgIAMgBTcDIAwBCyABQgA3AwALIAAgAzYCFCADIAQ3A0AgAyACNwM4QgAhBAwTCyAAKAIQIgEEQAJAIAEoAigiA0UEQCABKQMYIQIMAQsgA0EANgIoIAEoAihCADcDICABIAEpAxgiAiABKQMgIgUgAiAFVhsiAjcDGAsgASkDCCACVgRAA0AgASgCACACp0EEdGooAgAQBiACQgF8IgIgASkDCFQNAAsLIAEoAgAQBiABKAIEEAYgARAGCyAAKAIUIQEgAEEANgIUIAAgATYCEAwSCyACQghaBH4gASAAKAIANgIAIAEgACgCBDYCBEIIBUJ/CyEEDBELIAAoAhAiAQRAAkAgASgCKCIDRQRAIAEpAxghAgwBCyADQQA2AiggASgCKEIANwMgIAEgASkDGCICIAEpAyAiBSACIAVWGyICNwMYCyABKQMIIAJWBEADQCABKAIAIAKnQQR0aigCABAGIAJCAXwiAiABKQMIVA0ACwsgASgCABAGIAEoAgQQBiABEAYLIAAoAhQiAQRAAkAgASgCKCIDRQRAIAEpAxghAgwBCyADQQA2AiggASgCKEIANwMgIAEgASkDGCICIAEpAyAiBSACIAVWGyICNwMYCyABKQMIIAJWBEADQCABKAIAIAKnQQR0aigCABAGIAJCAXwiAiABKQMIVA0ACwsgASgCABAGIAEoAgQQBiABEAYLIAAQBgwQCyAAKAIQIgBCADcDOCAAQUBrQgA3AwAMDwsgAkJ/VwRAIAAEQCAAQQA2AgQgAEESNgIACwwOCyACIAAoAhAiAykDMCADKQM4IgZ9IgUgAiAFVBsiBVANDiABIAMpA0AiB6ciAEEEdCIBIAMoAgBqIgooAgAgBiADKAIEIABBA3RqKQMAfSICp2ogBSAKKQMIIAJ9IgYgBSAGVBsiBKcQByEKIAcgBCADKAIAIgAgAWopAwggAn1RrXwhAiAFIAZWBEADQCAKIASnaiAAIAKnQQR0IgFqIgAoAgAgBSAEfSIGIAApAwgiByAGIAdUGyIGpxAHGiACIAYgAygCACIAIAFqKQMIUa18IQIgBSAEIAZ8IgRWDQALCyADIAI3A0AgAyADKQM4IAR8NwM4DA4LQn8hBEHIABAJIgNFDQ0gA0IANwMAIANCADcDMCADQQA2AiggA0IANwMgIANCADcDGCADQgA3AxAgA0IANwMIIANCADcDOCADQQgQCSIBNgIEIAFFBEAgAxAGIAAEQCAAQQA2AgQgAEEONgIACwwOCyABQgA3AwAgACgCECIBBEACQCABKAIoIgpFBEAgASkDGCEEDAELIApBADYCKCABKAIoQgA3AyAgASABKQMYIgIgASkDICIFIAIgBVYbIgQ3AxgLIAEpAwggBFYEQANAIAEoAgAgBKdBBHRqKAIAEAYgBEIBfCIEIAEpAwhUDQALCyABKAIAEAYgASgCBBAGIAEQBgsgACADNgIQQgAhBAwNCyAAKAIUIgEEQAJAIAEoAigiA0UEQCABKQMYIQIMAQsgA0EANgIoIAEoAihCADcDICABIAEpAxgiAiABKQMgIgUgAiAFVhsiAjcDGAsgASkDCCACVgRAA0AgASgCACACp0EEdGooAgAQBiACQgF8IgIgASkDCFQNAAsLIAEoAgAQBiABKAIEEAYgARAGCyAAQQA2AhQMDAsgACgCECIDKQM4IAMpAzAgASACIAAQRCIHQgBTDQogAyAHNwM4AkAgAykDCCIGQgF9IgJQDQAgAygCBCEAA0ACQCAHIAAgAiAEfUIBiCAEfCIFp0EDdGopAwBUBEAgBUIBfSECDAELIAUgBlEEQCAGIQUMAwsgACAFQgF8IgSnQQN0aikDACAHVg0CCyAEIQUgAiAEVg0ACwsgAyAFNwNAQgAhBAwLCyAAKAIUIgMpAzggAykDMCABIAIgABBEIgdCAFMNCSADIAc3AzgCQCADKQMIIgZCAX0iAlANACADKAIEIQADQAJAIAcgACACIAR9QgGIIAR8IgWnQQN0aikDAFQEQCAFQgF9IQIMAQsgBSAGUQRAIAYhBQwDCyAAIAVCAXwiBKdBA3RqKQMAIAdWDQILIAQhBSACIARWDQALCyADIAU3A0BCACEEDAoLIAJCN1gEQCAABEAgAEEANgIEIABBEjYCAAsMCQsgARAqIAEgACgCDDYCKCAAKAIQKQMwIQIgAUEANgIwIAEgAjcDICABIAI3AxggAULcATcDAEI4IQQMCQsgACABKAIANgIMDAgLIAtBQGtBfzYCACALQouAgICwAjcDOCALQoyAgIDQATcDMCALQo+AgICgATcDKCALQpGAgICQATcDICALQoeAgICAATcDGCALQoWAgIDgADcDECALQoOAgIDAADcDCCALQoGAgIAgNwMAQQAgCxAkIQQMBwsgACgCECkDOCIEQn9VDQYgAARAIABBPTYCBCAAQR42AgALDAULIAAoAhQpAzgiBEJ/VQ0FIAAEQCAAQT02AgQgAEEeNgIACwwEC0J/IQQgAkJ/VwRAIAAEQCAAQQA2AgQgAEESNgIACwwFCyACIAAoAhQiAykDOCACfCIFQv//A3wiBFYEQCAABEAgAEEANgIEIABBEjYCAAsMBAsCQCAFIAMoAgQiCiADKQMIIganQQN0aikDACIHWA0AAkAgBCAHfUIQiCAGfCIIIAMpAxAiCVgNAEIQIAkgCVAbIQUDQCAFIgRCAYYhBSAEIAhUDQALIAQgCVQNACADKAIAIASnIgpBBHQQNCIMRQ0DIAMgDDYCACADKAIEIApBA3RBCGoQNCIKRQ0DIAMgBDcDECADIAo2AgQgAykDCCEGCyAGIAhaDQAgAygCACEMA0AgDCAGp0EEdGoiDUGAgAQQCSIONgIAIA5FBEAgAARAIABBADYCBCAAQQ42AgALDAYLIA1CgIAENwMIIAMgBkIBfCIFNwMIIAogBadBA3RqIAdCgIAEfCIHNwMAIAMpAwgiBiAIVA0ACwsgAykDQCEFIAMpAzghBwJAIAJQBEBCACEEDAELIAWnIgBBBHQiDCADKAIAaiINKAIAIAcgCiAAQQN0aikDAH0iBqdqIAEgAiANKQMIIAZ9IgcgAiAHVBsiBKcQBxogBSAEIAMoAgAiACAMaikDCCAGfVGtfCEFIAIgB1YEQANAIAAgBadBBHQiCmoiACgCACABIASnaiACIAR9IgYgACkDCCIHIAYgB1QbIganEAcaIAUgBiADKAIAIgAgCmopAwhRrXwhBSAEIAZ8IgQgAlQNAAsLIAMpAzghBwsgAyAFNwNAIAMgBCAHfCICNwM4IAIgAykDMFgNBCADIAI3AzAMBAsgAARAIABBADYCBCAAQRw2AgALDAILIAAEQCAAQQA2AgQgAEEONgIACyAABEAgAEEANgIEIABBDjYCAAsMAQsgAEEANgIUC0J/IQQLIAtB0ABqJAAgBAtIAQF/IABCADcCBCAAIAE2AgACQCABQQBIDQBBsBMoAgAgAUwNACABQQJ0QcATaigCAEEBRw0AQYSEASgCACECCyAAIAI2AgQLDgAgAkGx893xeWxBEHYLvgEAIwBBEGsiACQAIABBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAQRBqJAAgAkGx893xeWxBEHYLuQEBAX8jAEEQayIBJAAgAUEAOgAIQYCBAUECNgIAQfyAAUEDNgIAQfiAAUEENgIAQfSAAUEFNgIAQfCAAUEGNgIAQeyAAUEHNgIAQeiAAUEINgIAQeSAAUEJNgIAQeCAAUEKNgIAQdyAAUELNgIAQdiAAUEMNgIAQdSAAUENNgIAQdCAAUEONgIAQcyAAUEPNgIAQciAAUEQNgIAQcSAAUERNgIAQcCAAUESNgIAIAAQjgEgAUEQaiQAC78BAQF/IwBBEGsiAiQAIAJBADoACEGAgQFBAjYCAEH8gAFBAzYCAEH4gAFBBDYCAEH0gAFBBTYCAEHwgAFBBjYCAEHsgAFBBzYCAEHogAFBCDYCAEHkgAFBCTYCAEHggAFBCjYCAEHcgAFBCzYCAEHYgAFBDDYCAEHUgAFBDTYCAEHQgAFBDjYCAEHMgAFBDzYCAEHIgAFBEDYCAEHEgAFBETYCAEHAgAFBEjYCACAAIAEQkAEhACACQRBqJAAgAAu+AQEBfyMAQRBrIgIkACACQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABEFohACACQRBqJAAgAAu+AQEBfyMAQRBrIgIkACACQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABEFshACACQRBqJAAgAAu9AQEBfyMAQRBrIgMkACADQQA6AAhBgIEBQQI2AgBB/IABQQM2AgBB+IABQQQ2AgBB9IABQQU2AgBB8IABQQY2AgBB7IABQQc2AgBB6IABQQg2AgBB5IABQQk2AgBB4IABQQo2AgBB3IABQQs2AgBB2IABQQw2AgBB1IABQQ02AgBB0IABQQ42AgBBzIABQQ82AgBByIABQRA2AgBBxIABQRE2AgBBwIABQRI2AgAgACABIAIQjwEgA0EQaiQAC4UBAgR/AX4jAEEQayIBJAACQCAAKQMwUARADAELA0ACQCAAIAVBACABQQ9qIAFBCGoQZiIEQX9GDQAgAS0AD0EDRw0AIAIgASgCCEGAgICAf3FBgICAgHpGaiECC0F/IQMgBEF/Rg0BIAIhAyAFQgF8IgUgACkDMFQNAAsLIAFBEGokACADCwuMdSUAQYAIC7ELaW5zdWZmaWNpZW50IG1lbW9yeQBuZWVkIGRpY3Rpb25hcnkALSsgICAwWDB4AFppcCBhcmNoaXZlIGluY29uc2lzdGVudABJbnZhbGlkIGFyZ3VtZW50AGludmFsaWQgbGl0ZXJhbC9sZW5ndGhzIHNldABpbnZhbGlkIGNvZGUgbGVuZ3RocyBzZXQAdW5rbm93biBoZWFkZXIgZmxhZ3Mgc2V0AGludmFsaWQgZGlzdGFuY2VzIHNldABpbnZhbGlkIGJpdCBsZW5ndGggcmVwZWF0AEZpbGUgYWxyZWFkeSBleGlzdHMAdG9vIG1hbnkgbGVuZ3RoIG9yIGRpc3RhbmNlIHN5bWJvbHMAaW52YWxpZCBzdG9yZWQgYmxvY2sgbGVuZ3RocwAlcyVzJXMAYnVmZmVyIGVycm9yAE5vIGVycm9yAHN0cmVhbSBlcnJvcgBUZWxsIGVycm9yAEludGVybmFsIGVycm9yAFNlZWsgZXJyb3IAV3JpdGUgZXJyb3IAZmlsZSBlcnJvcgBSZWFkIGVycm9yAFpsaWIgZXJyb3IAZGF0YSBlcnJvcgBDUkMgZXJyb3IAaW5jb21wYXRpYmxlIHZlcnNpb24AaW52YWxpZCBjb2RlIC0tIG1pc3NpbmcgZW5kLW9mLWJsb2NrAGluY29ycmVjdCBoZWFkZXIgY2hlY2sAaW5jb3JyZWN0IGxlbmd0aCBjaGVjawBpbmNvcnJlY3QgZGF0YSBjaGVjawBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjawBoZWFkZXIgY3JjIG1pc21hdGNoADEuMi4xMy56bGliLW5nAGludmFsaWQgd2luZG93IHNpemUAUmVhZC1vbmx5IGFyY2hpdmUATm90IGEgemlwIGFyY2hpdmUAUmVzb3VyY2Ugc3RpbGwgaW4gdXNlAE1hbGxvYyBmYWlsdXJlAGludmFsaWQgYmxvY2sgdHlwZQBGYWlsdXJlIHRvIGNyZWF0ZSB0ZW1wb3JhcnkgZmlsZQBDYW4ndCBvcGVuIGZpbGUATm8gc3VjaCBmaWxlAFByZW1hdHVyZSBlbmQgb2YgZmlsZQBDYW4ndCByZW1vdmUgZmlsZQBpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUAaW52YWxpZCBkaXN0YW5jZSBjb2RlAHVua25vd24gY29tcHJlc3Npb24gbWV0aG9kAHN0cmVhbSBlbmQAQ29tcHJlc3NlZCBkYXRhIGludmFsaWQATXVsdGktZGlzayB6aXAgYXJjaGl2ZXMgbm90IHN1cHBvcnRl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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("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","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..2ee36e7b981bd --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1,21 @@ +enableScripts: false + +nmHoistingLimits: workspaces + +packageExtensions: + abstract-socket@*: + dependencies: + node-addon-api: 8.0.0 + +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 new file mode 100644 index 0000000000000..a8e3d243407c7 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,1916 @@ +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("//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") +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("filenames.auto.gni") +import("filenames.gni") +import("filenames.hunspell.gni") +import("filenames.libcxx.gni") +import("filenames.libcxxabi.gni") + +declare_args() { + # Emit a build-time V8 code cache for the electron/js2c/* bundles. When + # false an empty stub is compiled and bundles compile from source. + # + # Cross-arch is supported: the generator is built in v8_snapshot_toolchain + # (V8_TARGET_ARCH set to the target) and reads the target's snapshot blob, + # so the cache it emits is keyed to the target's read-only checksum -- the + # same mechanism that makes V8's mksnapshot cross-arch correct. Cross-OS is + # untested and stays off. + electron_generate_js2c_code_cache = host_os == target_os +} + +if (is_mac) { + import("//build/config/mac/rules.gni") + import("//third_party/icu/config.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" ] + } + + pkg_config("libnotify_config") { + packages = [ + "glib-2.0", + "gdk-pixbuf-2.0", + ] + } + + 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") +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") +} + +if (enable_pdf_viewer) { + assert(enable_pdf, "PDF viewer support requires enable_pdf=true") + assert(enable_electron_extensions, + "PDF viewer support requires enable_electron_extensions=true") +} + +if (enable_electron_extensions) { + assert(enable_extensions, + "Chrome extension support requires enable_extensions=true") +} + +config("branding") { + defines = [ + "ELECTRON_PRODUCT_NAME=\"$electron_product_name\"", + "ELECTRON_PROJECT_NAME=\"$electron_project_name\"", + ] +} + +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 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) +# for typescript prompting +npm_action("build_electron_definitions") { + script = "gn-typescript-definitions" + args = [ rebase_path("$target_gen_dir/tsc/typings/electron.d.ts") ] + inputs = auto_filenames.api_docs + [ "yarn.lock" ] + + outputs = [ "$target_gen_dir/tsc/typings/electron.d.ts" ] +} + +webpack_build("electron_browser_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.browser_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.browser.js" + out_file = "$target_gen_dir/js2c/browser_init.js" +} + +webpack_build("electron_renderer_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.renderer_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.renderer.js" + out_file = "$target_gen_dir/js2c/renderer_init.js" +} + +webpack_build("electron_worker_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.worker_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.worker.js" + out_file = "$target_gen_dir/js2c/worker_init.js" +} + +webpack_build("electron_sandboxed_renderer_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.sandbox_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.sandboxed_renderer.js" + out_file = "$target_gen_dir/js2c/sandbox_bundle.js" +} + +webpack_build("electron_isolated_renderer_bundle") { + deps = [ ":build_electron_definitions" ] + + inputs = auto_filenames.isolated_bundle_deps + + config_file = "//electron/build/webpack/webpack.config.isolated_renderer.js" + 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_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/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 + outputs = [ "$root_gen_dir/electron_natives.cc" ] + + script = "build/js2c.py" + 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" + +typescript_build("default_app_js") { + deps = [ ":build_electron_definitions" ] + + sources = filenames.default_app_ts_sources + + output_gen_dir = target_gen_default_app_js + output_dir_name = "default_app" + tsconfig = "tsconfig.default_app.json" +} + +copy("default_app_static") { + sources = filenames.default_app_static_sources + outputs = [ "$target_gen_default_app_js/{{source}}" ] +} + +copy("default_app_octicon_deps") { + sources = filenames.default_app_octicon_sources + outputs = [ "$target_gen_default_app_js/electron/default_app/octicon/{{source_file_part}}" ] +} + +asar("default_app_asar") { + deps = [ + ":default_app_js", + ":default_app_octicon_deps", + ":default_app_static", + ] + + root = "$target_gen_default_app_js/electron/default_app" + sources = get_target_outputs(":default_app_js") + + get_target_outputs(":default_app_static") + + get_target_outputs(":default_app_octicon_deps") + outputs = [ "$root_out_dir/resources/default_app.asar" ] +} + +grit("resources") { + 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" ] + + output_dir = "$target_gen_dir" +} + +copy("copy_shell_devtools_discovery_page") { + sources = [ "//content/shell/resources/shell_devtools_discovery_page.html" ] + outputs = [ "$target_gen_dir/shell_devtools_discovery_page.html" ] +} + +npm_action("electron_version_args") { + script = "generate-version-json" + + outputs = [ "$target_gen_dir/electron_version.args" ] + + args = rebase_path(outputs) + [ "$electron_version" ] + + inputs = [ "script/generate-version-json.js" ] +} + +templated_file("electron_version_header") { + deps = [ ":electron_version_args" ] + + template = "build/templates/electron_version.tmpl" + output = "$target_gen_dir/electron_version.h" + + args_files = get_target_outputs(":electron_version_args") +} + +templated_file("electron_win_rc") { + deps = [ ":electron_version_args" ] + + template = "build/templates/electron_rc.tmpl" + output = "$target_gen_dir/win-resources/electron.rc" + + args_files = get_target_outputs(":electron_version_args") +} + +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_file") { + deps = [ ":electron_version_args" ] + + 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.json5" ] + + outputs = [ + "$target_gen_dir/fuses.h", + "$target_gen_dir/fuses.cc", + ] + + 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", + "//third_party/electron_node:node_external_config", + ] + + public_configs = [ + ":branding", + ":electron_lib_config", + ] + + deps = [ + ":electron_fuses", + ":electron_generate_node_defines", + ":electron_js2c", + ":electron_version_header", + ":resources", + "buildflags", + "chromium_src:chrome", + "chromium_src:chrome_spellchecker", + "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/gpu", + "//content/public/renderer", + "//content/public/utility", + "//device/bluetooth", + "//device/bluetooth/public/cpp", + "//device/fido", + "//device/fido/strings", + "//gin", + "//gpu/ipc/client", + "//media/capture/mojom:video_capture", + "//media/mojo/mojom", + "//media/mojo/mojom:web_speech_recognition", + "//net:extras", + "//net:net_resources", + "//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: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 && + current_toolchain == default_toolchain) { + deps += [ ":mksnapshot_checksum_gen" ] + } + + public_deps = [ + "//base", + "//base:i18n", + "//content/public/app", + "//ui/base/unowned_user_data", + ] + + include_dirs = [ + ".", + "$target_gen_dir", + + # TODO(nornagon): replace usage of SchemeRegistry by an actually exported + # API of blink, then remove this from the include_dirs. + "//third_party/blink/renderer", + ] + + defines = [ + "BLINK_MOJO_IMPL=1", + "V8_DEPRECATION_WARNINGS", + ] + libs = [] + + if (is_linux) { + defines += [ "GDK_DISABLE_DEPRECATION_WARNINGS" ] + } + + if (!is_mas_build) { + 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 + } + if (is_mac) { + sources += filenames.lib_sources_mac + } + if (is_posix) { + sources += filenames.lib_sources_posix + } + if (is_linux) { + sources += filenames.lib_sources_linux + } + if (!is_mac) { + sources += filenames.lib_sources_views + } + + if (electron_generate_js2c_code_cache) { + sources += [ + "$root_gen_dir/electron_natives_code_cache_browser.cc", + "$root_gen_dir/electron_natives_code_cache_renderer.cc", + "$root_gen_dir/electron_natives_code_cache_sandbox.cc", + "$root_gen_dir/electron_natives_code_cache_utility.cc", + "$root_gen_dir/electron_natives_code_cache_worker.cc", + ] + deps += [ ":run_electron_natives_codecache" ] + } else { + sources += [ "shell/common/node_natives_code_cache_stub.cc" ] + } + + if (is_component_build) { + defines += [ "NODE_SHARED_MODE" ] + } + + if (enable_fake_location_provider) { + sources += [ + "shell/browser/fake_location_provider.cc", + "shell/browser/fake_location_provider.h", + ] + } + + 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", + "//components/remote_cocoa/browser", + "//content/browser:mac_helpers", + "//ui/accelerated_widget_mac", + ] + + if (!is_mas_build) { + deps += [ "//third_party/crashpad/crashpad/client" ] + } + + frameworks = [ + "AuthenticationServices.framework", + "AVFoundation.framework", + "Carbon.framework", + "LocalAuthentication.framework", + "QuartzCore.framework", + "Quartz.framework", + "Security.framework", + "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", + ] + if (is_mas_build) { + sources += [ "shell/browser/api/electron_api_app_mas.mm" ] + sources -= [ "shell/browser/auto_updater_mac.mm" ] + sources -= [ + "shell/app/electron_crash_reporter_client.cc", + "shell/app/electron_crash_reporter_client.h", + "shell/common/crash_keys.cc", + "shell/common/crash_keys.h", + ] + } else { + frameworks += [ + "Squirrel.framework", + "ReactiveObjC.framework", + "Mantle.framework", + ] + + deps += [ + "//third_party/squirrel.mac:reactiveobjc_framework+link", + "//third_party/squirrel.mac:squirrel_framework+link", + ] + + # ReactiveObjC which is used by Squirrel requires using __weak. + cflags_objcc = [ "-fobjc-weak" ] + } + } + 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:gtk_config", + "//ui/linux:display_server_utils", + "//ui/linux:linux_ui", + "//ui/linux:linux_ui_factory", + "//ui/wm", + ] + if (ozone_platform_x11) { + sources += filenames.lib_sources_linux_x11 + public_deps += [ + "//ui/base/x", + "//ui/ozone/platform/x11", + ] + } + configs += [ ":gio_unix" ] + defines += [ + # Disable warnings for g_settings_list_schemas. + "GLIB_DISABLE_DEPRECATION_WARNINGS", + ] + + sources += [ + "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", + "//components/os_crypt/async/browser:dpapi_key_provider", + "//third_party/libxml:xml_writer", + "//ui/wm", + "//ui/wm/public", + ] + public_deps += [ + "//sandbox/win:sandbox", + "//third_party/crashpad/crashpad/handler", + ] + } + + if (enable_plugins) { + sources += [ + "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_printing) { + sources += [ + "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", + ] + deps += [ + "//chrome/services/printing/public/mojom", + "//components/printing/common:mojo_interfaces", + ] + if (is_mac) { + deps += [ "//chrome/services/mac_notifications/public/mojom" ] + } + } + + if (enable_electron_extensions) { + sources += filenames.lib_sources_extensions + deps += [ + "shell/browser/extensions/api:api_registration", + "shell/common/extensions/api", + "shell/common/extensions/api:extensions_features", + "//chrome/browser/resources:component_extension_resources", + "//components/guest_view/common:mojom", + "//components/update_client", + "//components/zoom", + "//extensions/browser", + "//extensions/browser/api:api_provider", + "//extensions/browser/mime_handler", + "//extensions/browser/updater", + "//extensions/common", + "//extensions/common:core_api_provider", + "//extensions/renderer", + ] + } + + if (enable_pdf) { + # Printing depends on some //pdf code, so it needs to be built even if the + # pdf viewer isn't enabled. + deps += [ + "//pdf", + "//pdf:features", + ] + } + 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", + "//components/user_education/webui", + "//pdf", + "//pdf:content_restriction", + ] + sources += [ + "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 (allow_runtime_configurable_key_storage) { + defines += [ "ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE" ] + } +} + +# Build-time host tool emitting V8 code caches for the electron/js2c/* framework +# bundles. Built in v8_snapshot_toolchain (like node_mksnapshot) so it links V8 +# with V8_TARGET_ARCH set to the target and reads the target's snapshot blob -- +# the cache it emits is keyed to the target's read-only checksum and flag hash. +# Cross-OS stays off; see electron_generate_js2c_code_cache. +if (electron_generate_js2c_code_cache) { + if (current_toolchain == v8_snapshot_toolchain) { + executable("electron_natives_codecache") { + # Host build tool, not shipped Chromium code. + configs += [ "//build/config/compiler:no_chromium_code" ] + configs -= [ "//build/config/compiler:chromium_code" ] + include_dirs = [ + ".", + "//", + ] + sources = [ "shell/common/electron_natives_codecache_main.cc" ] + + # node's zstd binding also needs the compression symbols. + deps = [ + "//third_party/electron_node:libnode", + "//third_party/zstd:compress", + ] + } + } + + # One generated cache per process flavor: V8's code-cache key includes + # FlagList::Hash() over non-default flags, which differs per process type. + # The flag deltas below were captured from live processes. + _js2c_cc_flavors = [ + { + name = "sandbox" # sandboxed renderer (no Node env) + flags = "--enable-sharedarraybuffer-per-context" + }, + { + name = "renderer" + flags = "--enable-sharedarraybuffer-per-context --rehash-snapshot " + + "--no-freeze-flags-after-init" + }, + { + name = "browser" + flags = "--rehash-snapshot --no-freeze-flags-after-init" + }, + { + name = "utility" + flags = "--rehash-snapshot --no-freeze-flags-after-init" + }, + { + name = "worker" + flags = "--rehash-snapshot --no-freeze-flags-after-init" + }, + ] + + foreach(_f, _js2c_cc_flavors) { + action("run_electron_natives_codecache_" + _f.name) { + deps = [ + ":electron_natives_codecache($v8_snapshot_toolchain)", + "//tools/v8_context_snapshot", + "//v8:run_mksnapshot_default", + ] + script = "//v8/tools/run.py" + _gen_dir = + get_label_info(":electron_natives_codecache($v8_snapshot_toolchain)", + "root_out_dir") + _out = "$root_gen_dir/electron_natives_code_cache_" + _f.name + ".cc" + outputs = [ _out ] + args = [ + "./" + rebase_path(_gen_dir + "/electron_natives_codecache", + root_build_dir), + rebase_path(_out, root_build_dir), + rebase_path("$root_out_dir/$v8_context_snapshot_filename", + root_build_dir), + _f.name, + _f.flags, + ] + } + } + + group("run_electron_natives_codecache") { + public_deps = [] + foreach(_f, _js2c_cc_flavors) { + public_deps += [ ":run_electron_natives_codecache_" + _f.name ] + } + } +} + +# tools/v8_context_snapshot writes its output to $root_build_dir regardless +# of toolchain, so this is only well-formed in the default toolchain (where +# $root_out_dir == $root_build_dir). It is also only needed there -- only the +# shipped framework reads snapshot_checksum.h. +if (current_toolchain == default_toolchain) { + 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" + copy_data_to_bundle = true + } else { + output_dir = root_out_dir + } +} + +if (is_mac) { + electron_framework_name = "$electron_product_name Framework" + electron_helper_name = "$electron_product_name Helper" + electron_login_helper_name = "$electron_product_name Login Helper" + electron_framework_version = "A" + + mac_xib_bundle_data("electron_xibs") { + sources = [ "shell/common/resources/mac/MainMenu.xib" ] + } + + bundle_data("electron_framework_resources") { + public_deps = [ ":packed_resources" ] + sources = [] + if (icu_use_data_file) { + sources += [ "$root_out_dir/icudtl.dat" ] + public_deps += [ "//third_party/icu:icudata" ] + } + if (v8_use_external_startup_data) { + public_deps += [ "//v8" ] + if (use_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" ] + } + } + outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] + } + + if (!is_component_build && is_component_ffmpeg) { + bundle_data("electron_framework_libraries") { + sources = [] + public_deps = [] + sources += [ "$root_out_dir/libffmpeg.dylib" ] + public_deps += [ "//third_party/ffmpeg" ] + outputs = [ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}" ] + } + } else { + group("electron_framework_libraries") { + } + } + + # 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") { + deps = [ ":electron_angle_binaries" ] + } + + group("electron_swiftshader_library") { + deps = [ ":electron_swiftshader_binaries" ] + } + + bundle_data("electron_crashpad_helper") { + sources = [ "$root_out_dir/chrome_crashpad_handler" ] + + outputs = [ "{{bundle_contents_dir}}/Helpers/{{source_file_part}}" ] + + public_deps = [ "//components/crash/core/app:chrome_crashpad_handler" ] + + 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_sanitizer_runtime" ] + } + } + + mac_framework_bundle("electron_framework") { + output_name = electron_framework_name + framework_version = electron_framework_version + framework_contents = [ + "Resources", + "Libraries", + ] + if (!is_mas_build) { + framework_contents += [ "Helpers" ] + } + public_deps = [ + ":electron_framework_libraries", + ":electron_lib", + ] + deps = [ + ":electron_angle_library", + ":electron_framework_libraries", + ":electron_framework_resources", + ":electron_swiftshader_library", + ":electron_xibs", + "//third_party/electron_node:libnode", + ] + if (!is_mas_build) { + deps += [ ":electron_crashpad_helper" ] + } + info_plist = "shell/common/resources/mac/Info.plist" + + extra_substitutions = [ + "ELECTRON_BUNDLE_ID=$electron_mac_bundle_id.framework", + "ELECTRON_VERSION=$electron_version", + ] + + include_dirs = [ "." ] + sources = filenames.framework_sources + frameworks = [ "IOSurface.framework" ] + + ldflags = [ + "-Wl,-install_name,@rpath/$output_name.framework/$output_name", + "-rpath", + "@loader_path/Libraries", + + # Required for exporting all symbols of libuv. + "-Wl,-force_load,obj/third_party/electron_node/deps/uv/libuv.a", + ] + if (is_component_build) { + ldflags += [ + "-rpath", + "@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") { + mac_app_bundle(target_name) { + assert(defined(invoker.helper_name_suffix)) + + output_name = electron_helper_name + invoker.helper_name_suffix + deps = [ + ":electron_framework+link", + "//electron/build/config:generate_mas_config", + ] + if (!is_mas_build) { + deps += [ "//sandbox/mac:seatbelt" ] + } + defines = [ "HELPER_EXECUTABLE" ] + 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 = + [ "ELECTRON_BUNDLE_ID=$electron_mac_bundle_id.helper" ] + ldflags = [ + "-rpath", + "@executable_path/../../..", + ] + if (is_component_build) { + ldflags += [ + "-rpath", + "@executable_path/../../../../../..", + ] + } + } + } + + # 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] + electron_helper_app("electron_helper_app_${_helper_target}") { + helper_name_suffix = _helper_suffix + } + } + + template("stripped_framework") { + action(target_name) { + assert(defined(invoker.framework)) + + script = "//electron/build/strip_framework.py" + + forward_variables_from(invoker, [ "deps" ]) + inputs = [ "$root_out_dir/" + invoker.framework ] + outputs = [ "$target_out_dir/stripped_frameworks/" + invoker.framework ] + + args = rebase_path(inputs) + rebase_path(outputs) + } + } + + stripped_framework("stripped_mantle_framework") { + framework = "Mantle.framework" + deps = [ "//third_party/squirrel.mac:mantle_framework" ] + } + + stripped_framework("stripped_reactiveobjc_framework") { + framework = "ReactiveObjC.framework" + deps = [ "//third_party/squirrel.mac:reactiveobjc_framework" ] + } + + stripped_framework("stripped_squirrel_framework") { + framework = "Squirrel.framework" + deps = [ "//third_party/squirrel.mac:squirrel_framework" ] + } + + bundle_data("electron_app_framework_bundle_data") { + sources = [ "$root_out_dir/$electron_framework_name.framework" ] + if (!is_mas_build) { + sources += get_target_outputs(":stripped_mantle_framework") + + get_target_outputs(":stripped_reactiveobjc_framework") + + get_target_outputs(":stripped_squirrel_framework") + } + outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ] + public_deps = [ + ":electron_framework+link", + ":stripped_mantle_framework", + ":stripped_reactiveobjc_framework", + ":stripped_squirrel_framework", + ] + + 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]}" ] + } + } + + mac_app_bundle("electron_login_helper") { + output_name = electron_login_helper_name + sources = filenames.login_helper_sources + include_dirs = [ "." ] + frameworks = [ "AppKit.framework" ] + info_plist = "shell/app/resources/mac/loginhelper-Info.plist" + extra_substitutions = + [ "ELECTRON_BUNDLE_ID=$electron_mac_bundle_id.loginhelper" ] + } + + bundle_data("electron_login_helper_app") { + public_deps = [ ":electron_login_helper" ] + sources = [ "$root_out_dir/$electron_login_helper_name.app" ] + outputs = + [ "{{bundle_contents_dir}}/Library/LoginItems/{{source_file_part}}" ] + } + + action("electron_app_lproj_dirs") { + 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_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" ] + public_deps = [ ":electron_app_lproj_dirs" ] + } + } + group("electron_app_strings_bundle_data") { + public_deps = [] + foreach(locale, locales_as_apple_outputs) { + public_deps += [ ":electron_app_strings_${locale}_bundle_data" ] + } + } + + bundle_data("electron_app_resources") { + public_deps = [ + ":default_app_asar", + ":electron_app_strings_bundle_data", + ] + sources = [ + "$root_out_dir/resources/default_app.asar", + "shell/browser/resources/mac/electron.icns", + ] + 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 = [ + "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_target = ":electron_app_plist" + extra_substitutions = [ + "ELECTRON_BUNDLE_ID=$electron_mac_bundle_id", + "ELECTRON_VERSION=$electron_version", + ] + ldflags = [ + "-rpath", + "@executable_path/../Frameworks", + ] + } + + if (enable_dsyms) { + extract_symbols("electron_framework_syms") { + binary = "$root_out_dir/$electron_framework_name.framework/Versions/$electron_framework_version/$electron_framework_name" + symbol_dir = "$root_out_dir/breakpad_symbols" + dsym_file = "$root_out_dir/$electron_framework_name.dSYM/Contents/Resources/DWARF/$electron_framework_name" + deps = [ ":electron_framework" ] + } + + foreach(helper_params, electron_mac_helpers) { + _helper_target = helper_params[0] + _helper_bundle_id = helper_params[1] + _helper_suffix = helper_params[2] + extract_symbols("electron_helper_syms_${_helper_target}") { + binary = "$root_out_dir/$electron_helper_name${_helper_suffix}.app/Contents/MacOS/$electron_helper_name${_helper_suffix}" + symbol_dir = "$root_out_dir/breakpad_symbols" + dsym_file = "$root_out_dir/$electron_helper_name${_helper_suffix}.dSYM/Contents/Resources/DWARF/$electron_helper_name${_helper_suffix}" + deps = [ ":electron_helper_app_${_helper_target}" ] + } + } + + extract_symbols("electron_app_syms") { + binary = "$root_out_dir/$electron_product_name.app/Contents/MacOS/$electron_product_name" + symbol_dir = "$root_out_dir/breakpad_symbols" + dsym_file = "$root_out_dir/$electron_product_name.dSYM/Contents/Resources/DWARF/$electron_product_name" + deps = [ ":electron_app" ] + } + + extract_symbols("egl_syms") { + binary = "$root_out_dir/libEGL.dylib" + symbol_dir = "$root_out_dir/breakpad_symbols" + dsym_file = "$root_out_dir/libEGL.dylib.dSYM/Contents/Resources/DWARF/libEGL.dylib" + deps = [ "//third_party/angle:libEGL" ] + } + + extract_symbols("gles_syms") { + binary = "$root_out_dir/libGLESv2.dylib" + symbol_dir = "$root_out_dir/breakpad_symbols" + dsym_file = "$root_out_dir/libGLESv2.dylib.dSYM/Contents/Resources/DWARF/libGLESv2.dylib" + deps = [ "//third_party/angle:libGLESv2" ] + } + + extract_symbols("crashpad_handler_syms") { + binary = "$root_out_dir/chrome_crashpad_handler" + symbol_dir = "$root_out_dir/breakpad_symbols" + dsym_file = "$root_out_dir/chrome_crashpad_handler.dSYM/Contents/Resources/DWARF/chrome_crashpad_handler" + deps = [ "//components/crash/core/app:chrome_crashpad_handler" ] + } + + group("electron_symbols") { + deps = [ + ":egl_syms", + ":electron_app_syms", + ":electron_framework_syms", + ":gles_syms", + ] + + if (!is_mas_build) { + deps += [ ":crashpad_handler_syms" ] + } + + foreach(helper_params, electron_mac_helpers) { + _helper_target = helper_params[0] + deps += [ ":electron_helper_syms_${_helper_target}" ] + } + } + } else { + group("electron_symbols") { + } + } +} else { + windows_manifest("electron_app_manifest") { + sources = [ + "shell/browser/resources/win/disable_window_filtering.manifest", + "shell/browser/resources/win/dpi_aware.manifest", + as_invoker_manifest, + common_controls_manifest, + default_compatibility_manifest, + ] + } + + executable("electron_app") { + output_name = electron_project_name + 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, platform_pak_locales) { + data += [ "$root_out_dir/locales/$locale.pak" ] + } + + if (!is_mac) { + data += [ "$root_out_dir/resources/default_app.asar" ] + } + + if (use_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 += [ + "$target_gen_dir/win-resources/electron.rc", + "shell/browser/resources/win/resource.h", + ] + + deps += [ + "//chrome/app:exit_code_watcher", + "//components/crash/core/app:run_as_crashpad_handler", + ] + + ldflags = [ "/DELAYLOAD:ffmpeg.dll" ] + + libs = [ + "comctl32.lib", + "uiautomationcore.lib", + "wtsapi32.lib", + ] + + configs -= [ "//build/config/win:console" ] + configs += [ + "//build/config/win:windowed", + "//build/config/win:delayloads", + ] + + 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 + # executable names which it will recognise as node. This module definition + # file claims that the electron executable is in fact named "node.exe", + # which is one of the executable names that node-gyp recognizes. + # See https://github.com/nodejs/node-gyp/commit/52ceec3a6d15de3a8f385f43dbe5ecf5456ad07a + ldflags += [ "/DEF:" + rebase_path("build/electron.def", root_build_dir) ] + inputs = [ + "shell/browser/resources/win/electron.ico", + "build/electron.def", + ] + } + if (is_linux) { + ldflags = [ + "-pie", + + # Required for exporting all symbols of libuv. + "-Wl,--whole-archive", + "obj/third_party/electron_node/deps/uv/libuv.a", + "-Wl,--no-whole-archive", + ] + + if (!is_component_build && is_component_ffmpeg) { + configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ] + } + + if (is_linux) { + deps += [ "//sandbox/linux:chrome_sandbox" ] + } + } + } + + if (is_official_build) { + if (is_linux) { + _target_executable_suffix = "" + _target_shared_library_suffix = ".so" + } else if (is_win) { + _target_executable_suffix = ".exe" + _target_shared_library_suffix = ".dll" + } + + extract_symbols("electron_app_symbols") { + binary = "$root_out_dir/$electron_project_name$_target_executable_suffix" + symbol_dir = "$root_out_dir/breakpad_symbols" + deps = [ ":electron_app" ] + } + + extract_symbols("egl_symbols") { + binary = "$root_out_dir/libEGL$_target_shared_library_suffix" + symbol_dir = "$root_out_dir/breakpad_symbols" + deps = [ "//third_party/angle:libEGL" ] + } + + extract_symbols("gles_symbols") { + binary = "$root_out_dir/libGLESv2$_target_shared_library_suffix" + symbol_dir = "$root_out_dir/breakpad_symbols" + deps = [ "//third_party/angle:libGLESv2" ] + } + + group("electron_symbols") { + deps = [ + ":egl_symbols", + ":electron_app_symbols", + ":gles_symbols", + ] + } + } +} + +template("dist_zip") { + _runtime_deps_target = "${target_name}__deps" + _runtime_deps_file = + "$root_out_dir/gen.runtime/" + get_label_info(target_name, "dir") + "/" + + get_label_info(target_name, "name") + ".runtime_deps" + + group(_runtime_deps_target) { + forward_variables_from(invoker, + [ + "deps", + "data_deps", + "data", + "testonly", + ]) + write_runtime_deps = _runtime_deps_file + } + + action(target_name) { + script = "//electron/build/zip.py" + deps = [ ":$_runtime_deps_target" ] + forward_variables_from(invoker, + [ + "outputs", + "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", + ] + } +} + +copy("electron_license") { + sources = [ "LICENSE" ] + outputs = [ "$root_build_dir/{{source_file_part}}" ] +} +copy("chromium_licenses") { + deps = [ "//components/resources:about_credits" ] + sources = [ "$root_gen_dir/components/resources/about_credits.html" ] + outputs = [ "$root_build_dir/LICENSES.chromium.html" ] +} + +group("licenses") { + data_deps = [ + ":chromium_licenses", + ":electron_license", + ] +} + +dist_zip("electron_dist_zip") { + data_deps = [ + ":electron_app", + ":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:chromedriver_server", + "//electron/buildflags", +] + +group("electron_chromedriver") { + testonly = true + public_deps = electron_chromedriver_deps +} + +dist_zip("electron_chromedriver_zip") { + testonly = true + data_deps = electron_chromedriver_deps + deps = data_deps + outputs = [ "$root_build_dir/chromedriver.zip" ] +} + +mksnapshot_deps = [ + ":licenses", + "//v8:mksnapshot($v8_snapshot_toolchain)", +] + +if (use_v8_context_snapshot) { + mksnapshot_deps += [ "//tools/v8_context_snapshot:v8_context_snapshot_generator($v8_snapshot_toolchain)" ] +} + +group("electron_mksnapshot") { + public_deps = mksnapshot_deps +} + +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" ] +} + +copy("hunspell_dictionaries") { + sources = hunspell_dictionaries + hunspell_licenses + outputs = [ "$target_gen_dir/electron_hunspell/{{source_file_part}}" ] +} + +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 e4d4c531e5a30..819fb406e6ef1 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,46 +1,135 @@ -# Contributor Covenant Code of Conduct +# Code of Conduct -## Our Pledge +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: -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. +* [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) -## Our Standards +## Contributor Covenant Code of Conduct -Examples of behavior that contributes to creating a positive environment include: +### Our Pledge -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. -Examples of unacceptable behavior by participants include: +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks +### Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +### Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +### Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +### Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[coc@electronjs.org](mailto:coc@electronjs.org). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +### Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +#### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +#### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. -## Our Responsibilities +#### 3. Temporary Ban -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. -## Scope +#### 4. Permanent Ban -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. -## Enforcement +**Consequence**: A permanent ban from any sort of public interaction within +the community. -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [electron@github.com](mailto:electron@github.com). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +### Attribution -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. +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. -## Attribution +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion). -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +[homepage]: https://www.contributor-covenant.org -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING-ko.md b/CONTRIBUTING-ko.md deleted file mode 100644 index 480c2f73e47e0..0000000000000 --- a/CONTRIBUTING-ko.md +++ /dev/null @@ -1,80 +0,0 @@ -# Electron에 기여하기 - -:+1::tada: 먼저, 기여에 관심을 가져주셔서 감사합니다! :tada::+1: - -이 프로젝트는 기여자 규약인 [행동강령](CODE_OF_CONDUCT.md)을 준수합니다. 따라서 이 -프로젝트의 개발에 참여하려면 이 규약을 지켜야 합니다. 받아들일 수 없는 행위를 발견했을 -경우 atom@github.com로 보고하세요. - -다음 항목들은 Electron에 기여하는 가이드라인을 제시합니다. -참고로 이 항목들은 그저 가이드라인에 불과하며 규칙이 아닙니다. 따라서 스스로의 적절한 -판단에 따라 이 문서의 변경을 제안할 수 있으며 변경시 pull request를 넣으면 됩니다. - -## 이슈 제출 - -* [여기](https://github.com/electron/electron/issues/new)에서 새로운 이슈를 만들 수 -있습니다. 하지만 이슈를 작성하기 전에 아래의 항목들을 숙지하고 가능한한 이슈 보고에 -대해 최대한 많은 정보와 자세한 설명을 포함해야 합니다. 가능하다면 다음 항목을 포함해야 -합니다: - * 사용하고 있는 Electron의 버전 - * 현재 사용중인 운영체제 - * 가능하다면 무엇을 하려고 했고, 어떤 결과를 예측했으며, 어떤 것이 예측된대로 - 작동하지 않았는지에 대해 서술해야 합니다. -* 추가로 다음 사항을 준수하면 이슈를 해결하는데 큰 도움이 됩니다: - * 스크린샷 또는 GIF 애니메이션 이미지들 - * 터미널에 출력된 에러의 내용 또는 개발자 도구, 알림창에 뜬 내용 - * [Cursory search](https://github.com/electron/electron/issues?utf8=✓&q=is%3Aissue+)를 - 통해 이미 비슷한 내용의 이슈가 등록되어있는지 확인 - -## Pull Request 하기 - -* 가능한한 스크린샷과 GIF 애니메이션 이미지를 pull request에 추가 -* JavaScript, C++과 Python등 -[참조 문서에 정의된 코딩스타일](/docs-translations/ko-KR/development/coding-style.md)을 -준수 -* [문서 스타일 가이드](/docs-translations/ko-KR/styleguide.md)에 따라 문서를 -[Markdown](https://daringfireball.net/projects/markdown) 형식으로 작성. -* 짧은, 현재 시제 커밋 메시지 사용. [커밋 메시지 스타일 가이드](#git-커밋-메시지)를 -참고하세요 - -## 스타일 가이드 - -### 공통 코드 - -* 파일 마지막에 공백 라인(newline) 추가 -* 다음 순서에 맞춰서 require 코드 작성: - * Node 빌트인 모듈 (`path` 같은) - * Electron 모듈 (`ipc`, `app` 같은) - * 로컬 모듈 (상대 경로상에 있는) -* 다음 순서에 맞춰서 클래스 속성 지정: - * 클래스 메서드와 속성 (메서드는 `@`로 시작) - * 인스턴스 메서드와 속성 -* 플랫폼 종속적인 코드 자제: - * 파일 이름 결합시 `path.join()`을 사용. - * 임시 디렉터리가 필요할 땐 `/tmp` 대신 `os.tmpdir()`을 통해 접근. -* 명시적인 함수 종료가 필요할 땐 `return` 만 사용. - * `return null`, `return undefined`, `null`, 또는 `undefined` 사용 X - -### Git 커밋 메시지 - -* 현재 시제 사용 ("Added feature" 대신 "Add feature" 사용) -* 명령법(imperative mood) 사용 ("Moves cursor to..." 대신 "Move cursor to..." 사용) -* 첫 줄은 72자에 맞추거나 그 보다 적게 제한 -* 자유롭게 필요에 따라 이슈나 PR링크를 참조 -* 단순한 문서 변경일 경우 `[ci skip]`을 커밋 메시지에 추가 -* 커밋 메시지의 도입부에 의미있는 이모티콘 사용: - * :art: `:art:` 코드의 포맷이나 구조를 개선(추가)했을 때 - * :racehorse: `:racehorse:` 성능을 개선했을 때 - * :non-potable_water: `:non-potable_water:` 메모리 누수를 연결했을 때 - * :memo: `:memo:` 문서를 작성했을 때 - * :penguin: `:penguin:` Linux에 대한 패치를 했을 때 - * :apple: `:apple:` macOS에 대한 패치를 했을 때 - * :checkered_flag: `:checkered_flag:` Windows에 대한 패치를 했을 때 - * :bug: `:bug:` 버그를 고쳤을 때 - * :fire: `:fire:` 코드 또는 파일을 삭제했을 때 - * :green_heart: `:green_heart:` CI 빌드를 고쳤을 때 - * :white_check_mark: `:white_check_mark:` 테스트를 추가했을 때 - * :lock: `:lock:` 보안 문제를 해결했을 때 - * :arrow_up: `:arrow_up:` 종속성 라이브러리를 업데이트 했을 때 - * :arrow_down: `:arrow_down:` 종속성 라이브러리를 다운그레이드 했을 때 - * :shirt: `:shirt:` linter(코드 검사기)의 경고를 제거했을 때 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 736f0b22ef7d4..7199e7b0caebd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,74 +4,79 @@ This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable -behavior to atom@github.com. +behavior to coc@electronjs.org. The following is a set of guidelines for contributing to Electron. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. -## Submitting Issues - -* You can create an issue [here](https://github.com/electron/electron/issues/new), -but before doing that please read the notes below and include as many details as -possible with your report. If you can, please include: - * The version of Electron you are using - * The operating system you are using - * If applicable, what you were doing when the issue arose and what you - expected to happen -* Other things that will help resolve your issue: - * Screenshots and animated GIFs - * Error output that appears in your terminal, dev tools or as an alert - * Perform a [cursory search](https://github.com/electron/electron/issues?utf8=✓&q=is%3Aissue+) - to see if a similar issue has already been submitted - -## Submitting Pull Requests - -* Include screenshots and animated GIFs in your pull request whenever possible. -* Follow the JavaScript, C++, and Python [coding style defined in docs](/docs/development/coding-style.md). -* Write documentation in [Markdown](https://daringfireball.net/projects/markdown). - See the [Documentation Styleguide](/docs/styleguide.md). -* Use short, present tense commit messages. See [Commit Message Styleguide](#git-commit-messages). - -## Styleguides - -### General Code - -* End files with a newline. -* Place requires in the following order: - * Built in Node Modules (such as `path`) - * Built in Electron Modules (such as `ipc`, `app`) - * Local Modules (using relative paths) -* Place class properties in the following order: - * Class methods and properties (methods starting with a `@`) - * Instance methods and properties -* Avoid platform-dependent code: - * Use `path.join()` to concatenate filenames. - * Use `os.tmpdir()` rather than `/tmp` when you need to reference the - temporary directory. -* Using a plain `return` when returning explicitly at the end of a function. - * Not `return null`, `return undefined`, `null`, or `undefined` - -### Git Commit Messages - -* Use the present tense ("Add feature" not "Added feature") -* Use the imperative mood ("Move cursor to..." not "Moves cursor to...") -* Limit the first line to 72 characters or less -* Reference issues and pull requests liberally -* When only changing documentation, include `[ci skip]` in the commit description -* Consider starting the commit message with an applicable emoji: - * :art: `:art:` when improving the format/structure of the code - * :racehorse: `:racehorse:` when improving performance - * :non-potable_water: `:non-potable_water:` when plugging memory leaks - * :memo: `:memo:` when writing docs - * :penguin: `:penguin:` when fixing something on Linux - * :apple: `:apple:` when fixing something on macOS - * :checkered_flag: `:checkered_flag:` when fixing something on Windows - * :bug: `:bug:` when fixing a bug - * :fire: `:fire:` when removing code or files - * :green_heart: `:green_heart:` when fixing the CI build - * :white_check_mark: `:white_check_mark:` when adding tests - * :lock: `:lock:` when dealing with security - * :arrow_up: `:arrow_up:` when upgrading dependencies - * :arrow_down: `:arrow_down:` when downgrading dependencies - * :shirt: `:shirt:` when removing linter warnings +## [Issues](https://electronjs.org/docs/development/issues) + +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) +* [Submitting a Bug Report](https://electronjs.org/docs/development/issues#submitting-a-bug-report) +* [Triaging a Bug Report](https://electronjs.org/docs/development/issues#triaging-a-bug-report) +* [Resolving a Bug Report](https://electronjs.org/docs/development/issues#resolving-a-bug-report) + +### 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 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. +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. +Having the original text _as well as_ the translation can help mitigate translation errors. + +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/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) + +Pull Requests are the way concrete changes are made to the code, documentation, +dependencies, and tools contained in the `electron/electron` repository. + +* [Setting up your local environment](https://electronjs.org/docs/development/pull-requests#setting-up-your-local-environment) + * [Step 1: Fork](https://electronjs.org/docs/development/pull-requests#step-1-fork) + * [Step 2: Build](https://electronjs.org/docs/development/pull-requests#step-2-build) + * [Step 3: Branch](https://electronjs.org/docs/development/pull-requests#step-3-branch) +* [Making Changes](https://electronjs.org/docs/development/pull-requests#making-changes) + * [Step 4: Code](https://electronjs.org/docs/development/pull-requests#step-4-code) + * [Step 5: Commit](https://electronjs.org/docs/development/pull-requests#step-5-commit) + * [Commit message guidelines](https://electronjs.org/docs/development/pull-requests#commit-message-guidelines) + * [Step 6: Rebase](https://electronjs.org/docs/development/pull-requests#step-6-rebase) + * [Step 7: Test](https://electronjs.org/docs/development/pull-requests#step-7-test) + * [Step 8: Push](https://electronjs.org/docs/development/pull-requests#step-8-push) + * [Step 9: Opening the Pull Request](https://electronjs.org/docs/development/pull-requests#step-9-opening-the-pull-request) + * [Step 10: Discuss and Update](https://electronjs.org/docs/development/pull-requests#step-10-discuss-and-update) + * [Approval and Request Changes Workflow](https://electronjs.org/docs/development/pull-requests#approval-and-request-changes-workflow) + * [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. + +## Further Reading + +For more in-depth guides on developing Electron, see +[/docs/development](/docs/development/README.md). diff --git a/DEPS b/DEPS new file mode 100644 index 0000000000000..515676827b4bc --- /dev/null +++ b/DEPS @@ -0,0 +1,210 @@ +gclient_gn_args_from = 'src' + +vars = { + 'chromium_version': + '150.0.7849.0', + 'node_version': + 'v24.15.0', + 'nan_version': + '675cefebca42410733da8a454c8d9391fcebfbc2', + 'squirrel.mac_version': + '8d808803bc89ec0e2aa1450474856dfee3b00c6b', + 'reactiveobjc_version': + '74ab5baccc6f7202c8ac69a8d1e152c29dc1ea76', + 'mantle_version': + '2a8e2123a3931038179ee06105c9e6ec336b12ea', + 'engflow_reclient_configs_version': + '955335c30a752e9ef7bff375baab5e0819b6c00d', + + 'pyyaml_version': '3.12', + + 'chromium_git': 'https://chromium.googlesource.com', + 'electron_git': 'https://github.com/electron', + 'nodejs_git': 'https://github.com/nodejs', + 'yaml_git': 'https://github.com/yaml', + 'squirrel_git': 'https://github.com/Squirrel', + '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, + + # To use an mtime cache for patched files to speed up builds. + 'use_mtime_cache': True, + + # To allow in-house builds to checkout those manually. + 'checkout_chromium': True, + 'checkout_node': True, + 'checkout_nan': True, + 'checkout_pgo_profiles': True, + + # It's only needed to parse the native tests configurations. + 'checkout_pyyaml': 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, + + 'checkout_nacl': + False, + 'checkout_openxr': + False, + 'build_with_chromium': + True, + 'checkout_android': + False, + 'checkout_android_native_support': + False, + 'checkout_clang_tidy': + True, +} + +deps = { + 'src': { + 'url': (Var("chromium_git")) + '/chromium/src.git@' + (Var("chromium_version")), + 'condition': 'checkout_chromium and process_deps', + }, + 'src/third_party/nan': { + 'url': (Var("nodejs_git")) + '/nan.git@' + (Var("nan_version")), + 'condition': 'checkout_nan and process_deps', + }, + 'src/third_party/electron_node': { + 'url': (Var("nodejs_git")) + '/node.git@' + (Var("node_version")), + 'condition': 'checkout_node and process_deps', + }, + 'src/third_party/pyyaml': { + 'url': (Var("yaml_git")) + '/pyyaml.git@' + (Var("pyyaml_version")), + 'condition': 'checkout_pyyaml 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': Var("reactiveobjc_git") + '/ReactiveObjC.git@' + Var("reactiveobjc_version"), + 'condition': 'process_deps' + }, + 'src/third_party/squirrel.mac/vendor/Mantle': { + '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' + } +} + +pre_deps_hooks = [ + { + 'name': 'generate_mtime_cache', + 'condition': '(checkout_chromium and apply_patches and use_mtime_cache) and process_deps', + 'pattern': 'src/electron', + 'action': [ + 'python3', + 'src/electron/script/patches-mtime-cache.py', + 'generate', + '--cache-file', + 'src/electron/patches/mtime-cache.json', + '--patches-config', + 'src/electron/patches/config.json', + ], + }, +] + +hooks = [ + { + 'name': 'patch_chromium', + 'condition': '(checkout_chromium and apply_patches) and process_deps', + 'pattern': 'src/electron', + 'action': [ + 'python3', + 'src/electron/script/apply_all_patches.py', + 'src/electron/patches/config.json', + ], + }, + { + 'name': 'apply_mtime_cache', + 'condition': '(checkout_chromium and apply_patches and use_mtime_cache) and process_deps', + 'pattern': 'src/electron', + 'action': [ + 'python3', + 'src/electron/script/patches-mtime-cache.py', + 'apply', + '--cache-file', + 'src/electron/patches/mtime-cache.json', + ], + }, + { + '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(["node", ".yarn/releases/yarn-4.12.0.cjs", "install", "--immutable"]);', + ], + }, + { + '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', +] diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index a78e30d8620be..0000000000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,2 +0,0 @@ -* Electron version: -* Operating system: diff --git a/LICENSE b/LICENSE index 4d231b4563bb6..536d54efc3fd3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2014 GitHub Inc. +Copyright (c) Electron contributors +Copyright (c) 2013-2020 GitHub Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README-ko.md b/README-ko.md deleted file mode 100644 index 79cc716587b09..0000000000000 --- a/README-ko.md +++ /dev/null @@ -1,81 +0,0 @@ -[![Electron Logo](http://electron.atom.io/images/electron-logo.svg)](http://electron.atom.io/) - -[![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/kvxe4byi7jcxbe26/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/electron) -[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron#info=devDependencies) -[![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) - -### [Electron](https://github.com/electron/electron/) 한국어 참조 문서 - -Electron 프레임워크는 JavaScript, HTML 그리고 CSS를 사용하여 -Cross-Platform 데스크톱 애플리케이션을 개발할 수 있도록 해주는 프레임워크입니다. -[Node.js](https://nodejs.org/)와 [Chromium](http://www.chromium.org)을 기반으로 -만들어졌으며 [Atom Editor](https://github.com/atom/atom)에 사용되고 있습니다. -더 많은 애플리케이션은 [이곳](http://electron.atom.io/apps)에서 확인하세요. - -Electron에 대한 중요한 알림을 받고 싶다면 Twitter에서 -[@ElectronJS](https://twitter.com/electronjs)를 팔로우 하세요. - -이 프로젝트는 기여자 규약인 [행동강령](CODE_OF_CONDUCT.md)을 준수합니다. 따라서 이 -프로젝트의 개발에 참여하려면 이 규약을 지켜야 합니다. 받아들일 수 없는 행위를 발견했을 -경우 electron@github.com로 보고하세요. - -## 다운로드 - -Linux, Windows, macOS 용으로 미리 빌드된 Electron 바이너리와 디버그 심볼이 준비되어 -있습니다. [releases](https://github.com/electron/electron/releases) 페이지에서 -받아 볼 수 있습니다. - -또한 [`npm`](https://docs.npmjs.com/)을 통해 미리 빌드된 Electron 바이너리를 설치할 -수도 있습니다: - -```sh -# $PATH에 `electron` 커맨드를 등록하고 전역에 설치합니다. -npm install electron-prebuilt -g - -# 개발 의존성 모듈 형태로 설치합니다. -npm install electron-prebuilt --save-dev -``` - -### 미러 - -- [China](https://npm.taobao.org/mirrors/electron) - -## 참조 문서 - -[Docs](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/README.md)에 -개발 지침과 API 레퍼런스가 있습니다. Electron을 빌드 하는 방법과 프로젝트에 기여하는법 -또한 문서에 포함되어 있으니 참고하시기 바랍니다. - -## 참조 문서 (번역) - -- [브라질 포르투갈어](https://github.com/electron/electron/tree/master/docs-translations/pt-BR) -- [한국어](https://github.com/electron/electron/tree/master/docs-translations/ko-KR) -- [일본어](https://github.com/electron/electron/tree/master/docs-translations/jp) -- [스페인어](https://github.com/electron/electron/tree/master/docs-translations/es) -- [중국어 간체](https://github.com/electron/electron/tree/master/docs-translations/zh-CN) -- [중국어 번체](https://github.com/electron/electron/tree/master/docs-translations/zh-TW) -- [터키어](https://github.com/electron/electron/tree/master/docs-translations/tr-TR) -- [우크라이나어](https://github.com/electron/electron/tree/master/docs-translations/uk-UA) -- [러시아어](https://github.com/electron/electron/tree/master/docs-translations/ru-RU) -- [프랑스어](https://github.com/electron/electron/tree/master/docs-translations/fr-FR) - -## 시작하기 - -[`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) -저장소를 클론하여 Electron을 간단히 접해볼 수 있습니다. - -## 커뮤니티 - -다음 링크를 통해 커뮤니티에 질문을 올리거나 토론을 나눌 수 있습니다: - -- Atom 포럼의 [`electron`](http://discuss.atom.io/c/electron) 카테고리 -- Freenode 채팅의 `#atom-shell` 채널 -- Slack의 [`Atom`](http://atom-slack.herokuapp.com/) 채널 -- [`electron-br`](https://electron-br.slack.com) *(브라질)* 커뮤니티 -- [`electron-kr`](http://www.meetup.com/electron-kr/) *(한국)* 커뮤니티 -- [`electron-jp`](https://electron-jp-slackin.herokuapp.com/) *(일본)* 커뮤니티 -- [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(터키)* 커뮤니티 - -[awesome-electron](https://github.com/sindresorhus/awesome-electron) 프로젝트에 -커뮤니티가 운영중인 유용한 예시 애플리케이션과 도구, 리소스가 있으니 참고하기 바랍니다. diff --git a/README.md b/README.md index 2726e0778972c..cf69aaa75182d 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,102 @@ -[![Electron Logo](http://electron.atom.io/images/electron-logo.svg)](http://electron.atom.io/) +[![Electron Logo](https://electronjs.org/images/electron-logo.svg)](https://electronjs.org) -[![Travis Build Status](https://travis-ci.org/electron/electron.svg?branch=master)](https://travis-ci.org/electron/electron) -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/kvxe4byi7jcxbe26/branch/master?svg=true)](https://ci.appveyor.com/project/Atom/electron) -[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron#info=devDependencies) -[![Join the Electron Community on Slack](http://atom-slack.herokuapp.com/badge.svg)](http://atom-slack.herokuapp.com/) +[![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 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](http://www.chromium.org) and is used by the [Atom -editor](https://github.com/atom/atom) and many other [apps](http://electron.atom.io/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](CODE_OF_CONDUCT.md). +This project adheres to the Contributor Covenant +[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 electron@github.com. - -## Downloads +behavior to [coc@electronjs.org](mailto:coc@electronjs.org). -Prebuilt binaries and debug symbols of Electron for Linux, Windows and macOS can -be found on the [releases](https://github.com/electron/electron/releases) page. +## Installation -You can also use [`npm`](https://docs.npmjs.com/) to install prebuilt electron -binaries: +To install prebuilt Electron binaries, use [`npm`](https://docs.npmjs.com/). +The preferred method is to install Electron as a development dependency in your +app: ```sh -# Install the `electron` command globally in your $PATH -npm install electron-prebuilt -g +npm install electron --save-dev +``` + +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). + +## Platform support + +Each Electron release provides binaries for macOS, Windows, and Linux. + +* 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. + +## Resources for learning Electron -# Install as a development dependency -npm install electron-prebuilt --save-dev +* [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 + +Most people use Electron from the command line, but if you require `electron` inside +your **Node app** (not your Electron app) it will return the file path to the +binary. Use this to spawn Electron from Node scripts: + +```javascript +const electron = require('electron') +const proc = require('node:child_process') + +// will print something similar to /Users/maf/.../Electron +console.log(electron) + +// spawn Electron +const child = proc.spawn(electron) ``` ### Mirrors -- [China](https://npm.taobao.org/mirrors/electron) +* [China](https://npmmirror.com/mirrors/electron/) -## Documentation +See the [Advanced Installation Instructions](https://www.electronjs.org/docs/latest/tutorial/installation#mirror) to learn how to use a custom mirror. -Guides and the API reference are located in the -[docs](https://github.com/electron/electron/tree/master/docs) directory. It also -contains documents describing how to build and contribute to Electron. +## Documentation translations -## Documentation Translations +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. -- [Brazilian Portuguese](https://github.com/electron/electron/tree/master/docs-translations/pt-BR) -- [Korean](https://github.com/electron/electron/tree/master/docs-translations/ko-KR) -- [Japanese](https://github.com/electron/electron/tree/master/docs-translations/jp) -- [Spanish](https://github.com/electron/electron/tree/master/docs-translations/es) -- [Simplified Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-CN) -- [Traditional Chinese](https://github.com/electron/electron/tree/master/docs-translations/zh-TW) -- [Turkish](https://github.com/electron/electron/tree/master/docs-translations/tr-TR) -- [Ukrainian](https://github.com/electron/electron/tree/master/docs-translations/uk-UA) -- [Russian](https://github.com/electron/electron/tree/master/docs-translations/ru-RU) -- [French](https://github.com/electron/electron/tree/master/docs-translations/fr-FR) +## Contributing -## Quick Start - -Clone and run the [`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) -repository to see a minimal Electron app in action. +If you are interested in reporting/fixing issues and contributing directly to the code base, please see [CONTRIBUTING.md](CONTRIBUTING.md) for more information on what we're looking for and how to get started. ## Community -You can ask questions and interact with the community in the following -locations: -- [`electron`](http://discuss.atom.io/c/electron) category on the Atom -forums -- `#atom-shell` channel on Freenode -- [`Atom`](http://atom-slack.herokuapp.com/) channel on Slack -- [`electron-br`](https://electron-br.slack.com) *(Brazilian Portuguese)* -- [`electron-kr`](http://www.meetup.com/electron-kr/) *(Korean)* -- [`electron-jp`](https://electron-jp-slackin.herokuapp.com/) *(Japanese)* -- [`electron-tr`](http://www.meetup.com/Electron-JS-Istanbul/) *(Turkish)* -- [`electron-id`](https://electron-id.slack.com) *(Indonesia)* - -Check out [awesome-electron](https://github.com/sindresorhus/awesome-electron) -for a community maintained list of useful example apps, tools and resources. +Info on reporting bugs, getting help, finding third-party tools and sample apps, +and more can be found on the [Community page](https://www.electronjs.org/community). + +## License + +[MIT](https://github.com/electron/electron/blob/main/LICENSE) + +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 new file mode 100644 index 0000000000000..7b1e3dd46a025 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +# Reporting Security Issues + +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, 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/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 + +To learn more about securing an Electron application, please see the [security tutorial](docs/tutorial/security.md). diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index b093d2a2126ea..0000000000000 --- a/appveyor.yml +++ /dev/null @@ -1,25 +0,0 @@ -# appveyor file -# http://www.appveyor.com/docs/appveyor-yml -version: "{build}" - -os: Visual Studio 2015 - -init: - - git config --global core.autocrlf input - -platform: - - x86 - - x64 - -install: - - cmd: SET PATH=C:\Program Files (x86)\MSBuild\14.0\bin\;%PATH% - - cmd: SET PATH=C:\python27;%PATH% - - cmd: python script/cibuild - -branches: - only: - - master - -# disable build and test pahses -build: off -test: off diff --git a/atom/app/atom_content_client.cc b/atom/app/atom_content_client.cc deleted file mode 100644 index 40a6e1f5268dd..0000000000000 --- a/atom/app/atom_content_client.cc +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/app/atom_content_client.h" - -#include -#include - -#include "atom/common/atom_version.h" -#include "atom/common/chrome_version.h" -#include "atom/common/options_switches.h" -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "content/public/common/content_constants.h" -#include "content/public/common/pepper_plugin_info.h" -#include "content/public/common/user_agent.h" -#include "ppapi/shared_impl/ppapi_permissions.h" -#include "third_party/widevine/cdm/stub/widevine_cdm_version.h" -#include "ui/base/l10n/l10n_util.h" -#include "url/url_constants.h" - -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) -#include "chrome/common/widevine_cdm_constants.h" -#endif - -namespace atom { - -namespace { - -content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path, - const std::string& version) { - content::PepperPluginInfo plugin; - - plugin.is_out_of_process = true; - plugin.name = content::kFlashPluginName; - plugin.path = path; - plugin.permissions = ppapi::PERMISSION_ALL_BITS; - - std::vector flash_version_numbers = base::SplitString( - version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - if (flash_version_numbers.size() < 1) - flash_version_numbers.push_back("11"); - // |SplitString()| puts in an empty string given an empty string. :( - else if (flash_version_numbers[0].empty()) - flash_version_numbers[0] = "11"; - if (flash_version_numbers.size() < 2) - flash_version_numbers.push_back("2"); - if (flash_version_numbers.size() < 3) - flash_version_numbers.push_back("999"); - if (flash_version_numbers.size() < 4) - flash_version_numbers.push_back("999"); - // E.g., "Shockwave Flash 10.2 r154": - plugin.description = plugin.name + " " + flash_version_numbers[0] + "." + - flash_version_numbers[1] + " r" + flash_version_numbers[2]; - plugin.version = base::JoinString(flash_version_numbers, "."); - content::WebPluginMimeType swf_mime_type( - content::kFlashPluginSwfMimeType, - content::kFlashPluginSwfExtension, - content::kFlashPluginSwfDescription); - plugin.mime_types.push_back(swf_mime_type); - content::WebPluginMimeType spl_mime_type( - content::kFlashPluginSplMimeType, - content::kFlashPluginSplExtension, - content::kFlashPluginSplDescription); - plugin.mime_types.push_back(spl_mime_type); - - return plugin; -} - -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) -content::PepperPluginInfo CreateWidevineCdmInfo(const base::FilePath& path, - const std::string& version) { - content::PepperPluginInfo widevine_cdm; - widevine_cdm.is_out_of_process = true; - widevine_cdm.path = path; - widevine_cdm.name = kWidevineCdmDisplayName; - widevine_cdm.description = kWidevineCdmDescription + - std::string(" (version: ") + - version + ")"; - widevine_cdm.version = version; - content::WebPluginMimeType widevine_cdm_mime_type( - kWidevineCdmPluginMimeType, - kWidevineCdmPluginExtension, - kWidevineCdmPluginMimeTypeDescription); - - // Add the supported codecs as if they came from the component manifest. - std::vector codecs; - codecs.push_back(kCdmSupportedCodecVp8); - codecs.push_back(kCdmSupportedCodecVp9); -#if defined(USE_PROPRIETARY_CODECS) - codecs.push_back(kCdmSupportedCodecAvc1); -#endif // defined(USE_PROPRIETARY_CODECS) - std::string codec_string = base::JoinString( - codecs, std::string(1, kCdmSupportedCodecsValueDelimiter)); - widevine_cdm_mime_type.additional_param_names.push_back( - base::ASCIIToUTF16(kCdmSupportedCodecsParamName)); - widevine_cdm_mime_type.additional_param_values.push_back( - base::ASCIIToUTF16(codec_string)); - - widevine_cdm.mime_types.push_back(widevine_cdm_mime_type); - widevine_cdm.permissions = kWidevineCdmPluginPermissions; - - return widevine_cdm; -} -#endif - -void ConvertStringWithSeparatorToVector(std::vector* vec, - const char* separator, - const char* cmd_switch) { - auto command_line = base::CommandLine::ForCurrentProcess(); - auto string_with_separator = command_line->GetSwitchValueASCII(cmd_switch); - if (!string_with_separator.empty()) - *vec = base::SplitString(string_with_separator, separator, - base::TRIM_WHITESPACE, - base::SPLIT_WANT_NONEMPTY); -} - -} // namespace - -void AddPepperFlashFromCommandLine( - std::vector* plugins) { - auto command_line = base::CommandLine::ForCurrentProcess(); - base::FilePath flash_path = command_line->GetSwitchValuePath( - switches::kPpapiFlashPath); - if (flash_path.empty()) - return; - - auto flash_version = command_line->GetSwitchValueASCII( - switches::kPpapiFlashVersion); - - plugins->push_back(CreatePepperFlashInfo(flash_path, flash_version)); -} - -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) -void AddWidevineCdmFromCommandLine( - std::vector* plugins) { - auto command_line = base::CommandLine::ForCurrentProcess(); - base::FilePath widevine_cdm_path = command_line->GetSwitchValuePath( - switches::kWidevineCdmPath); - if (widevine_cdm_path.empty()) - return; - - if (!base::PathExists(widevine_cdm_path)) - return; - - auto widevine_cdm_version = command_line->GetSwitchValueASCII( - switches::kWidevineCdmVersion); - if (widevine_cdm_version.empty()) - return; - - plugins->push_back(CreateWidevineCdmInfo(widevine_cdm_path, - widevine_cdm_version)); -} -#endif - -AtomContentClient::AtomContentClient() { -} - -AtomContentClient::~AtomContentClient() { -} - -std::string AtomContentClient::GetProduct() const { - return "Chrome/" CHROME_VERSION_STRING; -} - -std::string AtomContentClient::GetUserAgent() const { - return content::BuildUserAgentFromProduct( - "Chrome/" CHROME_VERSION_STRING " " - ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING); -} - -base::string16 AtomContentClient::GetLocalizedString(int message_id) const { - return l10n_util::GetStringUTF16(message_id); -} - -void AtomContentClient::AddAdditionalSchemes( - std::vector* standard_schemes, - std::vector* referrer_schemes, - std::vector* savable_schemes) { - standard_schemes->push_back({"chrome-extension", url::SCHEME_WITHOUT_PORT}); -} - -void AtomContentClient::AddPepperPlugins( - std::vector* plugins) { - AddPepperFlashFromCommandLine(plugins); -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) - AddWidevineCdmFromCommandLine(plugins); -#endif -} - -void AtomContentClient::AddServiceWorkerSchemes( - std::set* service_worker_schemes) { - std::vector schemes; - ConvertStringWithSeparatorToVector(&schemes, ",", - switches::kRegisterServiceWorkerSchemes); - if (!schemes.empty()) { - for (const std::string& scheme : schemes) - service_worker_schemes->insert(scheme); - } - service_worker_schemes->insert(url::kFileScheme); -} - -} // namespace atom diff --git a/atom/app/atom_content_client.h b/atom/app/atom_content_client.h deleted file mode 100644 index f31a14605723c..0000000000000 --- a/atom/app/atom_content_client.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_APP_ATOM_CONTENT_CLIENT_H_ -#define ATOM_APP_ATOM_CONTENT_CLIENT_H_ - -#include -#include -#include - -#include "brightray/common/content_client.h" - -namespace atom { - -class AtomContentClient : public brightray::ContentClient { - public: - AtomContentClient(); - virtual ~AtomContentClient(); - - protected: - // content::ContentClient: - std::string GetProduct() const override; - std::string GetUserAgent() const override; - base::string16 GetLocalizedString(int message_id) const override; - void AddAdditionalSchemes( - std::vector* standard_schemes, - std::vector* referrer_schemes, - std::vector* savable_schemes) override; - void AddPepperPlugins( - std::vector* plugins) override; - void AddServiceWorkerSchemes( - std::set* service_worker_schemes) override; - - private: - DISALLOW_COPY_AND_ASSIGN(AtomContentClient); -}; - -} // namespace atom - -#endif // ATOM_APP_ATOM_CONTENT_CLIENT_H_ diff --git a/atom/app/atom_library_main.h b/atom/app/atom_library_main.h deleted file mode 100644 index e1603fa5942f7..0000000000000 --- a/atom/app/atom_library_main.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_APP_ATOM_LIBRARY_MAIN_H_ -#define ATOM_APP_ATOM_LIBRARY_MAIN_H_ - -#include "build/build_config.h" - -#if defined(OS_MACOSX) -extern "C" { -__attribute__((visibility("default"))) -int AtomMain(int argc, const char* argv[]); - -__attribute__((visibility("default"))) -int AtomInitializeICUandStartNode(int argc, char *argv[]); -} -#endif // OS_MACOSX - -#endif // ATOM_APP_ATOM_LIBRARY_MAIN_H_ diff --git a/atom/app/atom_library_main.mm b/atom/app/atom_library_main.mm deleted file mode 100644 index 7ee7522934689..0000000000000 --- a/atom/app/atom_library_main.mm +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/app/atom_library_main.h" - -#include "atom/app/atom_main_delegate.h" -#include "atom/app/node_main.h" -#include "atom/common/atom_command_line.h" -#include "base/at_exit.h" -#include "base/i18n/icu_util.h" -#include "base/mac/bundle_locations.h" -#include "base/mac/scoped_nsautorelease_pool.h" -#include "brightray/common/mac/main_application_bundle.h" -#include "content/public/app/content_main.h" - -#if defined(OS_MACOSX) -int AtomMain(int argc, const char* argv[]) { - atom::AtomMainDelegate delegate; - content::ContentMainParams params(&delegate); - params.argc = argc; - params.argv = argv; - atom::AtomCommandLine::Init(argc, argv); - return content::ContentMain(params); -} - -int AtomInitializeICUandStartNode(int argc, char *argv[]) { - base::AtExitManager atexit_manager; - base::mac::ScopedNSAutoreleasePool pool; - base::mac::SetOverrideFrameworkBundlePath( - brightray::MainApplicationBundlePath() - .Append("Contents") - .Append("Frameworks") - .Append(ATOM_PRODUCT_NAME " Framework.framework")); - base::i18n::InitializeICU(); - return atom::NodeMain(argc, argv); -} -#endif // OS_MACOSX diff --git a/atom/app/atom_main.cc b/atom/app/atom_main.cc deleted file mode 100644 index 387b5167f3fc5..0000000000000 --- a/atom/app/atom_main.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/app/atom_main.h" - -#include - -#if defined(OS_WIN) -#include -#include -#include -#include - -#include "atom/app/atom_main_delegate.h" -#include "atom/common/crash_reporter/win/crash_service_main.h" -#include "base/environment.h" -#include "base/process/launch.h" -#include "base/win/windows_version.h" -#include "content/public/app/sandbox_helper_win.h" -#include "sandbox/win/src/sandbox_types.h" -#elif defined(OS_LINUX) // defined(OS_WIN) -#include "atom/app/atom_main_delegate.h" // NOLINT -#include "content/public/app/content_main.h" -#else // defined(OS_LINUX) -#include "atom/app/atom_library_main.h" -#endif // defined(OS_MACOSX) - -#include "atom/app/node_main.h" -#include "atom/common/atom_command_line.h" -#include "base/at_exit.h" -#include "base/i18n/icu_util.h" - -namespace { - -const char* kRunAsNode = "ELECTRON_RUN_AS_NODE"; - -bool IsEnvSet(const char* name) { -#if defined(OS_WIN) - size_t required_size; - getenv_s(&required_size, nullptr, 0, name); - return required_size != 0; -#else - char* indicator = getenv(name); - return indicator && indicator[0] != '\0'; -#endif -} - -} // namespace - -#if defined(OS_WIN) -int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) { - int argc = 0; - wchar_t** wargv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - - bool run_as_node = IsEnvSet(kRunAsNode); - - // Make sure the output is printed to console. - if (run_as_node || !IsEnvSet("ELECTRON_NO_ATTACH_CONSOLE")) - base::RouteStdioToConsole(false); - - // Convert argv to to UTF8 - char** argv = new char*[argc]; - for (int i = 0; i < argc; i++) { - // Compute the size of the required buffer - DWORD size = WideCharToMultiByte(CP_UTF8, - 0, - wargv[i], - -1, - NULL, - 0, - NULL, - NULL); - if (size == 0) { - // This should never happen. - fprintf(stderr, "Could not convert arguments to utf8."); - exit(1); - } - // Do the actual conversion - argv[i] = new char[size]; - DWORD result = WideCharToMultiByte(CP_UTF8, - 0, - wargv[i], - -1, - argv[i], - size, - NULL, - NULL); - if (result == 0) { - // This should never happen. - fprintf(stderr, "Could not convert arguments to utf8."); - exit(1); - } - } - - if (run_as_node) { - // Now that argv conversion is done, we can finally start. - base::AtExitManager atexit_manager; - base::i18n::InitializeICU(); - return atom::NodeMain(argc, argv); - } else if (IsEnvSet("ELECTRON_INTERNAL_CRASH_SERVICE")) { - return crash_service::Main(cmd); - } - - sandbox::SandboxInterfaceInfo sandbox_info = {0}; - content::InitializeSandboxInfo(&sandbox_info); - atom::AtomMainDelegate delegate; - - content::ContentMainParams params(&delegate); - params.instance = instance; - params.sandbox_info = &sandbox_info; - atom::AtomCommandLine::Init(argc, argv); - atom::AtomCommandLine::InitW(argc, wargv); - return content::ContentMain(params); -} - -#elif defined(OS_LINUX) // defined(OS_WIN) - -int main(int argc, const char* argv[]) { - if (IsEnvSet(kRunAsNode)) { - base::i18n::InitializeICU(); - base::AtExitManager atexit_manager; - return atom::NodeMain(argc, const_cast(argv)); - } - - atom::AtomMainDelegate delegate; - content::ContentMainParams params(&delegate); - params.argc = argc; - params.argv = argv; - atom::AtomCommandLine::Init(argc, argv); - return content::ContentMain(params); -} - -#else // defined(OS_LINUX) - -int main(int argc, const char* argv[]) { - if (IsEnvSet(kRunAsNode)) { - return AtomInitializeICUandStartNode(argc, const_cast(argv)); - } - - return AtomMain(argc, argv); -} - -#endif // defined(OS_MACOSX) diff --git a/atom/app/atom_main.h b/atom/app/atom_main.h deleted file mode 100644 index 30663a429e936..0000000000000 --- a/atom/app/atom_main.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_APP_ATOM_MAIN_H_ -#define ATOM_APP_ATOM_MAIN_H_ - -#include "content/public/app/content_main.h" - -#endif // ATOM_APP_ATOM_MAIN_H_ diff --git a/atom/app/atom_main_delegate.cc b/atom/app/atom_main_delegate.cc deleted file mode 100644 index f4e0b60444818..0000000000000 --- a/atom/app/atom_main_delegate.cc +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/app/atom_main_delegate.h" - -#include -#include - -#include "atom/app/atom_content_client.h" -#include "atom/browser/atom_browser_client.h" -#include "atom/browser/relauncher.h" -#include "atom/common/google_api_key.h" -#include "atom/renderer/atom_renderer_client.h" -#include "atom/utility/atom_content_utility_client.h" -#include "base/command_line.h" -#include "base/debug/stack_trace.h" -#include "base/environment.h" -#include "base/logging.h" -#include "chrome/common/chrome_paths.h" -#include "content/public/common/content_switches.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" - -namespace atom { - -namespace { - -const char* kRelauncherProcess = "relauncher"; - -bool IsBrowserProcess(base::CommandLine* cmd) { - std::string process_type = cmd->GetSwitchValueASCII(switches::kProcessType); - return process_type.empty(); -} - -#if defined(OS_WIN) -void InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, - unsigned int, uintptr_t) { - // noop. -} -#endif - -} // namespace - -AtomMainDelegate::AtomMainDelegate() { -} - -AtomMainDelegate::~AtomMainDelegate() { -} - -bool AtomMainDelegate::BasicStartupComplete(int* exit_code) { - auto command_line = base::CommandLine::ForCurrentProcess(); - - logging::LoggingSettings settings; -#if defined(OS_WIN) - // On Windows the terminal returns immediately, so we add a new line to - // prevent output in the same line as the prompt. - if (IsBrowserProcess(command_line)) - std::wcout << std::endl; -#if defined(DEBUG) - // Print logging to debug.log on Windows - settings.logging_dest = logging::LOG_TO_ALL; - settings.log_file = L"debug.log"; - settings.lock_log = logging::LOCK_LOG_FILE; - settings.delete_old = logging::DELETE_OLD_LOG_FILE; -#else - settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; -#endif // defined(DEBUG) -#else // defined(OS_WIN) - settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; -#endif // !defined(OS_WIN) - - // Only enable logging when --enable-logging is specified. - std::unique_ptr env(base::Environment::Create()); - if (!command_line->HasSwitch(switches::kEnableLogging) && - !env->HasVar("ELECTRON_ENABLE_LOGGING")) { - settings.logging_dest = logging::LOG_NONE; - logging::SetMinLogLevel(logging::LOG_NUM_SEVERITIES); - } - - logging::InitLogging(settings); - - // Logging with pid and timestamp. - logging::SetLogItems(true, false, true, false); - - // Enable convient stack printing. - bool enable_stack_dumping = env->HasVar("ELECTRON_ENABLE_STACK_DUMPING"); -#if defined(DEBUG) && defined(OS_LINUX) - enable_stack_dumping = true; -#endif - if (enable_stack_dumping) - base::debug::EnableInProcessStackDumping(); - - chrome::RegisterPathProvider(); - -#if defined(OS_MACOSX) - SetUpBundleOverrides(); -#endif - -#if defined(OS_WIN) - // Ignore invalid parameter errors. - _set_invalid_parameter_handler(InvalidParameterHandler); -#endif - - return brightray::MainDelegate::BasicStartupComplete(exit_code); -} - -void AtomMainDelegate::PreSandboxStartup() { - brightray::MainDelegate::PreSandboxStartup(); - - // Set google API key. - std::unique_ptr env(base::Environment::Create()); - if (!env->HasVar("GOOGLE_API_KEY")) - env->SetVar("GOOGLE_API_KEY", GOOGLEAPIS_API_KEY); - - auto command_line = base::CommandLine::ForCurrentProcess(); - std::string process_type = command_line->GetSwitchValueASCII( - switches::kProcessType); - - // Only append arguments for browser process. - if (!IsBrowserProcess(command_line)) - return; - - // Disable renderer sandbox for most of node's functions. - command_line->AppendSwitch(switches::kNoSandbox); - - // Allow file:// URIs to read other file:// URIs by default. - command_line->AppendSwitch(switches::kAllowFileAccessFromFiles); - -#if defined(OS_MACOSX) - // Enable AVFoundation. - command_line->AppendSwitch("enable-avfoundation"); -#endif -} - -content::ContentBrowserClient* AtomMainDelegate::CreateContentBrowserClient() { - browser_client_.reset(new AtomBrowserClient); - return browser_client_.get(); -} - -content::ContentRendererClient* - AtomMainDelegate::CreateContentRendererClient() { - renderer_client_.reset(new AtomRendererClient); - return renderer_client_.get(); -} - -content::ContentUtilityClient* AtomMainDelegate::CreateContentUtilityClient() { - utility_client_.reset(new AtomContentUtilityClient); - return utility_client_.get(); -} - -int AtomMainDelegate::RunProcess( - const std::string& process_type, - const content::MainFunctionParams& main_function_params) { - if (process_type == kRelauncherProcess) - return relauncher::RelauncherMain(main_function_params); - else - return -1; -} - -#if defined(OS_MACOSX) -bool AtomMainDelegate::ShouldSendMachPort(const std::string& process_type) { - return process_type != kRelauncherProcess; -} - -bool AtomMainDelegate::DelaySandboxInitialization( - const std::string& process_type) { - return process_type == kRelauncherProcess; -} -#endif - -std::unique_ptr -AtomMainDelegate::CreateContentClient() { - return std::unique_ptr(new AtomContentClient); -} - -} // namespace atom diff --git a/atom/app/atom_main_delegate.h b/atom/app/atom_main_delegate.h deleted file mode 100644 index 58a380bd7d5ae..0000000000000 --- a/atom/app/atom_main_delegate.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_APP_ATOM_MAIN_DELEGATE_H_ -#define ATOM_APP_ATOM_MAIN_DELEGATE_H_ - -#include - -#include "brightray/common/main_delegate.h" -#include "brightray/common/content_client.h" - -namespace atom { - -class AtomMainDelegate : public brightray::MainDelegate { - public: - AtomMainDelegate(); - ~AtomMainDelegate(); - - protected: - // content::ContentMainDelegate: - bool BasicStartupComplete(int* exit_code) override; - void PreSandboxStartup() override; - content::ContentBrowserClient* CreateContentBrowserClient() override; - content::ContentRendererClient* CreateContentRendererClient() override; - content::ContentUtilityClient* CreateContentUtilityClient() override; - int RunProcess( - const std::string& process_type, - const content::MainFunctionParams& main_function_params) override; -#if defined(OS_MACOSX) - bool ShouldSendMachPort(const std::string& process_type) override; - bool DelaySandboxInitialization(const std::string& process_type) override; -#endif - - // brightray::MainDelegate: - std::unique_ptr CreateContentClient() override; -#if defined(OS_MACOSX) - void OverrideChildProcessPath() override; - void OverrideFrameworkBundlePath() override; -#endif - - private: -#if defined(OS_MACOSX) - void SetUpBundleOverrides(); -#endif - - brightray::ContentClient content_client_; - std::unique_ptr browser_client_; - std::unique_ptr renderer_client_; - std::unique_ptr utility_client_; - - DISALLOW_COPY_AND_ASSIGN(AtomMainDelegate); -}; - -} // namespace atom - -#endif // ATOM_APP_ATOM_MAIN_DELEGATE_H_ diff --git a/atom/app/atom_main_delegate_mac.mm b/atom/app/atom_main_delegate_mac.mm deleted file mode 100644 index ea5ab320a4d06..0000000000000 --- a/atom/app/atom_main_delegate_mac.mm +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/app/atom_main_delegate.h" - -#include "base/mac/bundle_locations.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_nsautorelease_pool.h" -#include "base/path_service.h" -#include "base/strings/sys_string_conversions.h" -#include "brightray/common/application_info.h" -#include "brightray/common/mac/main_application_bundle.h" -#include "content/public/common/content_paths.h" - -namespace atom { - -namespace { - -base::FilePath GetFrameworksPath() { - return brightray::MainApplicationBundlePath().Append("Contents") - .Append("Frameworks"); -} - -base::FilePath GetHelperAppPath(const base::FilePath& frameworks_path, - const std::string& name) { - return frameworks_path.Append(name + " Helper.app") - .Append("Contents") - .Append("MacOS") - .Append(name + " Helper"); -} - -} // namespace - -void AtomMainDelegate::OverrideFrameworkBundlePath() { - base::mac::SetOverrideFrameworkBundlePath( - GetFrameworksPath().Append(ATOM_PRODUCT_NAME " Framework.framework")); -} - -void AtomMainDelegate::OverrideChildProcessPath() { - base::FilePath frameworks_path = GetFrameworksPath(); - base::FilePath helper_path = GetHelperAppPath(frameworks_path, - ATOM_PRODUCT_NAME); - if (!base::PathExists(helper_path)) - helper_path = GetHelperAppPath(frameworks_path, - brightray::GetApplicationName()); - if (!base::PathExists(helper_path)) - LOG(FATAL) << "Unable to find helper app"; - PathService::Override(content::CHILD_PROCESS_EXE, helper_path); -} - -void AtomMainDelegate::SetUpBundleOverrides() { - base::mac::ScopedNSAutoreleasePool pool; - NSBundle* bundle = brightray::MainApplicationBundle(); - std::string base_bundle_id = - base::SysNSStringToUTF8([bundle bundleIdentifier]); - NSString* team_id = [bundle objectForInfoDictionaryKey:@"ElectronTeamID"]; - if (team_id) - base_bundle_id = base::SysNSStringToUTF8(team_id) + "." + base_bundle_id; - base::mac::SetBaseBundleID(base_bundle_id.c_str()); -} - -} // namespace atom diff --git a/atom/app/node_main.cc b/atom/app/node_main.cc deleted file mode 100644 index 040b4b6157214..0000000000000 --- a/atom/app/node_main.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/app/node_main.h" - -#include "atom/app/uv_task_runner.h" -#include "atom/browser/javascript_environment.h" -#include "atom/browser/node_debugger.h" -#include "base/command_line.h" -#include "base/feature_list.h" -#include "base/threading/thread_task_runner_handle.h" -#include "gin/array_buffer.h" -#include "gin/public/isolate_holder.h" -#include "gin/v8_initializer.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -int NodeMain(int argc, char *argv[]) { - base::CommandLine::Init(argc, argv); - - int exit_code = 1; - { - // Feed gin::PerIsolateData with a task runner. - argv = uv_setup_args(argc, argv); - uv_loop_t* loop = uv_default_loop(); - scoped_refptr uv_task_runner(new UvTaskRunner(loop)); - base::ThreadTaskRunnerHandle handle(uv_task_runner); - - // Initialize feature list. - std::unique_ptr feature_list(new base::FeatureList); - feature_list->InitializeFromCommandLine("", ""); - base::FeatureList::SetInstance(std::move(feature_list)); - - gin::V8Initializer::LoadV8Snapshot(); - gin::V8Initializer::LoadV8Natives(); - JavascriptEnvironment gin_env; - - int exec_argc; - const char** exec_argv; - node::Init(&argc, const_cast(argv), &exec_argc, &exec_argv); - - node::Environment* env = node::CreateEnvironment( - gin_env.isolate(), loop, gin_env.context(), argc, argv, - exec_argc, exec_argv); - - // Start our custom debugger implementation. - NodeDebugger node_debugger(gin_env.isolate()); - if (node_debugger.IsRunning()) - env->AssignToContext(v8::Debug::GetDebugContext()); - - node::LoadEnvironment(env); - - bool more; - do { - more = uv_run(env->event_loop(), UV_RUN_ONCE); - if (more == false) { - node::EmitBeforeExit(env); - - // Emit `beforeExit` if the loop became alive either after emitting - // event, or after running some callbacks. - more = uv_loop_alive(env->event_loop()); - if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0) - more = true; - } - } while (more == true); - - exit_code = node::EmitExit(env); - node::RunAtExit(env); - - node::FreeEnvironment(env); - } - - v8::V8::Dispose(); - - return exit_code; -} - -} // namespace atom diff --git a/atom/app/node_main.h b/atom/app/node_main.h deleted file mode 100644 index a4e047de39f18..0000000000000 --- a/atom/app/node_main.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_APP_NODE_MAIN_H_ -#define ATOM_APP_NODE_MAIN_H_ - -namespace atom { - -int NodeMain(int argc, char *argv[]); - -} // namespace atom - -#endif // ATOM_APP_NODE_MAIN_H_ diff --git a/atom/app/uv_task_runner.cc b/atom/app/uv_task_runner.cc deleted file mode 100644 index 7857ace3a2bdc..0000000000000 --- a/atom/app/uv_task_runner.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/app/uv_task_runner.h" - -#include "base/stl_util.h" - -namespace atom { - -UvTaskRunner::UvTaskRunner(uv_loop_t* loop) : loop_(loop) { -} - -UvTaskRunner::~UvTaskRunner() { - for (auto& iter : tasks_) { - uv_unref(reinterpret_cast(iter.first)); - delete iter.first; - } -} - -bool UvTaskRunner::PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - auto* timer = new uv_timer_t; - timer->data = this; - uv_timer_init(loop_, timer); - uv_timer_start(timer, UvTaskRunner::OnTimeout, delay.InMilliseconds(), 0); - tasks_[timer] = task; - return true; -} - -bool UvTaskRunner::RunsTasksOnCurrentThread() const { - return true; -} - -bool UvTaskRunner::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - return PostDelayedTask(from_here, task, delay); -} - -// static -void UvTaskRunner::OnTimeout(uv_timer_t* timer) { - UvTaskRunner* self = static_cast(timer->data); - if (!ContainsKey(self->tasks_, timer)) - return; - - self->tasks_[timer].Run(); - self->tasks_.erase(timer); - uv_timer_stop(timer); - uv_close(reinterpret_cast(timer), UvTaskRunner::OnClose); -} - -// static -void UvTaskRunner::OnClose(uv_handle_t* handle) { - delete reinterpret_cast(handle); -} - -} // namespace atom diff --git a/atom/app/uv_task_runner.h b/atom/app/uv_task_runner.h deleted file mode 100644 index c7302766c2d17..0000000000000 --- a/atom/app/uv_task_runner.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_APP_UV_TASK_RUNNER_H_ -#define ATOM_APP_UV_TASK_RUNNER_H_ - -#include - -#include "base/callback.h" -#include "base/single_thread_task_runner.h" -#include "vendor/node/deps/uv/include/uv.h" - -namespace atom { - -// TaskRunner implementation that posts tasks into libuv's default loop. -class UvTaskRunner : public base::SingleThreadTaskRunner { - public: - explicit UvTaskRunner(uv_loop_t* loop); - ~UvTaskRunner() override; - - // base::SingleThreadTaskRunner: - bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool RunsTasksOnCurrentThread() const override; - bool PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - - private: - static void OnTimeout(uv_timer_t* timer); - static void OnClose(uv_handle_t* handle); - - uv_loop_t* loop_; - - std::map tasks_; - - DISALLOW_COPY_AND_ASSIGN(UvTaskRunner); -}; - -} // namespace atom - -#endif // ATOM_APP_UV_TASK_RUNNER_H_ diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc deleted file mode 100644 index 5228c640f0038..0000000000000 --- a/atom/browser/api/atom_api_app.cc +++ /dev/null @@ -1,669 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_app.h" - -#include -#include - -#include "atom/browser/api/atom_api_menu.h" -#include "atom/browser/api/atom_api_session.h" -#include "atom/browser/api/atom_api_web_contents.h" -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/browser/browser.h" -#include "atom/browser/login_handler.h" -#include "atom/browser/relauncher.h" -#include "atom/common/atom_command_line.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/native_mate_converters/image_converter.h" -#include "atom/common/native_mate_converters/net_converter.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_includes.h" -#include "atom/common/options_switches.h" -#include "base/command_line.h" -#include "base/environment.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "brightray/browser/brightray_paths.h" -#include "chrome/common/chrome_paths.h" -#include "content/public/browser/browser_accessibility_state.h" -#include "content/public/browser/client_certificate_delegate.h" -#include "content/public/browser/gpu_data_manager.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/common/content_switches.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" -#include "net/ssl/ssl_cert_request_info.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/image/image.h" - -#if defined(OS_WIN) -#include "base/strings/utf_string_conversions.h" -#endif - -using atom::Browser; - -namespace mate { - -#if defined(OS_WIN) -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - Browser::UserTask* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - if (!dict.Get("program", &(out->program)) || - !dict.Get("title", &(out->title))) - return false; - if (dict.Get("iconPath", &(out->icon_path)) && - !dict.Get("iconIndex", &(out->icon_index))) - return false; - dict.Get("arguments", &(out->arguments)); - dict.Get("description", &(out->description)); - return true; - } -}; -#endif - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - Browser::LoginItemSettings* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - - dict.Get("openAtLogin", &(out->open_at_login)); - dict.Get("openAsHidden", &(out->open_as_hidden)); - return true; - } - - static v8::Local ToV8(v8::Isolate* isolate, - Browser::LoginItemSettings val) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("openAtLogin", val.open_at_login); - dict.Set("openAsHidden", val.open_as_hidden); - dict.Set("restoreState", val.restore_state); - dict.Set("wasOpenedAtLogin", val.opened_at_login); - dict.Set("wasOpenedAsHidden", val.opened_as_hidden); - return dict.GetHandle(); - } -}; -} // namespace mate - - -namespace atom { - -namespace api { - -namespace { - -// Return the path constant from string. -int GetPathConstant(const std::string& name) { - if (name == "appData") - return brightray::DIR_APP_DATA; - else if (name == "userData") - return brightray::DIR_USER_DATA; - else if (name == "cache") - return brightray::DIR_CACHE; - else if (name == "userCache") - return brightray::DIR_USER_CACHE; - else if (name == "home") - return base::DIR_HOME; - else if (name == "temp") - return base::DIR_TEMP; - else if (name == "userDesktop" || name == "desktop") - return base::DIR_USER_DESKTOP; - else if (name == "exe") - return base::FILE_EXE; - else if (name == "module") - return base::FILE_MODULE; - else if (name == "documents") - return chrome::DIR_USER_DOCUMENTS; - else if (name == "downloads") - return chrome::DIR_DEFAULT_DOWNLOADS; - else if (name == "music") - return chrome::DIR_USER_MUSIC; - else if (name == "pictures") - return chrome::DIR_USER_PICTURES; - else if (name == "videos") - return chrome::DIR_USER_VIDEOS; - else if (name == "pepperFlashSystemPlugin") - return chrome::FILE_PEPPER_FLASH_SYSTEM_PLUGIN; - else - return -1; -} - -bool NotificationCallbackWrapper( - const ProcessSingleton::NotificationCallback& callback, - const base::CommandLine::StringVector& cmd, - const base::FilePath& cwd) { - // Make sure the callback is called after app gets ready. - if (Browser::Get()->is_ready()) { - callback.Run(cmd, cwd); - } else { - scoped_refptr task_runner( - base::ThreadTaskRunnerHandle::Get()); - task_runner->PostTask( - FROM_HERE, base::Bind(base::IgnoreResult(callback), cmd, cwd)); - } - // ProcessSingleton needs to know whether current process is quiting. - return !Browser::Get()->is_shutting_down(); -} - -void OnClientCertificateSelected( - v8::Isolate* isolate, - std::shared_ptr delegate, - mate::Arguments* args) { - mate::Dictionary cert_data; - if (!args->GetNext(&cert_data)) { - args->ThrowError(); - return; - } - - v8::Local data; - if (!cert_data.Get("data", &data)) - return; - - auto certs = net::X509Certificate::CreateCertificateListFromBytes( - node::Buffer::Data(data), node::Buffer::Length(data), - net::X509Certificate::FORMAT_AUTO); - if (certs.size() > 0) - delegate->ContinueWithCertificate(certs[0].get()); -} - -void PassLoginInformation(scoped_refptr login_handler, - mate::Arguments* args) { - base::string16 username, password; - if (args->GetNext(&username) && args->GetNext(&password)) - login_handler->Login(username, password); - else - login_handler->CancelAuth(); -} - -#if defined(USE_NSS_CERTS) -int ImportIntoCertStore( - CertificateManagerModel* model, - const base::DictionaryValue& options) { - std::string file_data, cert_path; - base::string16 password; - net::CertificateList imported_certs; - int rv = -1; - options.GetString("certificate", &cert_path); - options.GetString("password", &password); - - if (!cert_path.empty()) { - if (base::ReadFileToString(base::FilePath(cert_path), &file_data)) { - auto module = model->cert_db()->GetPublicModule(); - rv = model->ImportFromPKCS12(module, - file_data, - password, - true, - &imported_certs); - if (imported_certs.size() > 1) { - auto it = imported_certs.begin(); - ++it; // skip first which would be the client certificate. - for (; it != imported_certs.end(); ++it) - rv &= model->SetCertTrust(it->get(), - net::CA_CERT, - net::NSSCertDatabase::TRUSTED_SSL); - } - } - } - return rv; -} -#endif - -} // namespace - -App::App(v8::Isolate* isolate) { - static_cast(AtomBrowserClient::Get())->set_delegate(this); - Browser::Get()->AddObserver(this); - content::GpuDataManager::GetInstance()->AddObserver(this); - Init(isolate); -} - -App::~App() { - static_cast(AtomBrowserClient::Get())->set_delegate( - nullptr); - Browser::Get()->RemoveObserver(this); - content::GpuDataManager::GetInstance()->RemoveObserver(this); -} - -void App::OnBeforeQuit(bool* prevent_default) { - *prevent_default = Emit("before-quit"); -} - -void App::OnWillQuit(bool* prevent_default) { - *prevent_default = Emit("will-quit"); -} - -void App::OnWindowAllClosed() { - Emit("window-all-closed"); -} - -void App::OnQuit() { - int exitCode = AtomBrowserMainParts::Get()->GetExitCode(); - Emit("quit", exitCode); - - if (process_singleton_.get()) { - process_singleton_->Cleanup(); - process_singleton_.reset(); - } -} - -void App::OnOpenFile(bool* prevent_default, const std::string& file_path) { - *prevent_default = Emit("open-file", file_path); -} - -void App::OnOpenURL(const std::string& url) { - Emit("open-url", url); -} - -void App::OnActivate(bool has_visible_windows) { - Emit("activate", has_visible_windows); -} - -void App::OnWillFinishLaunching() { - Emit("will-finish-launching"); -} - -void App::OnFinishLaunching() { - Emit("ready"); -} - -void App::OnAccessibilitySupportChanged() { - Emit("accessibility-support-changed", IsAccessibilitySupportEnabled()); -} - -#if defined(OS_MACOSX) -void App::OnContinueUserActivity( - bool* prevent_default, - const std::string& type, - const base::DictionaryValue& user_info) { - *prevent_default = Emit("continue-activity", type, user_info); -} -#endif - -void App::OnLogin(LoginHandler* login_handler, - const base::DictionaryValue& request_details) { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - bool prevent_default = Emit( - "login", - WebContents::CreateFrom(isolate(), login_handler->GetWebContents()), - request_details, - login_handler->auth_info(), - base::Bind(&PassLoginInformation, make_scoped_refptr(login_handler))); - - // Default behavior is to always cancel the auth. - if (!prevent_default) - login_handler->CancelAuth(); -} - -void App::OnCreateWindow(const GURL& target_url, - const std::string& frame_name, - WindowOpenDisposition disposition, - int render_process_id, - int render_frame_id) { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - content::RenderFrameHost* rfh = - content::RenderFrameHost::FromID(render_process_id, render_frame_id); - content::WebContents* web_contents = - content::WebContents::FromRenderFrameHost(rfh); - if (web_contents) { - auto api_web_contents = WebContents::CreateFrom(isolate(), web_contents); - api_web_contents->OnCreateWindow(target_url, frame_name, disposition); - } -} - -void App::AllowCertificateError( - content::WebContents* web_contents, - int cert_error, - const net::SSLInfo& ssl_info, - const GURL& request_url, - content::ResourceType resource_type, - bool overridable, - bool strict_enforcement, - bool expired_previous_decision, - const base::Callback& callback, - content::CertificateRequestResultType* request) { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - bool prevent_default = Emit("certificate-error", - WebContents::CreateFrom(isolate(), web_contents), - request_url, - net::ErrorToString(cert_error), - ssl_info.cert, - callback); - - // Deny the certificate by default. - if (!prevent_default) - *request = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY; -} - -void App::SelectClientCertificate( - content::WebContents* web_contents, - net::SSLCertRequestInfo* cert_request_info, - std::unique_ptr delegate) { - std::shared_ptr - shared_delegate(delegate.release()); - bool prevent_default = - Emit("select-client-certificate", - WebContents::CreateFrom(isolate(), web_contents), - cert_request_info->host_and_port.ToString(), - cert_request_info->client_certs, - base::Bind(&OnClientCertificateSelected, - isolate(), - shared_delegate)); - - // Default to first certificate from the platform store. - if (!prevent_default) - shared_delegate->ContinueWithCertificate( - cert_request_info->client_certs[0].get()); -} - -void App::OnGpuProcessCrashed(base::TerminationStatus exit_code) { - Emit("gpu-process-crashed"); -} - -base::FilePath App::GetPath(mate::Arguments* args, const std::string& name) { - bool succeed = false; - base::FilePath path; - int key = GetPathConstant(name); - if (key >= 0) - succeed = PathService::Get(key, &path); - if (!succeed) - args->ThrowError("Failed to get path"); - return path; -} - -void App::SetPath(mate::Arguments* args, - const std::string& name, - const base::FilePath& path) { - if (!path.IsAbsolute()) { - args->ThrowError("path must be absolute"); - return; - } - - bool succeed = false; - int key = GetPathConstant(name); - if (key >= 0) - succeed = PathService::OverrideAndCreateIfNeeded(key, path, true, false); - if (!succeed) - args->ThrowError("Failed to set path"); -} - -void App::SetDesktopName(const std::string& desktop_name) { -#if defined(OS_LINUX) - std::unique_ptr env(base::Environment::Create()); - env->SetVar("CHROME_DESKTOP", desktop_name); -#endif -} - -std::string App::GetLocale() { - return l10n_util::GetApplicationLocale(""); -} - -bool App::MakeSingleInstance( - const ProcessSingleton::NotificationCallback& callback) { - if (process_singleton_.get()) - return false; - - base::FilePath user_dir; - PathService::Get(brightray::DIR_USER_DATA, &user_dir); - process_singleton_.reset(new ProcessSingleton( - user_dir, base::Bind(NotificationCallbackWrapper, callback))); - - switch (process_singleton_->NotifyOtherProcessOrCreate()) { - case ProcessSingleton::NotifyResult::LOCK_ERROR: - case ProcessSingleton::NotifyResult::PROFILE_IN_USE: - case ProcessSingleton::NotifyResult::PROCESS_NOTIFIED: - process_singleton_.reset(); - return true; - case ProcessSingleton::NotifyResult::PROCESS_NONE: - default: // Shouldn't be needed, but VS warns if it is not there. - return false; - } -} - -void App::ReleaseSingleInstance() { - if (process_singleton_.get()) { - process_singleton_->Cleanup(); - process_singleton_.reset(); - } -} - -bool App::Relaunch(mate::Arguments* js_args) { - // Parse parameters. - bool override_argv = false; - base::FilePath exec_path; - relauncher::StringVector args; - - mate::Dictionary options; - if (js_args->GetNext(&options)) { - if (options.Get("execPath", &exec_path) | options.Get("args", &args)) - override_argv = true; - } - - if (!override_argv) { -#if defined(OS_WIN) - const relauncher::StringVector& argv = atom::AtomCommandLine::wargv(); -#else - const relauncher::StringVector& argv = atom::AtomCommandLine::argv(); -#endif - return relauncher::RelaunchApp(argv); - } - - relauncher::StringVector argv; - argv.reserve(1 + args.size()); - - if (exec_path.empty()) { - base::FilePath current_exe_path; - PathService::Get(base::FILE_EXE, ¤t_exe_path); - argv.push_back(current_exe_path.value()); - } else { - argv.push_back(exec_path.value()); - } - - argv.insert(argv.end(), args.begin(), args.end()); - - return relauncher::RelaunchApp(argv); -} - -void App::DisableHardwareAcceleration(mate::Arguments* args) { - if (Browser::Get()->is_ready()) { - args->ThrowError("app.disableHardwareAcceleration() can only be called " - "before app is ready"); - return; - } - content::GpuDataManager::GetInstance()->DisableHardwareAcceleration(); -} - -bool App::IsAccessibilitySupportEnabled() { - auto ax_state = content::BrowserAccessibilityState::GetInstance(); - return ax_state->IsAccessibleBrowser(); -} - -#if defined(USE_NSS_CERTS) -void App::ImportCertificate( - const base::DictionaryValue& options, - const net::CompletionCallback& callback) { - auto browser_context = AtomBrowserContext::From("", false); - if (!certificate_manager_model_) { - std::unique_ptr copy = options.CreateDeepCopy(); - CertificateManagerModel::Create( - browser_context.get(), - base::Bind(&App::OnCertificateManagerModelCreated, - base::Unretained(this), - base::Passed(©), - callback)); - return; - } - - int rv = ImportIntoCertStore(certificate_manager_model_.get(), options); - callback.Run(rv); -} - -void App::OnCertificateManagerModelCreated( - std::unique_ptr options, - const net::CompletionCallback& callback, - std::unique_ptr model) { - certificate_manager_model_ = std::move(model); - int rv = ImportIntoCertStore(certificate_manager_model_.get(), - *(options.get())); - callback.Run(rv); -} -#endif - -// static -mate::Handle App::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new App(isolate)); -} - -// static -void App::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "App")); - auto browser = base::Unretained(Browser::Get()); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("quit", base::Bind(&Browser::Quit, browser)) - .SetMethod("exit", base::Bind(&Browser::Exit, browser)) - .SetMethod("focus", base::Bind(&Browser::Focus, browser)) - .SetMethod("getVersion", base::Bind(&Browser::GetVersion, browser)) - .SetMethod("setVersion", base::Bind(&Browser::SetVersion, browser)) - .SetMethod("getName", base::Bind(&Browser::GetName, browser)) - .SetMethod("setName", base::Bind(&Browser::SetName, browser)) - .SetMethod("isReady", base::Bind(&Browser::is_ready, browser)) - .SetMethod("addRecentDocument", - base::Bind(&Browser::AddRecentDocument, browser)) - .SetMethod("clearRecentDocuments", - base::Bind(&Browser::ClearRecentDocuments, browser)) - .SetMethod("setAppUserModelId", - base::Bind(&Browser::SetAppUserModelID, browser)) - .SetMethod("isDefaultProtocolClient", - base::Bind(&Browser::IsDefaultProtocolClient, browser)) - .SetMethod("setAsDefaultProtocolClient", - base::Bind(&Browser::SetAsDefaultProtocolClient, browser)) - .SetMethod("removeAsDefaultProtocolClient", - base::Bind(&Browser::RemoveAsDefaultProtocolClient, browser)) - .SetMethod("setBadgeCount", base::Bind(&Browser::SetBadgeCount, browser)) - .SetMethod("getBadgeCount", base::Bind(&Browser::GetBadgeCount, browser)) - .SetMethod("getLoginItemSettings", - base::Bind(&Browser::GetLoginItemSettings, browser)) - .SetMethod("setLoginItemSettings", - base::Bind(&Browser::SetLoginItemSettings, browser)) -#if defined(OS_MACOSX) - .SetMethod("hide", base::Bind(&Browser::Hide, browser)) - .SetMethod("show", base::Bind(&Browser::Show, browser)) - .SetMethod("setUserActivity", - base::Bind(&Browser::SetUserActivity, browser)) - .SetMethod("getCurrentActivityType", - base::Bind(&Browser::GetCurrentActivityType, browser)) -#endif -#if defined(OS_WIN) - .SetMethod("setUserTasks", base::Bind(&Browser::SetUserTasks, browser)) -#endif -#if defined(OS_LINUX) - .SetMethod("isUnityRunning", - base::Bind(&Browser::IsUnityRunning, browser)) -#endif - .SetMethod("setPath", &App::SetPath) - .SetMethod("getPath", &App::GetPath) - .SetMethod("setDesktopName", &App::SetDesktopName) - .SetMethod("getLocale", &App::GetLocale) -#if defined(USE_NSS_CERTS) - .SetMethod("importCertificate", &App::ImportCertificate) -#endif - .SetMethod("makeSingleInstance", &App::MakeSingleInstance) - .SetMethod("releaseSingleInstance", &App::ReleaseSingleInstance) - .SetMethod("relaunch", &App::Relaunch) - .SetMethod("isAccessibilitySupportEnabled", - &App::IsAccessibilitySupportEnabled) - .SetMethod("disableHardwareAcceleration", - &App::DisableHardwareAcceleration); -} - -} // namespace api - -} // namespace atom - - -namespace { - -void AppendSwitch(const std::string& switch_string, mate::Arguments* args) { - auto command_line = base::CommandLine::ForCurrentProcess(); - - if (base::EndsWith(switch_string, "-path", - base::CompareCase::INSENSITIVE_ASCII) || - switch_string == switches::kLogNetLog) { - base::FilePath path; - args->GetNext(&path); - command_line->AppendSwitchPath(switch_string, path); - return; - } - - std::string value; - if (args->GetNext(&value)) - command_line->AppendSwitchASCII(switch_string, value); - else - command_line->AppendSwitch(switch_string); -} - -#if defined(OS_MACOSX) -int DockBounce(const std::string& type) { - int request_id = -1; - if (type == "critical") - request_id = Browser::Get()->DockBounce(Browser::BOUNCE_CRITICAL); - else if (type == "informational") - request_id = Browser::Get()->DockBounce(Browser::BOUNCE_INFORMATIONAL); - return request_id; -} - -void DockSetMenu(atom::api::Menu* menu) { - Browser::Get()->DockSetMenu(menu->model()); -} -#endif - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - auto command_line = base::CommandLine::ForCurrentProcess(); - - mate::Dictionary dict(isolate, exports); - dict.Set("App", atom::api::App::GetConstructor(isolate)->GetFunction()); - dict.Set("app", atom::api::App::Create(isolate)); - dict.SetMethod("appendSwitch", &AppendSwitch); - dict.SetMethod("appendArgument", - base::Bind(&base::CommandLine::AppendArg, - base::Unretained(command_line))); -#if defined(OS_MACOSX) - auto browser = base::Unretained(Browser::Get()); - dict.SetMethod("dockBounce", &DockBounce); - dict.SetMethod("dockCancelBounce", - base::Bind(&Browser::DockCancelBounce, browser)); - dict.SetMethod("dockDownloadFinished", - base::Bind(&Browser::DockDownloadFinished, browser)); - dict.SetMethod("dockSetBadgeText", - base::Bind(&Browser::DockSetBadgeText, browser)); - dict.SetMethod("dockGetBadgeText", - base::Bind(&Browser::DockGetBadgeText, browser)); - dict.SetMethod("dockHide", base::Bind(&Browser::DockHide, browser)); - dict.SetMethod("dockShow", base::Bind(&Browser::DockShow, browser)); - dict.SetMethod("dockIsVisible", base::Bind(&Browser::DockIsVisible, browser)); - dict.SetMethod("dockSetMenu", &DockSetMenu); - dict.SetMethod("dockSetIcon", base::Bind(&Browser::DockSetIcon, browser)); -#endif -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_app, Initialize) diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h deleted file mode 100644 index 990199cd6fe5a..0000000000000 --- a/atom/browser/api/atom_api_app.h +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_APP_H_ -#define ATOM_BROWSER_API_ATOM_API_APP_H_ - -#include - -#include "atom/browser/api/event_emitter.h" -#include "atom/browser/atom_browser_client.h" -#include "atom/browser/browser_observer.h" -#include "atom/common/native_mate_converters/callback.h" -#include "chrome/browser/process_singleton.h" -#include "content/public/browser/gpu_data_manager_observer.h" -#include "native_mate/handle.h" -#include "net/base/completion_callback.h" - -#if defined(USE_NSS_CERTS) -#include "chrome/browser/certificate_manager_model.h" -#endif - -namespace base { -class FilePath; -} - -namespace mate { -class Arguments; -} - -namespace atom { - -namespace api { - -class App : public AtomBrowserClient::Delegate, - public mate::EventEmitter, - public BrowserObserver, - public content::GpuDataManagerObserver { - public: - static mate::Handle Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - // Called when window with disposition needs to be created. - void OnCreateWindow(const GURL& target_url, - const std::string& frame_name, - WindowOpenDisposition disposition, - int render_process_id, - int render_frame_id); - -#if defined(USE_NSS_CERTS) - void OnCertificateManagerModelCreated( - std::unique_ptr options, - const net::CompletionCallback& callback, - std::unique_ptr model); -#endif - - protected: - explicit App(v8::Isolate* isolate); - ~App() override; - - // BrowserObserver: - void OnBeforeQuit(bool* prevent_default) override; - void OnWillQuit(bool* prevent_default) override; - void OnWindowAllClosed() override; - void OnQuit() override; - void OnOpenFile(bool* prevent_default, const std::string& file_path) override; - void OnOpenURL(const std::string& url) override; - void OnActivate(bool has_visible_windows) override; - void OnWillFinishLaunching() override; - void OnFinishLaunching() override; - void OnLogin(LoginHandler* login_handler, - const base::DictionaryValue& request_details) override; - void OnAccessibilitySupportChanged() override; -#if defined(OS_MACOSX) - void OnContinueUserActivity( - bool* prevent_default, - const std::string& type, - const base::DictionaryValue& user_info) override; -#endif - - // content::ContentBrowserClient: - void AllowCertificateError( - content::WebContents* web_contents, - int cert_error, - const net::SSLInfo& ssl_info, - const GURL& request_url, - content::ResourceType resource_type, - bool overridable, - bool strict_enforcement, - bool expired_previous_decision, - const base::Callback& callback, - content::CertificateRequestResultType* request) override; - void SelectClientCertificate( - content::WebContents* web_contents, - net::SSLCertRequestInfo* cert_request_info, - std::unique_ptr delegate) override; - - // content::GpuDataManagerObserver: - void OnGpuProcessCrashed(base::TerminationStatus exit_code) override; - - private: - // Get/Set the pre-defined path in PathService. - base::FilePath GetPath(mate::Arguments* args, const std::string& name); - void SetPath(mate::Arguments* args, - const std::string& name, - const base::FilePath& path); - - void SetDesktopName(const std::string& desktop_name); - std::string GetLocale(); - bool MakeSingleInstance( - const ProcessSingleton::NotificationCallback& callback); - void ReleaseSingleInstance(); - bool Relaunch(mate::Arguments* args); - void DisableHardwareAcceleration(mate::Arguments* args); - bool IsAccessibilitySupportEnabled(); -#if defined(USE_NSS_CERTS) - void ImportCertificate(const base::DictionaryValue& options, - const net::CompletionCallback& callback); -#endif - - std::unique_ptr process_singleton_; - -#if defined(USE_NSS_CERTS) - std::unique_ptr certificate_manager_model_; -#endif - - DISALLOW_COPY_AND_ASSIGN(App); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_APP_H_ diff --git a/atom/browser/api/atom_api_auto_updater.cc b/atom/browser/api/atom_api_auto_updater.cc deleted file mode 100644 index 83e5505a1953c..0000000000000 --- a/atom/browser/api/atom_api_auto_updater.cc +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_auto_updater.h" - -#include "base/time/time.h" -#include "atom/browser/browser.h" -#include "atom/browser/native_window.h" -#include "atom/browser/window_list.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/node_includes.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const base::Time& val) { - v8::MaybeLocal date = v8::Date::New( - isolate->GetCurrentContext(), val.ToJsTime()); - if (date.IsEmpty()) - return v8::Null(isolate); - else - return date.ToLocalChecked(); - } -}; - -} // namespace mate - -namespace atom { - -namespace api { - -AutoUpdater::AutoUpdater(v8::Isolate* isolate) { - auto_updater::AutoUpdater::SetDelegate(this); - Init(isolate); -} - -AutoUpdater::~AutoUpdater() { - auto_updater::AutoUpdater::SetDelegate(nullptr); -} - -void AutoUpdater::OnError(const std::string& message) { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - auto error = v8::Exception::Error(mate::StringToV8(isolate(), message)); - EmitCustomEvent( - "error", - error->ToObject(isolate()->GetCurrentContext()).ToLocalChecked(), - // Message is also emitted to keep compatibility with old code. - message); -} - -void AutoUpdater::OnCheckingForUpdate() { - Emit("checking-for-update"); -} - -void AutoUpdater::OnUpdateAvailable() { - Emit("update-available"); -} - -void AutoUpdater::OnUpdateNotAvailable() { - Emit("update-not-available"); -} - -void AutoUpdater::OnUpdateDownloaded(const std::string& release_notes, - const std::string& release_name, - const base::Time& release_date, - const std::string& url) { - Emit("update-downloaded", release_notes, release_name, release_date, url, - // Keep compatibility with old APIs. - base::Bind(&AutoUpdater::QuitAndInstall, base::Unretained(this))); -} - -void AutoUpdater::OnWindowAllClosed() { - QuitAndInstall(); -} - -void AutoUpdater::SetFeedURL(const std::string& url, mate::Arguments* args) { - auto_updater::AutoUpdater::HeaderMap headers; - args->GetNext(&headers); - auto_updater::AutoUpdater::SetFeedURL(url, headers); -} - -void AutoUpdater::QuitAndInstall() { - // If we don't have any window then quitAndInstall immediately. - WindowList* window_list = WindowList::GetInstance(); - if (window_list->size() == 0) { - auto_updater::AutoUpdater::QuitAndInstall(); - return; - } - - // Otherwise do the restart after all windows have been closed. - window_list->AddObserver(this); - for (NativeWindow* window : *window_list) - window->Close(); -} - -// static -mate::Handle AutoUpdater::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new AutoUpdater(isolate)); -} - -// static -void AutoUpdater::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "AutoUpdater")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("checkForUpdates", &auto_updater::AutoUpdater::CheckForUpdates) - .SetMethod("getFeedURL", &auto_updater::AutoUpdater::GetFeedURL) - .SetMethod("setFeedURL", &AutoUpdater::SetFeedURL) - .SetMethod("quitAndInstall", &AutoUpdater::QuitAndInstall); -} - -} // namespace api - -} // namespace atom - - -namespace { - -using atom::api::AutoUpdater; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("autoUpdater", AutoUpdater::Create(isolate)); - dict.Set("AutoUpdater", AutoUpdater::GetConstructor(isolate)->GetFunction()); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_auto_updater, Initialize) diff --git a/atom/browser/api/atom_api_auto_updater.h b/atom/browser/api/atom_api_auto_updater.h deleted file mode 100644 index 83a66146a3fb5..0000000000000 --- a/atom/browser/api/atom_api_auto_updater.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_AUTO_UPDATER_H_ -#define ATOM_BROWSER_API_ATOM_API_AUTO_UPDATER_H_ - -#include - -#include "atom/browser/api/event_emitter.h" -#include "atom/browser/auto_updater.h" -#include "atom/browser/window_list_observer.h" -#include "native_mate/arguments.h" -#include "native_mate/handle.h" - -namespace atom { - -namespace api { - -class AutoUpdater : public mate::EventEmitter, - public auto_updater::Delegate, - public WindowListObserver { - public: - static mate::Handle Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - explicit AutoUpdater(v8::Isolate* isolate); - ~AutoUpdater() override; - - // Delegate implementations. - void OnError(const std::string& error) override; - void OnCheckingForUpdate() override; - void OnUpdateAvailable() override; - void OnUpdateNotAvailable() override; - void OnUpdateDownloaded(const std::string& release_notes, - const std::string& release_name, - const base::Time& release_date, - const std::string& update_url) override; - - // WindowListObserver: - void OnWindowAllClosed() override; - - private: - std::string GetFeedURL(); - void SetFeedURL(const std::string& url, mate::Arguments* args); - void QuitAndInstall(); - - DISALLOW_COPY_AND_ASSIGN(AutoUpdater); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_AUTO_UPDATER_H_ diff --git a/atom/browser/api/atom_api_content_tracing.cc b/atom/browser/api/atom_api_content_tracing.cc deleted file mode 100644 index 937a87ea21311..0000000000000 --- a/atom/browser/api/atom_api_content_tracing.cc +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include -#include - -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/node_includes.h" -#include "base/bind.h" -#include "base/files/file_util.h" -#include "content/public/browser/tracing_controller.h" -#include "native_mate/dictionary.h" - -using content::TracingController; - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - base::trace_event::TraceConfig* out) { - Dictionary options; - if (!ConvertFromV8(isolate, val, &options)) - return false; - std::string category_filter, trace_options; - if (!options.Get("categoryFilter", &category_filter) || - !options.Get("traceOptions", &trace_options)) - return false; - *out = base::trace_event::TraceConfig(category_filter, trace_options); - return true; - } -}; - -} // namespace mate - -namespace { - -using CompletionCallback = base::Callback; - -scoped_refptr GetTraceDataSink( - const base::FilePath& path, const CompletionCallback& callback) { - base::FilePath result_file_path = path; - if (result_file_path.empty() && !base::CreateTemporaryFile(&result_file_path)) - LOG(ERROR) << "Creating temporary file failed"; - - return TracingController::CreateFileSink(result_file_path, - base::Bind(callback, - result_file_path)); -} - -void StopRecording(const base::FilePath& path, - const CompletionCallback& callback) { - TracingController::GetInstance()->StopTracing( - GetTraceDataSink(path, callback)); -} - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - auto controller = base::Unretained(TracingController::GetInstance()); - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("getCategories", base::Bind( - &TracingController::GetCategories, controller)); - dict.SetMethod("startRecording", base::Bind( - &TracingController::StartTracing, controller)); - dict.SetMethod("stopRecording", &StopRecording); - dict.SetMethod("getTraceBufferUsage", base::Bind( - &TracingController::GetTraceBufferUsage, controller)); - dict.SetMethod("setWatchEvent", base::Bind( - &TracingController::SetWatchEvent, controller)); - dict.SetMethod("cancelWatchEvent", base::Bind( - &TracingController::CancelWatchEvent, controller)); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_content_tracing, Initialize) diff --git a/atom/browser/api/atom_api_cookies.cc b/atom/browser/api/atom_api_cookies.cc deleted file mode 100644 index 86cc59847b247..0000000000000 --- a/atom/browser/api/atom_api_cookies.cc +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_cookies.h" - -#include "atom/browser/atom_browser_context.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "base/time/time.h" -#include "base/values.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" -#include "net/cookies/cookie_monster.h" -#include "net/cookies/cookie_store.h" -#include "net/cookies/cookie_util.h" -#include "net/url_request/url_request_context.h" -#include "net/url_request/url_request_context_getter.h" - -using content::BrowserThread; - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - atom::api::Cookies::Error val) { - if (val == atom::api::Cookies::SUCCESS) - return v8::Null(isolate); - else - return v8::Exception::Error(StringToV8(isolate, "Setting cookie failed")); - } -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const net::CanonicalCookie& val) { - mate::Dictionary dict(isolate, v8::Object::New(isolate)); - dict.Set("name", val.Name()); - dict.Set("value", val.Value()); - dict.Set("domain", val.Domain()); - dict.Set("hostOnly", net::cookie_util::DomainIsHostOnly(val.Domain())); - dict.Set("path", val.Path()); - dict.Set("secure", val.IsSecure()); - dict.Set("httpOnly", val.IsHttpOnly()); - dict.Set("session", !val.IsPersistent()); - if (val.IsPersistent()) - dict.Set("expirationDate", val.ExpiryDate().ToDoubleT()); - return dict.GetHandle(); - } -}; - -} // namespace mate - -namespace atom { - -namespace api { - -namespace { - -// Returns whether |domain| matches |filter|. -bool MatchesDomain(std::string filter, const std::string& domain) { - // Add a leading '.' character to the filter domain if it doesn't exist. - if (net::cookie_util::DomainIsHostOnly(filter)) - filter.insert(0, "."); - - std::string sub_domain(domain); - // Strip any leading '.' character from the input cookie domain. - if (!net::cookie_util::DomainIsHostOnly(sub_domain)) - sub_domain = sub_domain.substr(1); - - // Now check whether the domain argument is a subdomain of the filter domain. - for (sub_domain.insert(0, "."); sub_domain.length() >= filter.length();) { - if (sub_domain == filter) - return true; - const size_t next_dot = sub_domain.find('.', 1); // Skip over leading dot. - sub_domain.erase(0, next_dot); - } - return false; -} - -// Returns whether |cookie| matches |filter|. -bool MatchesCookie(const base::DictionaryValue* filter, - const net::CanonicalCookie& cookie) { - std::string str; - bool b; - if (filter->GetString("name", &str) && str != cookie.Name()) - return false; - if (filter->GetString("path", &str) && str != cookie.Path()) - return false; - if (filter->GetString("domain", &str) && !MatchesDomain(str, cookie.Domain())) - return false; - if (filter->GetBoolean("secure", &b) && b != cookie.IsSecure()) - return false; - if (filter->GetBoolean("session", &b) && b != !cookie.IsPersistent()) - return false; - return true; -} - -// Helper to returns the CookieStore. -inline net::CookieStore* GetCookieStore( - scoped_refptr getter) { - return getter->GetURLRequestContext()->cookie_store(); -} - -// Run |callback| on UI thread. -void RunCallbackInUI(const base::Closure& callback) { - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); -} - -// Remove cookies from |list| not matching |filter|, and pass it to |callback|. -void FilterCookies(std::unique_ptr filter, - const Cookies::GetCallback& callback, - const net::CookieList& list) { - net::CookieList result; - for (const auto& cookie : list) { - if (MatchesCookie(filter.get(), cookie)) - result.push_back(cookie); - } - RunCallbackInUI(base::Bind(callback, Cookies::SUCCESS, result)); -} - -// Receives cookies matching |filter| in IO thread. -void GetCookiesOnIO(scoped_refptr getter, - std::unique_ptr filter, - const Cookies::GetCallback& callback) { - std::string url; - filter->GetString("url", &url); - - auto filtered_callback = - base::Bind(FilterCookies, base::Passed(&filter), callback); - - // Empty url will match all url cookies. - if (url.empty()) - GetCookieStore(getter)->GetAllCookiesAsync(filtered_callback); - else - GetCookieStore(getter)->GetAllCookiesForURLAsync(GURL(url), - filtered_callback); -} - -// Removes cookie with |url| and |name| in IO thread. -void RemoveCookieOnIOThread(scoped_refptr getter, - const GURL& url, const std::string& name, - const base::Closure& callback) { - GetCookieStore(getter)->DeleteCookieAsync( - url, name, base::Bind(RunCallbackInUI, callback)); -} - -// Callback of SetCookie. -void OnSetCookie(const Cookies::SetCallback& callback, bool success) { - RunCallbackInUI( - base::Bind(callback, success ? Cookies::SUCCESS : Cookies::FAILED)); -} - -// Sets cookie with |details| in IO thread. -void SetCookieOnIO(scoped_refptr getter, - std::unique_ptr details, - const Cookies::SetCallback& callback) { - std::string url, name, value, domain, path; - bool secure = false; - bool http_only = false; - double creation_date; - double expiration_date; - double last_access_date; - details->GetString("url", &url); - details->GetString("name", &name); - details->GetString("value", &value); - details->GetString("domain", &domain); - details->GetString("path", &path); - details->GetBoolean("secure", &secure); - details->GetBoolean("httpOnly", &http_only); - - base::Time creation_time; - if (details->GetDouble("creationDate", &creation_date)) { - creation_time = (creation_date == 0) ? - base::Time::UnixEpoch() : - base::Time::FromDoubleT(creation_date); - } - - base::Time expiration_time; - if (details->GetDouble("expirationDate", &expiration_date)) { - expiration_time = (expiration_date == 0) ? - base::Time::UnixEpoch() : - base::Time::FromDoubleT(expiration_date); - } - - base::Time last_access_time; - if (details->GetDouble("lastAccessDate", &last_access_date)) { - last_access_time = (last_access_date == 0) ? - base::Time::UnixEpoch() : - base::Time::FromDoubleT(last_access_date); - } - - GetCookieStore(getter)->SetCookieWithDetailsAsync( - GURL(url), name, value, domain, path, creation_time, - expiration_time, last_access_time, secure, http_only, - net::CookieSameSite::DEFAULT_MODE, false, - net::COOKIE_PRIORITY_DEFAULT, base::Bind(OnSetCookie, callback)); -} - -} // namespace - -Cookies::Cookies(v8::Isolate* isolate, - AtomBrowserContext* browser_context) - : request_context_getter_(browser_context->url_request_context_getter()) { - Init(isolate); -} - -Cookies::~Cookies() { -} - -void Cookies::Get(const base::DictionaryValue& filter, - const GetCallback& callback) { - std::unique_ptr copied(filter.CreateDeepCopy()); - auto getter = make_scoped_refptr(request_context_getter_); - content::BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(GetCookiesOnIO, getter, Passed(&copied), callback)); -} - -void Cookies::Remove(const GURL& url, const std::string& name, - const base::Closure& callback) { - auto getter = make_scoped_refptr(request_context_getter_); - content::BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(RemoveCookieOnIOThread, getter, url, name, callback)); -} - -void Cookies::Set(const base::DictionaryValue& details, - const SetCallback& callback) { - std::unique_ptr copied(details.CreateDeepCopy()); - auto getter = make_scoped_refptr(request_context_getter_); - content::BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(SetCookieOnIO, getter, Passed(&copied), callback)); -} - -// static -mate::Handle Cookies::Create( - v8::Isolate* isolate, - AtomBrowserContext* browser_context) { - return mate::CreateHandle(isolate, new Cookies(isolate, browser_context)); -} - -// static -void Cookies::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "Cookies")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("get", &Cookies::Get) - .SetMethod("remove", &Cookies::Remove) - .SetMethod("set", &Cookies::Set); -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/atom_api_cookies.h b/atom/browser/api/atom_api_cookies.h deleted file mode 100644 index 5f60cb7ab49d4..0000000000000 --- a/atom/browser/api/atom_api_cookies.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_COOKIES_H_ -#define ATOM_BROWSER_API_ATOM_API_COOKIES_H_ - -#include - -#include "atom/browser/api/trackable_object.h" -#include "base/callback.h" -#include "native_mate/handle.h" -#include "net/cookies/canonical_cookie.h" - -namespace base { -class DictionaryValue; -} - -namespace net { -class URLRequestContextGetter; -} - -namespace atom { - -class AtomBrowserContext; - -namespace api { - -class Cookies : public mate::TrackableObject { - public: - enum Error { - SUCCESS, - FAILED, - }; - - using GetCallback = base::Callback; - using SetCallback = base::Callback; - - static mate::Handle Create(v8::Isolate* isolate, - AtomBrowserContext* browser_context); - - // mate::TrackableObject: - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - Cookies(v8::Isolate* isolate, AtomBrowserContext* browser_context); - ~Cookies() override; - - void Get(const base::DictionaryValue& filter, const GetCallback& callback); - void Remove(const GURL& url, const std::string& name, - const base::Closure& callback); - void Set(const base::DictionaryValue& details, const SetCallback& callback); - - private: - net::URLRequestContextGetter* request_context_getter_; - - DISALLOW_COPY_AND_ASSIGN(Cookies); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_COOKIES_H_ diff --git a/atom/browser/api/atom_api_debugger.cc b/atom/browser/api/atom_api_debugger.cc deleted file mode 100644 index 88d2a7adf4a79..0000000000000 --- a/atom/browser/api/atom_api_debugger.cc +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_debugger.h" - -#include - -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_includes.h" -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" -#include "content/public/browser/devtools_agent_host.h" -#include "content/public/browser/web_contents.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" - -using content::DevToolsAgentHost; - -namespace atom { - -namespace api { - -Debugger::Debugger(v8::Isolate* isolate, content::WebContents* web_contents) - : web_contents_(web_contents), - previous_request_id_(0) { - Init(isolate); -} - -Debugger::~Debugger() { -} - -void Debugger::AgentHostClosed(DevToolsAgentHost* agent_host, - bool replaced_with_another_client) { - std::string detach_reason = "target closed"; - if (replaced_with_another_client) - detach_reason = "replaced with devtools"; - Emit("detach", detach_reason); -} - -void Debugger::DispatchProtocolMessage(DevToolsAgentHost* agent_host, - const std::string& message) { - DCHECK(agent_host == agent_host_.get()); - - std::unique_ptr parsed_message(base::JSONReader::Read(message)); - if (!parsed_message->IsType(base::Value::TYPE_DICTIONARY)) - return; - - base::DictionaryValue* dict = - static_cast(parsed_message.get()); - int id; - if (!dict->GetInteger("id", &id)) { - std::string method; - if (!dict->GetString("method", &method)) - return; - base::DictionaryValue* params_value = nullptr; - base::DictionaryValue params; - if (dict->GetDictionary("params", ¶ms_value)) - params.Swap(params_value); - Emit("message", method, params); - } else { - auto send_command_callback = pending_requests_[id]; - pending_requests_.erase(id); - if (send_command_callback.is_null()) - return; - base::DictionaryValue* error_body = nullptr; - base::DictionaryValue error; - if (dict->GetDictionary("error", &error_body)) - error.Swap(error_body); - - base::DictionaryValue* result_body = nullptr; - base::DictionaryValue result; - if (dict->GetDictionary("result", &result_body)) - result.Swap(result_body); - send_command_callback.Run(error, result); - } -} - -void Debugger::Attach(mate::Arguments* args) { - std::string protocol_version; - args->GetNext(&protocol_version); - - if (!protocol_version.empty() && - !DevToolsAgentHost::IsSupportedProtocolVersion(protocol_version)) { - args->ThrowError("Requested protocol version is not supported"); - return; - } - agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents_); - if (!agent_host_.get()) { - args->ThrowError("No target available"); - return; - } - if (agent_host_->IsAttached()) { - args->ThrowError("Another debugger is already attached to this target"); - return; - } - - agent_host_->AttachClient(this); -} - -bool Debugger::IsAttached() { - return agent_host_.get() ? agent_host_->IsAttached() : false; -} - -void Debugger::Detach() { - if (!agent_host_.get()) - return; - agent_host_->DetachClient(); - AgentHostClosed(agent_host_.get(), false); - agent_host_ = nullptr; -} - -void Debugger::SendCommand(mate::Arguments* args) { - if (!agent_host_.get()) - return; - - std::string method; - if (!args->GetNext(&method)) { - args->ThrowError(); - return; - } - base::DictionaryValue command_params; - args->GetNext(&command_params); - SendCommandCallback callback; - args->GetNext(&callback); - - base::DictionaryValue request; - int request_id = ++previous_request_id_; - pending_requests_[request_id] = callback; - request.SetInteger("id", request_id); - request.SetString("method", method); - if (!command_params.empty()) - request.Set("params", command_params.DeepCopy()); - - std::string json_args; - base::JSONWriter::Write(request, &json_args); - agent_host_->DispatchProtocolMessage(json_args); -} - -// static -mate::Handle Debugger::Create( - v8::Isolate* isolate, - content::WebContents* web_contents) { - return mate::CreateHandle(isolate, new Debugger(isolate, web_contents)); -} - -// static -void Debugger::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "Debugger")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("attach", &Debugger::Attach) - .SetMethod("isAttached", &Debugger::IsAttached) - .SetMethod("detach", &Debugger::Detach) - .SetMethod("sendCommand", &Debugger::SendCommand); -} - -} // namespace api - -} // namespace atom - -namespace { - -using atom::api::Debugger; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary(isolate, exports) - .Set("Debugger", Debugger::GetConstructor(isolate)->GetFunction()); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_debugger, Initialize); diff --git a/atom/browser/api/atom_api_debugger.h b/atom/browser/api/atom_api_debugger.h deleted file mode 100644 index 2f7106efd7ede..0000000000000 --- a/atom/browser/api/atom_api_debugger.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_DEBUGGER_H_ -#define ATOM_BROWSER_API_ATOM_API_DEBUGGER_H_ - -#include -#include - -#include "atom/browser/api/trackable_object.h" -#include "base/callback.h" -#include "base/values.h" -#include "content/public/browser/devtools_agent_host_client.h" -#include "native_mate/handle.h" - -namespace content { -class DevToolsAgentHost; -class WebContents; -} - -namespace mate { -class Arguments; -} - -namespace atom { - -namespace api { - -class Debugger: public mate::TrackableObject, - public content::DevToolsAgentHostClient { - public: - using SendCommandCallback = - base::Callback; - - static mate::Handle Create( - v8::Isolate* isolate, content::WebContents* web_contents); - - // mate::TrackableObject: - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - Debugger(v8::Isolate* isolate, content::WebContents* web_contents); - ~Debugger() override; - - // content::DevToolsAgentHostClient: - void AgentHostClosed(content::DevToolsAgentHost* agent_host, - bool replaced_with_another_client) override; - void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host, - const std::string& message) override; - - private: - using PendingRequestMap = std::map; - - void Attach(mate::Arguments* args); - bool IsAttached(); - void Detach(); - void SendCommand(mate::Arguments* args); - - content::WebContents* web_contents_; // Weak Reference. - scoped_refptr agent_host_; - - PendingRequestMap pending_requests_; - int previous_request_id_; - - DISALLOW_COPY_AND_ASSIGN(Debugger); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_DEBUGGER_H_ diff --git a/atom/browser/api/atom_api_desktop_capturer.cc b/atom/browser/api/atom_api_desktop_capturer.cc deleted file mode 100644 index 1ff5aadc0fac6..0000000000000 --- a/atom/browser/api/atom_api_desktop_capturer.cc +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_desktop_capturer.h" - -#include "atom/common/api/atom_api_native_image.h" -#include "atom/common/native_mate_converters/gfx_converter.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/media/desktop_media_list.h" -#include "native_mate/dictionary.h" -#include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" -#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" -#include "third_party/webrtc/modules/desktop_capture/window_capturer.h" - -#include "atom/common/node_includes.h" - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const DesktopMediaList::Source& source) { - mate::Dictionary dict(isolate, v8::Object::New(isolate)); - content::DesktopMediaID id = source.id; - dict.Set("name", base::UTF16ToUTF8(source.name)); - dict.Set("id", id.ToString()); - dict.Set( - "thumbnail", - atom::api::NativeImage::Create(isolate, gfx::Image(source.thumbnail))); - return ConvertToV8(isolate, dict); - } -}; - -} // namespace mate - -namespace atom { - -namespace api { - -DesktopCapturer::DesktopCapturer(v8::Isolate* isolate) { - Init(isolate); -} - -DesktopCapturer::~DesktopCapturer() { -} - -void DesktopCapturer::StartHandling(bool capture_window, - bool capture_screen, - const gfx::Size& thumbnail_size) { - webrtc::DesktopCaptureOptions options = - webrtc::DesktopCaptureOptions::CreateDefault(); - -#if defined(OS_WIN) - // On windows, desktop effects (e.g. Aero) will be disabled when the Desktop - // capture API is active by default. - // We keep the desktop effects in most times. Howerver, the screen still - // fickers when the API is capturing the window due to limitation of current - // implemetation. This is a known and wontFix issue in webrtc (see: - // http://code.google.com/p/webrtc/issues/detail?id=3373) - options.set_disable_effects(false); -#endif - - std::unique_ptr screen_capturer( - capture_screen ? webrtc::ScreenCapturer::Create(options) : nullptr); - std::unique_ptr window_capturer( - capture_window ? webrtc::WindowCapturer::Create(options) : nullptr); - media_list_.reset(new NativeDesktopMediaList( - std::move(screen_capturer), std::move(window_capturer))); - - media_list_->SetThumbnailSize(thumbnail_size); - media_list_->StartUpdating(this); -} - -void DesktopCapturer::OnSourceAdded(int index) { -} - -void DesktopCapturer::OnSourceRemoved(int index) { -} - -void DesktopCapturer::OnSourceMoved(int old_index, int new_index) { -} - -void DesktopCapturer::OnSourceNameChanged(int index) { -} - -void DesktopCapturer::OnSourceThumbnailChanged(int index) { -} - -bool DesktopCapturer::OnRefreshFinished() { - Emit("finished", media_list_->GetSources()); - return false; -} - -// static -mate::Handle DesktopCapturer::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new DesktopCapturer(isolate)); -} - -// static -void DesktopCapturer::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "DesktopCapturer")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("startHandling", &DesktopCapturer::StartHandling); -} - -} // namespace api - -} // namespace atom - -namespace { - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("desktopCapturer", atom::api::DesktopCapturer::Create(isolate)); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_desktop_capturer, Initialize); diff --git a/atom/browser/api/atom_api_desktop_capturer.h b/atom/browser/api/atom_api_desktop_capturer.h deleted file mode 100644 index 571f08bcfc63c..0000000000000 --- a/atom/browser/api/atom_api_desktop_capturer.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_ -#define ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_ - -#include "atom/browser/api/event_emitter.h" -#include "chrome/browser/media/desktop_media_list_observer.h" -#include "chrome/browser/media/native_desktop_media_list.h" -#include "native_mate/handle.h" - -namespace atom { - -namespace api { - -class DesktopCapturer: public mate::EventEmitter, - public DesktopMediaListObserver { - public: - static mate::Handle Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - void StartHandling(bool capture_window, - bool capture_screen, - const gfx::Size& thumbnail_size); - - protected: - explicit DesktopCapturer(v8::Isolate* isolate); - ~DesktopCapturer() override; - - // DesktopMediaListObserver overrides. - void OnSourceAdded(int index) override; - void OnSourceRemoved(int index) override; - void OnSourceMoved(int old_index, int new_index) override; - void OnSourceNameChanged(int index) override; - void OnSourceThumbnailChanged(int index) override; - bool OnRefreshFinished() override; - - private: - std::unique_ptr media_list_; - - DISALLOW_COPY_AND_ASSIGN(DesktopCapturer); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_DESKTOP_CAPTURER_H_ diff --git a/atom/browser/api/atom_api_dialog.cc b/atom/browser/api/atom_api_dialog.cc deleted file mode 100644 index 5d853e2d59006..0000000000000 --- a/atom/browser/api/atom_api_dialog.cc +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include -#include -#include - -#include "atom/browser/api/atom_api_window.h" -#include "atom/browser/native_window.h" -#include "atom/browser/ui/file_dialog.h" -#include "atom/browser/ui/message_box.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/native_mate_converters/image_converter.h" -#include "native_mate/dictionary.h" - -#include "atom/common/node_includes.h" - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - file_dialog::Filter* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - if (!dict.Get("name", &(out->first))) - return false; - if (!dict.Get("extensions", &(out->second))) - return false; - return true; - } -}; - -} // namespace mate - -namespace { - -void ShowMessageBox(int type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon, - atom::NativeWindow* window, - mate::Arguments* args) { - v8::Local peek = args->PeekNext(); - atom::MessageBoxCallback callback; - if (mate::Converter::FromV8(args->isolate(), - peek, - &callback)) { - atom::ShowMessageBox(window, (atom::MessageBoxType)type, buttons, - default_id, cancel_id, options, title, - message, detail, icon, callback); - } else { - int chosen = atom::ShowMessageBox(window, (atom::MessageBoxType)type, - buttons, default_id, cancel_id, - options, title, message, detail, icon); - args->Return(chosen); - } -} - -void ShowOpenDialog(const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const file_dialog::Filters& filters, - int properties, - atom::NativeWindow* window, - mate::Arguments* args) { - v8::Local peek = args->PeekNext(); - file_dialog::OpenDialogCallback callback; - if (mate::Converter::FromV8(args->isolate(), - peek, - &callback)) { - file_dialog::ShowOpenDialog(window, title, button_label, default_path, - filters, properties, callback); - } else { - std::vector paths; - if (file_dialog::ShowOpenDialog(window, title, button_label, default_path, - filters, properties, &paths)) - args->Return(paths); - } -} - -void ShowSaveDialog(const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const file_dialog::Filters& filters, - atom::NativeWindow* window, - mate::Arguments* args) { - v8::Local peek = args->PeekNext(); - file_dialog::SaveDialogCallback callback; - if (mate::Converter::FromV8(args->isolate(), - peek, - &callback)) { - file_dialog::ShowSaveDialog(window, title, button_label, default_path, - filters, callback); - } else { - base::FilePath path; - if (file_dialog::ShowSaveDialog(window, title, button_label, default_path, - filters, &path)) - args->Return(path); - } -} - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("showMessageBox", &ShowMessageBox); - dict.SetMethod("showErrorBox", &atom::ShowErrorBox); - dict.SetMethod("showOpenDialog", &ShowOpenDialog); - dict.SetMethod("showSaveDialog", &ShowSaveDialog); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_dialog, Initialize) diff --git a/atom/browser/api/atom_api_download_item.cc b/atom/browser/api/atom_api_download_item.cc deleted file mode 100644 index 05261a64f087c..0000000000000 --- a/atom/browser/api/atom_api_download_item.cc +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_download_item.h" - -#include - -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/node_includes.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/utf_string_conversions.h" -#include "native_mate/dictionary.h" -#include "net/base/filename_util.h" - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - content::DownloadItem::DownloadState state) { - std::string download_state; - switch (state) { - case content::DownloadItem::IN_PROGRESS: - download_state = "progressing"; - break; - case content::DownloadItem::COMPLETE: - download_state = "completed"; - break; - case content::DownloadItem::CANCELLED: - download_state = "cancelled"; - break; - case content::DownloadItem::INTERRUPTED: - download_state = "interrupted"; - break; - default: - break; - } - return ConvertToV8(isolate, download_state); - } -}; - -} // namespace mate - -namespace atom { - -namespace api { - -namespace { - -std::map> g_download_item_objects; - -} // namespace - -DownloadItem::DownloadItem(v8::Isolate* isolate, - content::DownloadItem* download_item) - : download_item_(download_item) { - download_item_->AddObserver(this); - Init(isolate); - AttachAsUserData(download_item); -} - -DownloadItem::~DownloadItem() { - if (download_item_) { - // Destroyed by either garbage collection or destroy(). - download_item_->RemoveObserver(this); - download_item_->Remove(); - } - - // Remove from the global map. - g_download_item_objects.erase(weak_map_id()); -} - -void DownloadItem::OnDownloadUpdated(content::DownloadItem* item) { - if (download_item_->IsDone()) { - Emit("done", item->GetState()); - - // Destroy the item once item is downloaded. - base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure()); - } else { - Emit("updated", item->GetState()); - } -} - -void DownloadItem::OnDownloadDestroyed(content::DownloadItem* download_item) { - download_item_ = nullptr; - // Destroy the native class immediately when downloadItem is destroyed. - delete this; -} - -void DownloadItem::Pause() { - download_item_->Pause(); -} - -bool DownloadItem::IsPaused() const { - return download_item_->IsPaused(); -} - -void DownloadItem::Resume() { - download_item_->Resume(); -} - -bool DownloadItem::CanResume() const { - return download_item_->CanResume(); -} - -void DownloadItem::Cancel() { - download_item_->Cancel(true); - download_item_->Remove(); -} - -int64_t DownloadItem::GetReceivedBytes() const { - return download_item_->GetReceivedBytes(); -} - -int64_t DownloadItem::GetTotalBytes() const { - return download_item_->GetTotalBytes(); -} - -std::string DownloadItem::GetMimeType() const { - return download_item_->GetMimeType(); -} - -bool DownloadItem::HasUserGesture() const { - return download_item_->HasUserGesture(); -} - -std::string DownloadItem::GetFilename() const { - return base::UTF16ToUTF8(net::GenerateFileName(GetURL(), - GetContentDisposition(), - std::string(), - download_item_->GetSuggestedFilename(), - GetMimeType(), - std::string()).LossyDisplayName()); -} - -std::string DownloadItem::GetContentDisposition() const { - return download_item_->GetContentDisposition(); -} - -const GURL& DownloadItem::GetURL() const { - return download_item_->GetURL(); -} - -content::DownloadItem::DownloadState DownloadItem::GetState() const { - return download_item_->GetState(); -} - -bool DownloadItem::IsDone() const { - return download_item_->IsDone(); -} - -void DownloadItem::SetSavePath(const base::FilePath& path) { - save_path_ = path; -} - -base::FilePath DownloadItem::GetSavePath() const { - return save_path_; -} - -// static -void DownloadItem::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "DownloadItem")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .MakeDestroyable() - .SetMethod("pause", &DownloadItem::Pause) - .SetMethod("isPaused", &DownloadItem::IsPaused) - .SetMethod("resume", &DownloadItem::Resume) - .SetMethod("canResume", &DownloadItem::CanResume) - .SetMethod("cancel", &DownloadItem::Cancel) - .SetMethod("getReceivedBytes", &DownloadItem::GetReceivedBytes) - .SetMethod("getTotalBytes", &DownloadItem::GetTotalBytes) - .SetMethod("getMimeType", &DownloadItem::GetMimeType) - .SetMethod("hasUserGesture", &DownloadItem::HasUserGesture) - .SetMethod("getFilename", &DownloadItem::GetFilename) - .SetMethod("getContentDisposition", &DownloadItem::GetContentDisposition) - .SetMethod("getURL", &DownloadItem::GetURL) - .SetMethod("getState", &DownloadItem::GetState) - .SetMethod("isDone", &DownloadItem::IsDone) - .SetMethod("setSavePath", &DownloadItem::SetSavePath) - .SetMethod("getSavePath", &DownloadItem::GetSavePath); -} - -// static -mate::Handle DownloadItem::Create( - v8::Isolate* isolate, content::DownloadItem* item) { - auto existing = TrackableObject::FromWrappedClass(isolate, item); - if (existing) - return mate::CreateHandle(isolate, static_cast(existing)); - - auto handle = mate::CreateHandle(isolate, new DownloadItem(isolate, item)); - - // Reference this object in case it got garbage collected. - g_download_item_objects[handle->weak_map_id()] = - v8::Global(isolate, handle.ToV8()); - return handle; -} - -} // namespace api - -} // namespace atom - -namespace { - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary(isolate, exports) - .Set("DownloadItem", - atom::api::DownloadItem::GetConstructor(isolate)->GetFunction()); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_download_item, Initialize); diff --git a/atom/browser/api/atom_api_download_item.h b/atom/browser/api/atom_api_download_item.h deleted file mode 100644 index 332c8cebb8773..0000000000000 --- a/atom/browser/api/atom_api_download_item.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_ -#define ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_ - -#include - -#include "atom/browser/api/trackable_object.h" -#include "base/files/file_path.h" -#include "content/public/browser/download_item.h" -#include "native_mate/handle.h" -#include "url/gurl.h" - -namespace atom { - -namespace api { - -class DownloadItem : public mate::TrackableObject, - public content::DownloadItem::Observer { - public: - static mate::Handle Create(v8::Isolate* isolate, - content::DownloadItem* item); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - void Pause(); - bool IsPaused() const; - void Resume(); - bool CanResume() const; - void Cancel(); - int64_t GetReceivedBytes() const; - int64_t GetTotalBytes() const; - std::string GetMimeType() const; - bool HasUserGesture() const; - std::string GetFilename() const; - std::string GetContentDisposition() const; - const GURL& GetURL() const; - content::DownloadItem::DownloadState GetState() const; - bool IsDone() const; - void SetSavePath(const base::FilePath& path); - base::FilePath GetSavePath() const; - - protected: - DownloadItem(v8::Isolate* isolate, content::DownloadItem* download_item); - ~DownloadItem(); - - // Override content::DownloadItem::Observer methods - void OnDownloadUpdated(content::DownloadItem* download) override; - void OnDownloadDestroyed(content::DownloadItem* download) override; - - private: - base::FilePath save_path_; - content::DownloadItem* download_item_; - - DISALLOW_COPY_AND_ASSIGN(DownloadItem); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_DOWNLOAD_ITEM_H_ diff --git a/atom/browser/api/atom_api_global_shortcut.cc b/atom/browser/api/atom_api_global_shortcut.cc deleted file mode 100644 index 039d708a7c1cc..0000000000000 --- a/atom/browser/api/atom_api_global_shortcut.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_global_shortcut.h" - -#include - -#include "atom/common/native_mate_converters/accelerator_converter.h" -#include "atom/common/native_mate_converters/callback.h" -#include "base/stl_util.h" -#include "native_mate/dictionary.h" - -#include "atom/common/node_includes.h" - -using extensions::GlobalShortcutListener; - -namespace atom { - -namespace api { - -GlobalShortcut::GlobalShortcut(v8::Isolate* isolate) { - Init(isolate); -} - -GlobalShortcut::~GlobalShortcut() { - UnregisterAll(); -} - -void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) { - if (accelerator_callback_map_.find(accelerator) == - accelerator_callback_map_.end()) { - // This should never occur, because if it does, GlobalGlobalShortcutListener - // notifes us with wrong accelerator. - NOTREACHED(); - return; - } - accelerator_callback_map_[accelerator].Run(); -} - -bool GlobalShortcut::Register(const ui::Accelerator& accelerator, - const base::Closure& callback) { - if (!GlobalShortcutListener::GetInstance()->RegisterAccelerator( - accelerator, this)) { - return false; - } - - accelerator_callback_map_[accelerator] = callback; - return true; -} - -void GlobalShortcut::Unregister(const ui::Accelerator& accelerator) { - if (!ContainsKey(accelerator_callback_map_, accelerator)) - return; - - accelerator_callback_map_.erase(accelerator); - GlobalShortcutListener::GetInstance()->UnregisterAccelerator( - accelerator, this); -} - -bool GlobalShortcut::IsRegistered(const ui::Accelerator& accelerator) { - return ContainsKey(accelerator_callback_map_, accelerator); -} - -void GlobalShortcut::UnregisterAll() { - accelerator_callback_map_.clear(); - GlobalShortcutListener::GetInstance()->UnregisterAccelerators(this); -} - -// static -mate::Handle GlobalShortcut::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new GlobalShortcut(isolate)); -} - -// static -void GlobalShortcut::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "GlobalShortcut")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("register", &GlobalShortcut::Register) - .SetMethod("isRegistered", &GlobalShortcut::IsRegistered) - .SetMethod("unregister", &GlobalShortcut::Unregister) - .SetMethod("unregisterAll", &GlobalShortcut::UnregisterAll); -} - -} // namespace api - -} // namespace atom - -namespace { - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("globalShortcut", atom::api::GlobalShortcut::Create(isolate)); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_global_shortcut, Initialize) diff --git a/atom/browser/api/atom_api_global_shortcut.h b/atom/browser/api/atom_api_global_shortcut.h deleted file mode 100644 index b023aec4a8436..0000000000000 --- a/atom/browser/api/atom_api_global_shortcut.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_GLOBAL_SHORTCUT_H_ -#define ATOM_BROWSER_API_ATOM_API_GLOBAL_SHORTCUT_H_ - -#include -#include - -#include "atom/browser/api/trackable_object.h" -#include "base/callback.h" -#include "chrome/browser/extensions/global_shortcut_listener.h" -#include "native_mate/handle.h" -#include "ui/base/accelerators/accelerator.h" - -namespace atom { - -namespace api { - -class GlobalShortcut : public extensions::GlobalShortcutListener::Observer, - public mate::TrackableObject { - public: - static mate::Handle Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - explicit GlobalShortcut(v8::Isolate* isolate); - ~GlobalShortcut() override; - - private: - typedef std::map AcceleratorCallbackMap; - - bool Register(const ui::Accelerator& accelerator, - const base::Closure& callback); - bool IsRegistered(const ui::Accelerator& accelerator); - void Unregister(const ui::Accelerator& accelerator); - void UnregisterAll(); - - // GlobalShortcutListener::Observer implementation. - void OnKeyPressed(const ui::Accelerator& accelerator) override; - - AcceleratorCallbackMap accelerator_callback_map_; - - DISALLOW_COPY_AND_ASSIGN(GlobalShortcut); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_GLOBAL_SHORTCUT_H_ diff --git a/atom/browser/api/atom_api_menu.cc b/atom/browser/api/atom_api_menu.cc deleted file mode 100644 index 627ce601f54b0..0000000000000 --- a/atom/browser/api/atom_api_menu.cc +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_menu.h" - -#include "atom/browser/native_window.h" -#include "atom/common/native_mate_converters/accelerator_converter.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/image_converter.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "native_mate/constructor.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace api { - -Menu::Menu(v8::Isolate* isolate, v8::Local wrapper) - : model_(new AtomMenuModel(this)), - parent_(nullptr) { - InitWith(isolate, wrapper); -} - -Menu::~Menu() { -} - -void Menu::AfterInit(v8::Isolate* isolate) { - mate::Dictionary wrappable(isolate, GetWrapper()); - mate::Dictionary delegate; - if (!wrappable.Get("delegate", &delegate)) - return; - - delegate.Get("isCommandIdChecked", &is_checked_); - delegate.Get("isCommandIdEnabled", &is_enabled_); - delegate.Get("isCommandIdVisible", &is_visible_); - delegate.Get("getAcceleratorForCommandId", &get_accelerator_); - delegate.Get("executeCommand", &execute_command_); - delegate.Get("menuWillShow", &menu_will_show_); -} - -bool Menu::IsCommandIdChecked(int command_id) const { - return is_checked_.Run(command_id); -} - -bool Menu::IsCommandIdEnabled(int command_id) const { - return is_enabled_.Run(command_id); -} - -bool Menu::IsCommandIdVisible(int command_id) const { - return is_visible_.Run(command_id); -} - -bool Menu::GetAcceleratorForCommandIdWithParams( - int command_id, - bool use_default_accelerator, - ui::Accelerator* accelerator) const { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - v8::Local val = get_accelerator_.Run( - command_id, use_default_accelerator); - return mate::ConvertFromV8(isolate(), val, accelerator); -} - -void Menu::ExecuteCommand(int command_id, int flags) { - execute_command_.Run( - mate::internal::CreateEventFromFlags(isolate(), flags), - command_id); -} - -void Menu::MenuWillShow(ui::SimpleMenuModel* source) { - menu_will_show_.Run(); -} - -void Menu::InsertItemAt( - int index, int command_id, const base::string16& label) { - model_->InsertItemAt(index, command_id, label); -} - -void Menu::InsertSeparatorAt(int index) { - model_->InsertSeparatorAt(index, ui::NORMAL_SEPARATOR); -} - -void Menu::InsertCheckItemAt(int index, - int command_id, - const base::string16& label) { - model_->InsertCheckItemAt(index, command_id, label); -} - -void Menu::InsertRadioItemAt(int index, - int command_id, - const base::string16& label, - int group_id) { - model_->InsertRadioItemAt(index, command_id, label, group_id); -} - -void Menu::InsertSubMenuAt(int index, - int command_id, - const base::string16& label, - Menu* menu) { - menu->parent_ = this; - model_->InsertSubMenuAt(index, command_id, label, menu->model_.get()); -} - -void Menu::SetIcon(int index, const gfx::Image& image) { - model_->SetIcon(index, image); -} - -void Menu::SetSublabel(int index, const base::string16& sublabel) { - model_->SetSublabel(index, sublabel); -} - -void Menu::SetRole(int index, const base::string16& role) { - model_->SetRole(index, role); -} - -void Menu::Clear() { - model_->Clear(); -} - -int Menu::GetIndexOfCommandId(int command_id) { - return model_->GetIndexOfCommandId(command_id); -} - -int Menu::GetItemCount() const { - return model_->GetItemCount(); -} - -int Menu::GetCommandIdAt(int index) const { - return model_->GetCommandIdAt(index); -} - -base::string16 Menu::GetLabelAt(int index) const { - return model_->GetLabelAt(index); -} - -base::string16 Menu::GetSublabelAt(int index) const { - return model_->GetSublabelAt(index); -} - -bool Menu::IsItemCheckedAt(int index) const { - return model_->IsItemCheckedAt(index); -} - -bool Menu::IsEnabledAt(int index) const { - return model_->IsEnabledAt(index); -} - -bool Menu::IsVisibleAt(int index) const { - return model_->IsVisibleAt(index); -} - -// static -void Menu::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "Menu")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .MakeDestroyable() - .SetMethod("insertItem", &Menu::InsertItemAt) - .SetMethod("insertCheckItem", &Menu::InsertCheckItemAt) - .SetMethod("insertRadioItem", &Menu::InsertRadioItemAt) - .SetMethod("insertSeparator", &Menu::InsertSeparatorAt) - .SetMethod("insertSubMenu", &Menu::InsertSubMenuAt) - .SetMethod("setIcon", &Menu::SetIcon) - .SetMethod("setSublabel", &Menu::SetSublabel) - .SetMethod("setRole", &Menu::SetRole) - .SetMethod("clear", &Menu::Clear) - .SetMethod("getIndexOfCommandId", &Menu::GetIndexOfCommandId) - .SetMethod("getItemCount", &Menu::GetItemCount) - .SetMethod("getCommandIdAt", &Menu::GetCommandIdAt) - .SetMethod("getLabelAt", &Menu::GetLabelAt) - .SetMethod("getSublabelAt", &Menu::GetSublabelAt) - .SetMethod("isItemCheckedAt", &Menu::IsItemCheckedAt) - .SetMethod("isEnabledAt", &Menu::IsEnabledAt) - .SetMethod("isVisibleAt", &Menu::IsVisibleAt) - .SetMethod("popupAt", &Menu::PopupAt); -} - -} // namespace api - -} // namespace atom - - -namespace { - -using atom::api::Menu; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - Menu::SetConstructor(isolate, base::Bind(&Menu::New)); - - mate::Dictionary dict(isolate, exports); - dict.Set("Menu", Menu::GetConstructor(isolate)->GetFunction()); -#if defined(OS_MACOSX) - dict.SetMethod("setApplicationMenu", &Menu::SetApplicationMenu); - dict.SetMethod("sendActionToFirstResponder", - &Menu::SendActionToFirstResponder); -#endif -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_menu, Initialize) diff --git a/atom/browser/api/atom_api_menu.h b/atom/browser/api/atom_api_menu.h deleted file mode 100644 index 97b63600492c4..0000000000000 --- a/atom/browser/api/atom_api_menu.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_MENU_H_ -#define ATOM_BROWSER_API_ATOM_API_MENU_H_ - -#include -#include - -#include "atom/browser/api/atom_api_window.h" -#include "atom/browser/api/trackable_object.h" -#include "atom/browser/ui/atom_menu_model.h" -#include "base/callback.h" - -namespace atom { - -namespace api { - -class Menu : public mate::TrackableObject, - public AtomMenuModel::Delegate { - public: - static mate::WrappableBase* New(mate::Arguments* args); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - -#if defined(OS_MACOSX) - // Set the global menubar. - static void SetApplicationMenu(Menu* menu); - - // Fake sending an action from the application menu. - static void SendActionToFirstResponder(const std::string& action); -#endif - - AtomMenuModel* model() const { return model_.get(); } - - protected: - Menu(v8::Isolate* isolate, v8::Local wrapper); - ~Menu() override; - - // mate::Wrappable: - void AfterInit(v8::Isolate* isolate) override; - - // ui::SimpleMenuModel::Delegate: - bool IsCommandIdChecked(int command_id) const override; - bool IsCommandIdEnabled(int command_id) const override; - bool IsCommandIdVisible(int command_id) const override; - bool GetAcceleratorForCommandIdWithParams( - int command_id, - bool use_default_accelerator, - ui::Accelerator* accelerator) const override; - void ExecuteCommand(int command_id, int event_flags) override; - void MenuWillShow(ui::SimpleMenuModel* source) override; - - virtual void PopupAt(Window* window, - int x = -1, int y = -1, - int positioning_item = 0) = 0; - - std::unique_ptr model_; - Menu* parent_; - - private: - void InsertItemAt(int index, int command_id, const base::string16& label); - void InsertSeparatorAt(int index); - void InsertCheckItemAt(int index, - int command_id, - const base::string16& label); - void InsertRadioItemAt(int index, - int command_id, - const base::string16& label, - int group_id); - void InsertSubMenuAt(int index, - int command_id, - const base::string16& label, - Menu* menu); - void SetIcon(int index, const gfx::Image& image); - void SetSublabel(int index, const base::string16& sublabel); - void SetRole(int index, const base::string16& role); - void Clear(); - int GetIndexOfCommandId(int command_id); - int GetItemCount() const; - int GetCommandIdAt(int index) const; - base::string16 GetLabelAt(int index) const; - base::string16 GetSublabelAt(int index) const; - bool IsItemCheckedAt(int index) const; - bool IsEnabledAt(int index) const; - bool IsVisibleAt(int index) const; - - // Stored delegate methods. - base::Callback is_checked_; - base::Callback is_enabled_; - base::Callback is_visible_; - base::Callback(int, bool)> get_accelerator_; - base::Callback, int)> execute_command_; - base::Callback menu_will_show_; - - DISALLOW_COPY_AND_ASSIGN(Menu); -}; - -} // namespace api - -} // namespace atom - - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - atom::AtomMenuModel** out) { - // null would be tranfered to NULL. - if (val->IsNull()) { - *out = nullptr; - return true; - } - - atom::api::Menu* menu; - if (!Converter::FromV8(isolate, val, &menu)) - return false; - *out = menu->model(); - return true; - } -}; - -} // namespace mate - -#endif // ATOM_BROWSER_API_ATOM_API_MENU_H_ diff --git a/atom/browser/api/atom_api_menu_mac.h b/atom/browser/api/atom_api_menu_mac.h deleted file mode 100644 index d318b7bdc0554..0000000000000 --- a/atom/browser/api/atom_api_menu_mac.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_MENU_MAC_H_ -#define ATOM_BROWSER_API_ATOM_API_MENU_MAC_H_ - -#include "atom/browser/api/atom_api_menu.h" - -#include - -#import "atom/browser/ui/cocoa/atom_menu_controller.h" - -namespace atom { - -namespace api { - -class MenuMac : public Menu { - protected: - MenuMac(v8::Isolate* isolate, v8::Local wrapper); - - void PopupAt(Window* window, int x, int y, int positioning_item) override; - - base::scoped_nsobject menu_controller_; - - private: - friend class Menu; - - static void SendActionToFirstResponder(const std::string& action); - - DISALLOW_COPY_AND_ASSIGN(MenuMac); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_MENU_MAC_H_ diff --git a/atom/browser/api/atom_api_menu_mac.mm b/atom/browser/api/atom_api_menu_mac.mm deleted file mode 100644 index 9e901d10980ae..0000000000000 --- a/atom/browser/api/atom_api_menu_mac.mm +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#import "atom/browser/api/atom_api_menu_mac.h" - -#include "atom/browser/native_window.h" -#include "atom/browser/unresponsive_suppressor.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/sys_string_conversions.h" -#include "brightray/browser/inspectable_web_contents.h" -#include "brightray/browser/inspectable_web_contents_view.h" -#include "content/public/browser/web_contents.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace api { - -MenuMac::MenuMac(v8::Isolate* isolate, v8::Local wrapper) - : Menu(isolate, wrapper) { -} - -void MenuMac::PopupAt(Window* window, int x, int y, int positioning_item) { - NativeWindow* native_window = window->window(); - if (!native_window) - return; - brightray::InspectableWebContents* web_contents = - native_window->inspectable_web_contents(); - if (!web_contents) - return; - - base::scoped_nsobject menu_controller( - [[AtomMenuController alloc] initWithModel:model_.get() - useDefaultAccelerator:NO]); - NSMenu* menu = [menu_controller menu]; - NSView* view = web_contents->GetView()->GetNativeView(); - - // Which menu item to show. - NSMenuItem* item = nil; - if (positioning_item < [menu numberOfItems] && positioning_item >= 0) - item = [menu itemAtIndex:positioning_item]; - - // (-1, -1) means showing on mouse location. - NSPoint position; - if (x == -1 || y == -1) { - NSWindow* nswindow = native_window->GetNativeWindow(); - position = [view convertPoint:[nswindow mouseLocationOutsideOfEventStream] - fromView:nil]; - } else { - position = NSMakePoint(x, [view frame].size.height - y); - } - - // If no preferred item is specified, try to show all of the menu items. - if (!positioning_item) { - CGFloat windowBottom = CGRectGetMinY([view window].frame); - CGFloat lowestMenuPoint = windowBottom + position.y - [menu size].height; - CGFloat screenBottom = CGRectGetMinY([view window].screen.frame); - CGFloat distanceFromBottom = lowestMenuPoint - screenBottom; - if (distanceFromBottom < 0) - position.y = position.y - distanceFromBottom + 4; - } - - // Place the menu left of cursor if it is overflowing off right of screen. - CGFloat windowLeft = CGRectGetMinX([view window].frame); - CGFloat rightmostMenuPoint = windowLeft + position.x + [menu size].width; - CGFloat screenRight = CGRectGetMaxX([view window].screen.frame); - if (rightmostMenuPoint > screenRight) - position.x = position.x - [menu size].width; - - // Don't emit unresponsive event when showing menu. - atom::UnresponsiveSuppressor suppressor; - - // Show the menu. - [menu popUpMenuPositioningItem:item atLocation:position inView:view]; -} - -// static -void Menu::SetApplicationMenu(Menu* base_menu) { - MenuMac* menu = static_cast(base_menu); - base::scoped_nsobject menu_controller( - [[AtomMenuController alloc] initWithModel:menu->model_.get() - useDefaultAccelerator:YES]); - [NSApp setMainMenu:[menu_controller menu]]; - - // Ensure the menu_controller_ is destroyed after main menu is set. - menu_controller.swap(menu->menu_controller_); -} - -// static -void Menu::SendActionToFirstResponder(const std::string& action) { - SEL selector = NSSelectorFromString(base::SysUTF8ToNSString(action)); - [NSApp sendAction:selector to:nil from:[NSApp mainMenu]]; -} - -// static -mate::WrappableBase* Menu::New(mate::Arguments* args) { - return new MenuMac(args->isolate(), args->GetThis()); -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/atom_api_menu_views.cc b/atom/browser/api/atom_api_menu_views.cc deleted file mode 100644 index 8a72247c9d0b6..0000000000000 --- a/atom/browser/api/atom_api_menu_views.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_menu_views.h" - -#include "atom/browser/native_window_views.h" -#include "atom/browser/unresponsive_suppressor.h" -#include "content/public/browser/render_widget_host_view.h" -#include "ui/display/screen.h" -#include "ui/views/controls/menu/menu_runner.h" - -namespace atom { - -namespace api { - -MenuViews::MenuViews(v8::Isolate* isolate, v8::Local wrapper) - : Menu(isolate, wrapper) { -} - -void MenuViews::PopupAt(Window* window, int x, int y, int positioning_item) { - NativeWindow* native_window = static_cast(window->window()); - if (!native_window) - return; - content::WebContents* web_contents = native_window->web_contents(); - if (!web_contents) - return; - content::RenderWidgetHostView* view = web_contents->GetRenderWidgetHostView(); - if (!view) - return; - - // (-1, -1) means showing on mouse location. - gfx::Point location; - if (x == -1 || y == -1) { - location = display::Screen::GetScreen()->GetCursorScreenPoint(); - } else { - gfx::Point origin = view->GetViewBounds().origin(); - location = gfx::Point(origin.x() + x, origin.y() + y); - } - - // Don't emit unresponsive event when showing menu. - atom::UnresponsiveSuppressor suppressor; - - // Show the menu. - views::MenuRunner menu_runner( - model(), - views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS); - ignore_result(menu_runner.RunMenuAt( - static_cast(window->window())->widget(), - NULL, - gfx::Rect(location, gfx::Size()), - views::MENU_ANCHOR_TOPLEFT, - ui::MENU_SOURCE_MOUSE)); -} - -// static -mate::WrappableBase* Menu::New(mate::Arguments* args) { - return new MenuViews(args->isolate(), args->GetThis()); -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/atom_api_menu_views.h b/atom/browser/api/atom_api_menu_views.h deleted file mode 100644 index 1e7abd1372e20..0000000000000 --- a/atom/browser/api/atom_api_menu_views.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_ -#define ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_ - -#include "atom/browser/api/atom_api_menu.h" -#include "ui/display/screen.h" - -namespace atom { - -namespace api { - -class MenuViews : public Menu { - public: - MenuViews(v8::Isolate* isolate, v8::Local wrapper); - - protected: - void PopupAt(Window* window, int x, int y, int positioning_item) override; - - private: - DISALLOW_COPY_AND_ASSIGN(MenuViews); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_MENU_VIEWS_H_ diff --git a/atom/browser/api/atom_api_power_monitor.cc b/atom/browser/api/atom_api_power_monitor.cc deleted file mode 100644 index 02b61e8f4bb15..0000000000000 --- a/atom/browser/api/atom_api_power_monitor.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_power_monitor.h" - -#include "atom/browser/browser.h" -#include "atom/common/node_includes.h" -#include "base/power_monitor/power_monitor.h" -#include "base/power_monitor/power_monitor_device_source.h" -#include "native_mate/dictionary.h" - -namespace atom { - -namespace api { - -PowerMonitor::PowerMonitor(v8::Isolate* isolate) { - base::PowerMonitor::Get()->AddObserver(this); - Init(isolate); -} - -PowerMonitor::~PowerMonitor() { - base::PowerMonitor::Get()->RemoveObserver(this); -} - -void PowerMonitor::OnPowerStateChange(bool on_battery_power) { - if (on_battery_power) - Emit("on-battery"); - else - Emit("on-ac"); -} - -void PowerMonitor::OnSuspend() { - Emit("suspend"); -} - -void PowerMonitor::OnResume() { - Emit("resume"); -} - -// static -v8::Local PowerMonitor::Create(v8::Isolate* isolate) { - if (!Browser::Get()->is_ready()) { - isolate->ThrowException(v8::Exception::Error(mate::StringToV8( - isolate, - "Cannot initialize \"power-monitor\" module before app is ready"))); - return v8::Null(isolate); - } - - return mate::CreateHandle(isolate, new PowerMonitor(isolate)).ToV8(); -} - -// static -void PowerMonitor::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "PowerMonitor")); -} - -} // namespace api - -} // namespace atom - - -namespace { - -using atom::api::PowerMonitor; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { -#if defined(OS_MACOSX) - base::PowerMonitorDeviceSource::AllocateSystemIOPorts(); -#endif - - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("powerMonitor", PowerMonitor::Create(isolate)); - dict.Set("PowerMonitor", - PowerMonitor::GetConstructor(isolate)->GetFunction()); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_power_monitor, Initialize) diff --git a/atom/browser/api/atom_api_power_monitor.h b/atom/browser/api/atom_api_power_monitor.h deleted file mode 100644 index 94717e4c90892..0000000000000 --- a/atom/browser/api/atom_api_power_monitor.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_ -#define ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_ - -#include "atom/browser/api/trackable_object.h" -#include "base/compiler_specific.h" -#include "base/power_monitor/power_observer.h" -#include "native_mate/handle.h" - -namespace atom { - -namespace api { - -class PowerMonitor : public mate::TrackableObject, - public base::PowerObserver { - public: - static v8::Local Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - explicit PowerMonitor(v8::Isolate* isolate); - ~PowerMonitor() override; - - // base::PowerObserver implementations: - void OnPowerStateChange(bool on_battery_power) override; - void OnSuspend() override; - void OnResume() override; - - private: - DISALLOW_COPY_AND_ASSIGN(PowerMonitor); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_POWER_MONITOR_H_ diff --git a/atom/browser/api/atom_api_power_save_blocker.cc b/atom/browser/api/atom_api_power_save_blocker.cc deleted file mode 100644 index 0f017be5fb1d5..0000000000000 --- a/atom/browser/api/atom_api_power_save_blocker.cc +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_power_save_blocker.h" - -#include - -#include "atom/common/node_includes.h" -#include "content/public/browser/power_save_blocker.h" -#include "native_mate/dictionary.h" - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - content::PowerSaveBlocker::PowerSaveBlockerType* out) { - using content::PowerSaveBlocker; - std::string type; - if (!ConvertFromV8(isolate, val, &type)) - return false; - if (type == "prevent-app-suspension") - *out = PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension; - else if (type == "prevent-display-sleep") - *out = PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep; - else - return false; - return true; - } -}; - -} // namespace mate - -namespace atom { - -namespace api { - -PowerSaveBlocker::PowerSaveBlocker(v8::Isolate* isolate) - : current_blocker_type_( - content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension) { - Init(isolate); -} - -PowerSaveBlocker::~PowerSaveBlocker() { -} - -void PowerSaveBlocker::UpdatePowerSaveBlocker() { - if (power_save_blocker_types_.empty()) { - power_save_blocker_.reset(); - return; - } - - // |kPowerSaveBlockPreventAppSuspension| keeps system active, but allows - // screen to be turned off. - // |kPowerSaveBlockPreventDisplaySleep| keeps system and screen active, has a - // higher precedence level than |kPowerSaveBlockPreventAppSuspension|. - // - // Only the highest-precedence blocker type takes effect. - content::PowerSaveBlocker::PowerSaveBlockerType new_blocker_type = - content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension; - for (const auto& element : power_save_blocker_types_) { - if (element.second == - content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep) { - new_blocker_type = - content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep; - break; - } - } - - if (!power_save_blocker_ || new_blocker_type != current_blocker_type_) { - std::unique_ptr new_blocker = - content::PowerSaveBlocker::Create( - new_blocker_type, - content::PowerSaveBlocker::kReasonOther, - ATOM_PRODUCT_NAME); - power_save_blocker_.swap(new_blocker); - current_blocker_type_ = new_blocker_type; - } -} - -int PowerSaveBlocker::Start( - content::PowerSaveBlocker::PowerSaveBlockerType type) { - static int count = 0; - power_save_blocker_types_[count] = type; - UpdatePowerSaveBlocker(); - return count++; -} - -bool PowerSaveBlocker::Stop(int id) { - bool success = power_save_blocker_types_.erase(id) > 0; - UpdatePowerSaveBlocker(); - return success; -} - -bool PowerSaveBlocker::IsStarted(int id) { - return power_save_blocker_types_.find(id) != power_save_blocker_types_.end(); -} - -// static -mate::Handle PowerSaveBlocker::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new PowerSaveBlocker(isolate)); -} - -// static -void PowerSaveBlocker::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "PowerSaveBlocker")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("start", &PowerSaveBlocker::Start) - .SetMethod("stop", &PowerSaveBlocker::Stop) - .SetMethod("isStarted", &PowerSaveBlocker::IsStarted); -} - -} // namespace api - -} // namespace atom - -namespace { - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("powerSaveBlocker", atom::api::PowerSaveBlocker::Create(isolate)); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_power_save_blocker, Initialize); diff --git a/atom/browser/api/atom_api_power_save_blocker.h b/atom/browser/api/atom_api_power_save_blocker.h deleted file mode 100644 index 0687106ab8ba2..0000000000000 --- a/atom/browser/api/atom_api_power_save_blocker.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_POWER_SAVE_BLOCKER_H_ -#define ATOM_BROWSER_API_ATOM_API_POWER_SAVE_BLOCKER_H_ - -#include -#include - -#include "atom/browser/api/trackable_object.h" -#include "content/public/browser/power_save_blocker.h" -#include "native_mate/handle.h" - -namespace mate { -class Dictionary; -} - -namespace atom { - -namespace api { - -class PowerSaveBlocker : public mate::TrackableObject { - public: - static mate::Handle Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - explicit PowerSaveBlocker(v8::Isolate* isolate); - ~PowerSaveBlocker() override; - - private: - void UpdatePowerSaveBlocker(); - int Start(content::PowerSaveBlocker::PowerSaveBlockerType type); - bool Stop(int id); - bool IsStarted(int id); - - std::unique_ptr power_save_blocker_; - - // Currnet blocker type used by |power_save_blocker_| - content::PowerSaveBlocker::PowerSaveBlockerType current_blocker_type_; - - // Map from id to the corresponding blocker type for each request. - using PowerSaveBlockerTypeMap = - std::map; - PowerSaveBlockerTypeMap power_save_blocker_types_; - - DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_POWER_SAVE_BLOCKER_H_ diff --git a/atom/browser/api/atom_api_protocol.cc b/atom/browser/api/atom_api_protocol.cc deleted file mode 100644 index e4f27b54fb96c..0000000000000 --- a/atom/browser/api/atom_api_protocol.cc +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_protocol.h" - -#include "atom/browser/atom_browser_client.h" -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/browser/browser.h" -#include "atom/browser/net/url_request_async_asar_job.h" -#include "atom/browser/net/url_request_buffer_job.h" -#include "atom/browser/net/url_request_fetch_job.h" -#include "atom/browser/net/url_request_string_job.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_includes.h" -#include "atom/common/options_switches.h" -#include "base/command_line.h" -#include "base/strings/string_util.h" -#include "content/public/browser/child_process_security_policy.h" -#include "native_mate/dictionary.h" -#include "url/url_util.h" - -using content::BrowserThread; - -namespace atom { - -namespace api { - -namespace { - -// List of registered custom standard schemes. -std::vector g_standard_schemes; - -// Clear protocol handlers in IO thread. -void ClearJobFactoryInIO( - scoped_refptr request_context_getter) { - auto job_factory = static_cast( - request_context_getter->job_factory()); - job_factory->Clear(); -} - -} // namespace - -std::vector GetStandardSchemes() { - return g_standard_schemes; -} - -void RegisterStandardSchemes(const std::vector& schemes) { - g_standard_schemes = schemes; - - auto* policy = content::ChildProcessSecurityPolicy::GetInstance(); - for (const std::string& scheme : schemes) { - url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); - policy->RegisterWebSafeScheme(scheme); - } - - base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( - atom::switches::kStandardSchemes, base::JoinString(schemes, ",")); -} - -Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context) - : request_context_getter_(browser_context->GetRequestContext()), - weak_factory_(this) { - Init(isolate); -} - -Protocol::~Protocol() { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(ClearJobFactoryInIO, request_context_getter_)); -} - -void Protocol::RegisterServiceWorkerSchemes( - const std::vector& schemes) { - atom::AtomBrowserClient::SetCustomServiceWorkerSchemes(schemes); -} - -void Protocol::UnregisterProtocol( - const std::string& scheme, mate::Arguments* args) { - CompletionCallback callback; - args->GetNext(&callback); - content::BrowserThread::PostTaskAndReplyWithResult( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&Protocol::UnregisterProtocolInIO, - request_context_getter_, scheme), - base::Bind(&Protocol::OnIOCompleted, - GetWeakPtr(), callback)); -} - -// static -Protocol::ProtocolError Protocol::UnregisterProtocolInIO( - scoped_refptr request_context_getter, - const std::string& scheme) { - auto job_factory = static_cast( - request_context_getter->job_factory()); - if (!job_factory->HasProtocolHandler(scheme)) - return PROTOCOL_NOT_REGISTERED; - job_factory->SetProtocolHandler(scheme, nullptr); - return PROTOCOL_OK; -} - -void Protocol::IsProtocolHandled(const std::string& scheme, - const BooleanCallback& callback) { - content::BrowserThread::PostTaskAndReplyWithResult( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&Protocol::IsProtocolHandledInIO, - request_context_getter_, scheme), - callback); -} - -// static -bool Protocol::IsProtocolHandledInIO( - scoped_refptr request_context_getter, - const std::string& scheme) { - return request_context_getter->job_factory()->IsHandledProtocol(scheme); -} - -void Protocol::UninterceptProtocol( - const std::string& scheme, mate::Arguments* args) { - CompletionCallback callback; - args->GetNext(&callback); - content::BrowserThread::PostTaskAndReplyWithResult( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&Protocol::UninterceptProtocolInIO, - request_context_getter_, scheme), - base::Bind(&Protocol::OnIOCompleted, - GetWeakPtr(), callback)); -} - -// static -Protocol::ProtocolError Protocol::UninterceptProtocolInIO( - scoped_refptr request_context_getter, - const std::string& scheme) { - return static_cast( - request_context_getter->job_factory())->UninterceptProtocol(scheme) ? - PROTOCOL_OK : PROTOCOL_NOT_INTERCEPTED; -} - -void Protocol::OnIOCompleted( - const CompletionCallback& callback, ProtocolError error) { - // The completion callback is optional. - if (callback.is_null()) - return; - - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - - if (error == PROTOCOL_OK) { - callback.Run(v8::Null(isolate())); - } else { - std::string str = ErrorCodeToString(error); - callback.Run(v8::Exception::Error(mate::StringToV8(isolate(), str))); - } -} - -std::string Protocol::ErrorCodeToString(ProtocolError error) { - switch (error) { - case PROTOCOL_FAIL: return "Failed to manipulate protocol factory"; - case PROTOCOL_REGISTERED: return "The scheme has been registred"; - case PROTOCOL_NOT_REGISTERED: return "The scheme has not been registred"; - case PROTOCOL_INTERCEPTED: return "The scheme has been intercepted"; - case PROTOCOL_NOT_INTERCEPTED: return "The scheme has not been intercepted"; - default: return "Unexpected error"; - } -} - -AtomURLRequestJobFactory* Protocol::GetJobFactoryInIO() const { - request_context_getter_->GetURLRequestContext(); // Force init. - return static_cast( - static_cast( - request_context_getter_.get())->job_factory()); -} - -// static -mate::Handle Protocol::Create( - v8::Isolate* isolate, AtomBrowserContext* browser_context) { - return mate::CreateHandle(isolate, new Protocol(isolate, browser_context)); -} - -// static -void Protocol::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "Protocol")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("registerServiceWorkerSchemes", - &Protocol::RegisterServiceWorkerSchemes) - .SetMethod("registerStringProtocol", - &Protocol::RegisterProtocol) - .SetMethod("registerBufferProtocol", - &Protocol::RegisterProtocol) - .SetMethod("registerFileProtocol", - &Protocol::RegisterProtocol) - .SetMethod("registerHttpProtocol", - &Protocol::RegisterProtocol) - .SetMethod("unregisterProtocol", &Protocol::UnregisterProtocol) - .SetMethod("isProtocolHandled", &Protocol::IsProtocolHandled) - .SetMethod("interceptStringProtocol", - &Protocol::InterceptProtocol) - .SetMethod("interceptBufferProtocol", - &Protocol::InterceptProtocol) - .SetMethod("interceptFileProtocol", - &Protocol::InterceptProtocol) - .SetMethod("interceptHttpProtocol", - &Protocol::InterceptProtocol) - .SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol); -} - -} // namespace api - -} // namespace atom - -namespace { - -void RegisterStandardSchemes( - const std::vector& schemes, mate::Arguments* args) { - if (atom::Browser::Get()->is_ready()) { - args->ThrowError("protocol.registerStandardSchemes should be called before " - "app is ready"); - return; - } - - atom::api::RegisterStandardSchemes(schemes); -} - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.SetMethod("registerStandardSchemes", &RegisterStandardSchemes); - dict.SetMethod("getStandardSchemes", &atom::api::GetStandardSchemes); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_protocol, Initialize) diff --git a/atom/browser/api/atom_api_protocol.h b/atom/browser/api/atom_api_protocol.h deleted file mode 100644 index 2e69e781c75a0..0000000000000 --- a/atom/browser/api/atom_api_protocol.h +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_ -#define ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_ - -#include -#include -#include - -#include "atom/browser/api/trackable_object.h" -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/net/atom_url_request_job_factory.h" -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "content/public/browser/browser_thread.h" -#include "native_mate/arguments.h" -#include "native_mate/dictionary.h" -#include "native_mate/handle.h" -#include "net/url_request/url_request_context.h" - -namespace base { -class DictionaryValue; -} - -namespace atom { - -namespace api { - -std::vector GetStandardSchemes(); -void RegisterStandardSchemes(const std::vector& schemes); - -class Protocol : public mate::TrackableObject { - public: - using Handler = - base::Callback)>; - using CompletionCallback = base::Callback)>; - using BooleanCallback = base::Callback; - - static mate::Handle Create( - v8::Isolate* isolate, AtomBrowserContext* browser_context); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context); - ~Protocol(); - - private: - // Possible errors. - enum ProtocolError { - PROTOCOL_OK, // no error - PROTOCOL_FAIL, // operation failed, should never occur - PROTOCOL_REGISTERED, - PROTOCOL_NOT_REGISTERED, - PROTOCOL_INTERCEPTED, - PROTOCOL_NOT_INTERCEPTED, - }; - - // The protocol handler that will create a protocol handler for certain - // request job. - template - class CustomProtocolHandler - : public net::URLRequestJobFactory::ProtocolHandler { - public: - CustomProtocolHandler( - v8::Isolate* isolate, - net::URLRequestContextGetter* request_context, - const Handler& handler) - : isolate_(isolate), - request_context_(request_context), - handler_(handler) {} - ~CustomProtocolHandler() override {} - - net::URLRequestJob* MaybeCreateJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override { - RequestJob* request_job = new RequestJob(request, network_delegate); - request_job->SetHandlerInfo(isolate_, request_context_.get(), handler_); - return request_job; - } - - private: - v8::Isolate* isolate_; - scoped_refptr request_context_; - Protocol::Handler handler_; - - DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler); - }; - - // Register schemes that can handle service worker. - void RegisterServiceWorkerSchemes(const std::vector& schemes); - - // Register the protocol with certain request job. - template - void RegisterProtocol(const std::string& scheme, - const Handler& handler, - mate::Arguments* args) { - CompletionCallback callback; - args->GetNext(&callback); - content::BrowserThread::PostTaskAndReplyWithResult( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&Protocol::RegisterProtocolInIO, - request_context_getter_, isolate(), scheme, handler), - base::Bind(&Protocol::OnIOCompleted, - GetWeakPtr(), callback)); - } - template - static ProtocolError RegisterProtocolInIO( - scoped_refptr request_context_getter, - v8::Isolate* isolate, - const std::string& scheme, - const Handler& handler) { - auto job_factory = static_cast( - request_context_getter->job_factory()); - if (job_factory->IsHandledProtocol(scheme)) - return PROTOCOL_REGISTERED; - std::unique_ptr> protocol_handler( - new CustomProtocolHandler( - isolate, request_context_getter.get(), handler)); - if (job_factory->SetProtocolHandler(scheme, std::move(protocol_handler))) - return PROTOCOL_OK; - else - return PROTOCOL_FAIL; - } - - // Unregister the protocol handler that handles |scheme|. - void UnregisterProtocol(const std::string& scheme, mate::Arguments* args); - static ProtocolError UnregisterProtocolInIO( - scoped_refptr request_context_getter, - const std::string& scheme); - - // Whether the protocol has handler registered. - void IsProtocolHandled(const std::string& scheme, - const BooleanCallback& callback); - static bool IsProtocolHandledInIO( - scoped_refptr request_context_getter, - const std::string& scheme); - - // Replace the protocol handler with a new one. - template - void InterceptProtocol(const std::string& scheme, - const Handler& handler, - mate::Arguments* args) { - CompletionCallback callback; - args->GetNext(&callback); - content::BrowserThread::PostTaskAndReplyWithResult( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&Protocol::InterceptProtocolInIO, - request_context_getter_, isolate(), scheme, handler), - base::Bind(&Protocol::OnIOCompleted, - GetWeakPtr(), callback)); - } - template - static ProtocolError InterceptProtocolInIO( - scoped_refptr request_context_getter, - v8::Isolate* isolate, - const std::string& scheme, - const Handler& handler) { - auto job_factory = static_cast( - request_context_getter->job_factory()); - if (!job_factory->IsHandledProtocol(scheme)) - return PROTOCOL_NOT_REGISTERED; - // It is possible a protocol is handled but can not be intercepted. - if (!job_factory->HasProtocolHandler(scheme)) - return PROTOCOL_FAIL; - std::unique_ptr> protocol_handler( - new CustomProtocolHandler( - isolate, request_context_getter.get(), handler)); - if (!job_factory->InterceptProtocol(scheme, std::move(protocol_handler))) - return PROTOCOL_INTERCEPTED; - return PROTOCOL_OK; - } - - // Restore the |scheme| to its original protocol handler. - void UninterceptProtocol(const std::string& scheme, mate::Arguments* args); - static ProtocolError UninterceptProtocolInIO( - scoped_refptr request_context_getter, - const std::string& scheme); - - // Convert error code to JS exception and call the callback. - void OnIOCompleted(const CompletionCallback& callback, ProtocolError error); - - // Convert error code to string. - std::string ErrorCodeToString(ProtocolError error); - - AtomURLRequestJobFactory* GetJobFactoryInIO() const; - - base::WeakPtr GetWeakPtr() { - return weak_factory_.GetWeakPtr(); - } - - scoped_refptr request_context_getter_; - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(Protocol); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_PROTOCOL_H_ diff --git a/atom/browser/api/atom_api_render_process_preferences.cc b/atom/browser/api/atom_api_render_process_preferences.cc deleted file mode 100644 index d5017122dd6a6..0000000000000 --- a/atom/browser/api/atom_api_render_process_preferences.cc +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_render_process_preferences.h" - -#include "atom/browser/api/atom_api_web_contents.h" -#include "atom/browser/atom_browser_client.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_includes.h" -#include "content/public/browser/render_process_host.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" - -namespace atom { - -namespace api { - -namespace { - -bool IsWebContents(v8::Isolate* isolate, content::RenderProcessHost* process) { - content::WebContents* web_contents = - static_cast(AtomBrowserClient::Get())-> - GetWebContentsFromProcessID(process->GetID()); - if (!web_contents) - return false; - - auto api_web_contents = WebContents::CreateFrom(isolate, web_contents); - auto type = api_web_contents->GetType(); - return type == WebContents::Type::BROWSER_WINDOW || - type == WebContents::Type::WEB_VIEW; -} - -} // namespace - -RenderProcessPreferences::RenderProcessPreferences( - v8::Isolate* isolate, - const atom::RenderProcessPreferences::Predicate& predicate) - : preferences_(predicate) { - Init(isolate); -} - -RenderProcessPreferences::~RenderProcessPreferences() { -} - -int RenderProcessPreferences::AddEntry(const base::DictionaryValue& entry) { - return preferences_.AddEntry(entry); -} - -void RenderProcessPreferences::RemoveEntry(int id) { - preferences_.RemoveEntry(id); -} - -// static -void RenderProcessPreferences::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName( - mate::StringToV8(isolate, "RenderProcessPreferences")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("addEntry", &RenderProcessPreferences::AddEntry) - .SetMethod("removeEntry", &RenderProcessPreferences::RemoveEntry); -} - -// static -mate::Handle -RenderProcessPreferences::ForAllWebContents(v8::Isolate* isolate) { - return mate::CreateHandle( - isolate, - new RenderProcessPreferences(isolate, - base::Bind(&IsWebContents, isolate))); -} - -} // namespace api - -} // namespace atom - -namespace { - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("forAllWebContents", - &atom::api::RenderProcessPreferences::ForAllWebContents); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_render_process_preferences, - Initialize) diff --git a/atom/browser/api/atom_api_render_process_preferences.h b/atom/browser/api/atom_api_render_process_preferences.h deleted file mode 100644 index 19cc0d8821f88..0000000000000 --- a/atom/browser/api/atom_api_render_process_preferences.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_RENDER_PROCESS_PREFERENCES_H_ -#define ATOM_BROWSER_API_ATOM_API_RENDER_PROCESS_PREFERENCES_H_ - -#include "atom/browser/render_process_preferences.h" -#include "native_mate/handle.h" -#include "native_mate/wrappable.h" - -namespace atom { - -namespace api { - -class RenderProcessPreferences - : public mate::Wrappable { - public: - static mate::Handle - ForAllWebContents(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - int AddEntry(const base::DictionaryValue& entry); - void RemoveEntry(int id); - - protected: - RenderProcessPreferences( - v8::Isolate* isolate, - const atom::RenderProcessPreferences::Predicate& predicate); - ~RenderProcessPreferences() override; - - private: - atom::RenderProcessPreferences preferences_; - - DISALLOW_COPY_AND_ASSIGN(RenderProcessPreferences); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_RENDER_PROCESS_PREFERENCES_H_ diff --git a/atom/browser/api/atom_api_screen.cc b/atom/browser/api/atom_api_screen.cc deleted file mode 100644 index dfdd3450ebd84..0000000000000 --- a/atom/browser/api/atom_api_screen.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_screen.h" - -#include -#include - -#include "atom/browser/browser.h" -#include "atom/common/native_mate_converters/gfx_converter.h" -#include "base/bind.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/gfx/geometry/point.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace api { - -namespace { - -// Find an item in container according to its ID. -template -typename T::iterator FindById(T* container, int id) { - auto predicate = [id] (const typename T::value_type& item) -> bool { - return item.id() == id; - }; - return std::find_if(container->begin(), container->end(), predicate); -} - -// Convert the changed_metrics bitmask to string array. -std::vector MetricsToArray(uint32_t metrics) { - std::vector array; - if (metrics & display::DisplayObserver::DISPLAY_METRIC_BOUNDS) - array.push_back("bounds"); - if (metrics & display::DisplayObserver::DISPLAY_METRIC_WORK_AREA) - array.push_back("workArea"); - if (metrics & display::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR) - array.push_back("scaleFactor"); - if (metrics & display::DisplayObserver::DISPLAY_METRIC_ROTATION) - array.push_back("rotation"); - return array; -} - -} // namespace - -Screen::Screen(v8::Isolate* isolate, display::Screen* screen) - : screen_(screen) { - screen_->AddObserver(this); - Init(isolate); -} - -Screen::~Screen() { - screen_->RemoveObserver(this); -} - -gfx::Point Screen::GetCursorScreenPoint() { - return screen_->GetCursorScreenPoint(); -} - -display::Display Screen::GetPrimaryDisplay() { - return screen_->GetPrimaryDisplay(); -} - -std::vector Screen::GetAllDisplays() { - return screen_->GetAllDisplays(); -} - -display::Display Screen::GetDisplayNearestPoint(const gfx::Point& point) { - return screen_->GetDisplayNearestPoint(point); -} - -display::Display Screen::GetDisplayMatching(const gfx::Rect& match_rect) { - return screen_->GetDisplayMatching(match_rect); -} - -void Screen::OnDisplayAdded(const display::Display& new_display) { - Emit("display-added", new_display); -} - -void Screen::OnDisplayRemoved(const display::Display& old_display) { - Emit("display-removed", old_display); -} - -void Screen::OnDisplayMetricsChanged(const display::Display& display, - uint32_t changed_metrics) { - Emit("display-metrics-changed", display, MetricsToArray(changed_metrics)); -} - -// static -v8::Local Screen::Create(v8::Isolate* isolate) { - if (!Browser::Get()->is_ready()) { - isolate->ThrowException(v8::Exception::Error(mate::StringToV8( - isolate, - "Cannot initialize \"screen\" module before app is ready"))); - return v8::Null(isolate); - } - - display::Screen* screen = display::Screen::GetScreen(); - if (!screen) { - isolate->ThrowException(v8::Exception::Error(mate::StringToV8( - isolate, "Failed to get screen information"))); - return v8::Null(isolate); - } - - return mate::CreateHandle(isolate, new Screen(isolate, screen)).ToV8(); -} - -// static -void Screen::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "Screen")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("getCursorScreenPoint", &Screen::GetCursorScreenPoint) - .SetMethod("getPrimaryDisplay", &Screen::GetPrimaryDisplay) - .SetMethod("getAllDisplays", &Screen::GetAllDisplays) - .SetMethod("getDisplayNearestPoint", &Screen::GetDisplayNearestPoint) - .SetMethod("getDisplayMatching", &Screen::GetDisplayMatching); -} - -} // namespace api - -} // namespace atom - -namespace { - -using atom::api::Screen; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("screen", Screen::Create(isolate)); - dict.Set("Screen", Screen::GetConstructor(isolate)->GetFunction()); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_screen, Initialize) diff --git a/atom/browser/api/atom_api_screen.h b/atom/browser/api/atom_api_screen.h deleted file mode 100644 index 2bbaa13f6df55..0000000000000 --- a/atom/browser/api/atom_api_screen.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_SCREEN_H_ -#define ATOM_BROWSER_API_ATOM_API_SCREEN_H_ - -#include - -#include "atom/browser/api/event_emitter.h" -#include "native_mate/handle.h" -#include "ui/display/display_observer.h" -#include "ui/display/screen.h" - -namespace gfx { -class Point; -class Rect; -class Screen; -} - -namespace atom { - -namespace api { - -class Screen : public mate::EventEmitter, - public display::DisplayObserver { - public: - static v8::Local Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - Screen(v8::Isolate* isolate, display::Screen* screen); - ~Screen() override; - - gfx::Point GetCursorScreenPoint(); - display::Display GetPrimaryDisplay(); - std::vector GetAllDisplays(); - display::Display GetDisplayNearestPoint(const gfx::Point& point); - display::Display GetDisplayMatching(const gfx::Rect& match_rect); - - // display::DisplayObserver: - void OnDisplayAdded(const display::Display& new_display) override; - void OnDisplayRemoved(const display::Display& old_display) override; - void OnDisplayMetricsChanged(const display::Display& display, - uint32_t changed_metrics) override; - - private: - display::Screen* screen_; - - DISALLOW_COPY_AND_ASSIGN(Screen); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_SCREEN_H_ diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc deleted file mode 100644 index 58de02f2ff631..0000000000000 --- a/atom/browser/api/atom_api_session.cc +++ /dev/null @@ -1,623 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_session.h" - -#include -#include -#include - -#include "atom/browser/api/atom_api_cookies.h" -#include "atom/browser/api/atom_api_download_item.h" -#include "atom/browser/api/atom_api_protocol.h" -#include "atom/browser/api/atom_api_web_request.h" -#include "atom/browser/browser.h" -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/browser/atom_permission_manager.h" -#include "atom/browser/net/atom_cert_verifier.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/content_converter.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/native_mate_converters/net_converter.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_includes.h" -#include "base/files/file_path.h" -#include "base/guid.h" -#include "components/prefs/pref_service.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/threading/thread_task_runner_handle.h" -#include "brightray/browser/net/devtools_network_conditions.h" -#include "brightray/browser/net/devtools_network_controller_handle.h" -#include "chrome/common/pref_names.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/storage_partition.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" -#include "net/base/load_flags.h" -#include "net/disk_cache/disk_cache.h" -#include "net/dns/host_cache.h" -#include "net/http/http_auth_handler_factory.h" -#include "net/http/http_auth_preferences.h" -#include "net/proxy/proxy_service.h" -#include "net/proxy/proxy_config_service_fixed.h" -#include "net/url_request/static_http_user_agent_settings.h" -#include "net/url_request/url_request_context.h" -#include "net/url_request/url_request_context_getter.h" -#include "ui/base/l10n/l10n_util.h" - -using content::BrowserThread; -using content::StoragePartition; - -namespace { - -struct ClearStorageDataOptions { - GURL origin; - uint32_t storage_types = StoragePartition::REMOVE_DATA_MASK_ALL; - uint32_t quota_types = StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL; -}; - -uint32_t GetStorageMask(const std::vector& storage_types) { - uint32_t storage_mask = 0; - for (const auto& it : storage_types) { - auto type = base::ToLowerASCII(it); - if (type == "appcache") - storage_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE; - else if (type == "cookies") - storage_mask |= StoragePartition::REMOVE_DATA_MASK_COOKIES; - else if (type == "filesystem") - storage_mask |= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS; - else if (type == "indexdb") - storage_mask |= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB; - else if (type == "localstorage") - storage_mask |= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE; - else if (type == "shadercache") - storage_mask |= StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE; - else if (type == "websql") - storage_mask |= StoragePartition::REMOVE_DATA_MASK_WEBSQL; - else if (type == "serviceworkers") - storage_mask |= StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS; - } - return storage_mask; -} - -uint32_t GetQuotaMask(const std::vector& quota_types) { - uint32_t quota_mask = 0; - for (const auto& it : quota_types) { - auto type = base::ToLowerASCII(it); - if (type == "temporary") - quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY; - else if (type == "persistent") - quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_PERSISTENT; - else if (type == "syncable") - quota_mask |= StoragePartition::QUOTA_MANAGED_STORAGE_MASK_SYNCABLE; - } - return quota_mask; -} - -void SetUserAgentInIO(scoped_refptr getter, - const std::string& accept_lang, - const std::string& user_agent) { - getter->GetURLRequestContext()->set_http_user_agent_settings( - new net::StaticHttpUserAgentSettings( - net::HttpUtil::GenerateAcceptLanguageHeader(accept_lang), - user_agent)); -} - -} // namespace - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - ClearStorageDataOptions* out) { - mate::Dictionary options; - if (!ConvertFromV8(isolate, val, &options)) - return false; - options.Get("origin", &out->origin); - std::vector types; - if (options.Get("storages", &types)) - out->storage_types = GetStorageMask(types); - if (options.Get("quotas", &types)) - out->quota_types = GetQuotaMask(types); - return true; - } -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - net::ProxyConfig* out) { - std::string proxy_rules, proxy_bypass_rules; - GURL pac_url; - mate::Dictionary options; - // Fallback to previous API when passed String. - // https://git.io/vuhjj - if (ConvertFromV8(isolate, val, &proxy_rules)) { - pac_url = GURL(proxy_rules); // Assume it is PAC script if it is URL. - } else if (ConvertFromV8(isolate, val, &options)) { - options.Get("pacScript", &pac_url); - options.Get("proxyRules", &proxy_rules); - options.Get("proxyBypassRules", &proxy_bypass_rules); - } else { - return false; - } - - // pacScript takes precedence over proxyRules. - if (!pac_url.is_empty() && pac_url.is_valid()) { - out->set_pac_url(pac_url); - } else { - out->proxy_rules().ParseFromString(proxy_rules); - out->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_rules); - } - return true; - } -}; - -} // namespace mate - -namespace atom { - -namespace api { - -namespace { - -const char kPersistPrefix[] = "persist:"; - -// Referenced session objects. -std::map> g_sessions; - -class ResolveProxyHelper { - public: - ResolveProxyHelper(AtomBrowserContext* browser_context, - const GURL& url, - Session::ResolveProxyCallback callback) - : callback_(callback), - original_thread_(base::ThreadTaskRunnerHandle::Get()) { - scoped_refptr context_getter = - browser_context->url_request_context_getter(); - context_getter->GetNetworkTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&ResolveProxyHelper::ResolveProxy, - base::Unretained(this), context_getter, url)); - } - - void OnResolveProxyCompleted(int result) { - std::string proxy; - if (result == net::OK) - proxy = proxy_info_.ToPacString(); - original_thread_->PostTask(FROM_HERE, - base::Bind(callback_, proxy)); - delete this; - } - - private: - void ResolveProxy(scoped_refptr context_getter, - const GURL& url) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - net::ProxyService* proxy_service = - context_getter->GetURLRequestContext()->proxy_service(); - net::CompletionCallback completion_callback = - base::Bind(&ResolveProxyHelper::OnResolveProxyCompleted, - base::Unretained(this)); - - // Start the request. - int result = proxy_service->ResolveProxy( - url, "GET", net::LOAD_NORMAL, &proxy_info_, completion_callback, - &pac_req_, nullptr, net::BoundNetLog()); - - // Completed synchronously. - if (result != net::ERR_IO_PENDING) - completion_callback.Run(result); - } - - Session::ResolveProxyCallback callback_; - net::ProxyInfo proxy_info_; - net::ProxyService::PacRequest* pac_req_; - scoped_refptr original_thread_; - - DISALLOW_COPY_AND_ASSIGN(ResolveProxyHelper); -}; - -// Runs the callback in UI thread. -template -void RunCallbackInUI(const base::Callback& callback, T... result) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, base::Bind(callback, result...)); -} - -// Callback of HttpCache::GetBackend. -void OnGetBackend(disk_cache::Backend** backend_ptr, - Session::CacheAction action, - const net::CompletionCallback& callback, - int result) { - if (result != net::OK) { - RunCallbackInUI(callback, result); - } else if (backend_ptr && *backend_ptr) { - if (action == Session::CacheAction::CLEAR) { - (*backend_ptr)->DoomAllEntries(base::Bind(&RunCallbackInUI, - callback)); - } else if (action == Session::CacheAction::STATS) { - base::StringPairs stats; - (*backend_ptr)->GetStats(&stats); - for (const auto& stat : stats) { - if (stat.first == "Current size") { - int current_size; - base::StringToInt(stat.second, ¤t_size); - RunCallbackInUI(callback, current_size); - break; - } - } - } - } else { - RunCallbackInUI(callback, net::ERR_FAILED); - } -} - -void DoCacheActionInIO( - const scoped_refptr& context_getter, - Session::CacheAction action, - const net::CompletionCallback& callback) { - auto request_context = context_getter->GetURLRequestContext(); - auto http_cache = request_context->http_transaction_factory()->GetCache(); - if (!http_cache) - RunCallbackInUI(callback, net::ERR_FAILED); - - // Call GetBackend and make the backend's ptr accessable in OnGetBackend. - using BackendPtr = disk_cache::Backend*; - auto* backend_ptr = new BackendPtr(nullptr); - net::CompletionCallback on_get_backend = - base::Bind(&OnGetBackend, base::Owned(backend_ptr), action, callback); - int rv = http_cache->GetBackend(backend_ptr, on_get_backend); - if (rv != net::ERR_IO_PENDING) - on_get_backend.Run(net::OK); -} - -void SetProxyInIO(net::URLRequestContextGetter* getter, - const net::ProxyConfig& config, - const base::Closure& callback) { - auto proxy_service = getter->GetURLRequestContext()->proxy_service(); - proxy_service->ResetConfigService(base::WrapUnique( - new net::ProxyConfigServiceFixed(config))); - // Refetches and applies the new pac script if provided. - proxy_service->ForceReloadProxyConfig(); - RunCallbackInUI(callback); -} - -void SetCertVerifyProcInIO( - const scoped_refptr& context_getter, - const AtomCertVerifier::VerifyProc& proc) { - auto request_context = context_getter->GetURLRequestContext(); - static_cast(request_context->cert_verifier())-> - SetVerifyProc(proc); -} - -void ClearHostResolverCacheInIO( - const scoped_refptr& context_getter, - const base::Closure& callback) { - auto request_context = context_getter->GetURLRequestContext(); - auto cache = request_context->host_resolver()->GetHostCache(); - if (cache) { - cache->clear(); - DCHECK_EQ(0u, cache->size()); - if (!callback.is_null()) - RunCallbackInUI(callback); - } -} - -void AllowNTLMCredentialsForDomainsInIO( - const scoped_refptr& context_getter, - const std::string& domains) { - auto request_context = context_getter->GetURLRequestContext(); - auto auth_handler = request_context->http_auth_handler_factory(); - if (auth_handler) { - auto auth_preferences = const_cast( - auth_handler->http_auth_preferences()); - if (auth_preferences) - auth_preferences->set_server_whitelist(domains); - } -} - -void OnClearStorageDataDone(const base::Closure& callback) { - if (!callback.is_null()) - callback.Run(); -} - -} // namespace - -Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context) - : devtools_network_emulation_client_id_(base::GenerateGUID()), - browser_context_(browser_context) { - // Observe DownloadManger to get download notifications. - content::BrowserContext::GetDownloadManager(browser_context)-> - AddObserver(this); - - Init(isolate); - AttachAsUserData(browser_context); -} - -Session::~Session() { - content::BrowserContext::GetDownloadManager(browser_context())-> - RemoveObserver(this); - g_sessions.erase(weak_map_id()); -} - -void Session::OnDownloadCreated(content::DownloadManager* manager, - content::DownloadItem* item) { - if (item->IsSavePackageDownload()) - return; - - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - bool prevent_default = Emit( - "will-download", - DownloadItem::Create(isolate(), item), - item->GetWebContents()); - if (prevent_default) { - item->Cancel(true); - item->Remove(); - } -} - -void Session::ResolveProxy(const GURL& url, ResolveProxyCallback callback) { - new ResolveProxyHelper(browser_context(), url, callback); -} - -template -void Session::DoCacheAction(const net::CompletionCallback& callback) { - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&DoCacheActionInIO, - make_scoped_refptr(browser_context_->GetRequestContext()), - action, - callback)); -} - -void Session::ClearStorageData(mate::Arguments* args) { - // clearStorageData([options, callback]) - ClearStorageDataOptions options; - base::Closure callback; - args->GetNext(&options); - args->GetNext(&callback); - - auto storage_partition = - content::BrowserContext::GetStoragePartition(browser_context(), nullptr); - storage_partition->ClearData( - options.storage_types, options.quota_types, options.origin, - content::StoragePartition::OriginMatcherFunction(), - base::Time(), base::Time::Max(), - base::Bind(&OnClearStorageDataDone, callback)); -} - -void Session::FlushStorageData() { - auto storage_partition = - content::BrowserContext::GetStoragePartition(browser_context(), nullptr); - storage_partition->Flush(); -} - -void Session::SetProxy(const net::ProxyConfig& config, - const base::Closure& callback) { - auto getter = browser_context_->GetRequestContext(); - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&SetProxyInIO, base::Unretained(getter), config, callback)); -} - -void Session::SetDownloadPath(const base::FilePath& path) { - browser_context_->prefs()->SetFilePath( - prefs::kDownloadDefaultDirectory, path); -} - -void Session::EnableNetworkEmulation(const mate::Dictionary& options) { - std::unique_ptr conditions; - bool offline = false; - double latency, download_throughput, upload_throughput; - if (options.Get("offline", &offline) && offline) { - conditions.reset(new brightray::DevToolsNetworkConditions(offline)); - } else { - options.Get("latency", &latency); - options.Get("downloadThroughput", &download_throughput); - options.Get("uploadThroughput", &upload_throughput); - conditions.reset( - new brightray::DevToolsNetworkConditions(false, - latency, - download_throughput, - upload_throughput)); - } - - browser_context_->network_controller_handle()->SetNetworkState( - devtools_network_emulation_client_id_, std::move(conditions)); - browser_context_->network_delegate()->SetDevToolsNetworkEmulationClientId( - devtools_network_emulation_client_id_); -} - -void Session::DisableNetworkEmulation() { - std::unique_ptr conditions; - browser_context_->network_controller_handle()->SetNetworkState( - devtools_network_emulation_client_id_, std::move(conditions)); - browser_context_->network_delegate()->SetDevToolsNetworkEmulationClientId( - std::string()); -} - -void Session::SetCertVerifyProc(v8::Local val, - mate::Arguments* args) { - AtomCertVerifier::VerifyProc proc; - if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &proc))) { - args->ThrowError("Must pass null or function"); - return; - } - - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&SetCertVerifyProcInIO, - make_scoped_refptr(browser_context_->GetRequestContext()), - proc)); -} - -void Session::SetPermissionRequestHandler(v8::Local val, - mate::Arguments* args) { - AtomPermissionManager::RequestHandler handler; - if (!(val->IsNull() || mate::ConvertFromV8(args->isolate(), val, &handler))) { - args->ThrowError("Must pass null or function"); - return; - } - auto permission_manager = static_cast( - browser_context()->GetPermissionManager()); - permission_manager->SetPermissionRequestHandler(handler); -} - -void Session::ClearHostResolverCache(mate::Arguments* args) { - base::Closure callback; - args->GetNext(&callback); - - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&ClearHostResolverCacheInIO, - make_scoped_refptr(browser_context_->GetRequestContext()), - callback)); -} - -void Session::AllowNTLMCredentialsForDomains(const std::string& domains) { - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&AllowNTLMCredentialsForDomainsInIO, - make_scoped_refptr(browser_context_->GetRequestContext()), - domains)); -} - -void Session::SetUserAgent(const std::string& user_agent, - mate::Arguments* args) { - browser_context_->SetUserAgent(user_agent); - - std::string accept_lang = l10n_util::GetApplicationLocale(""); - args->GetNext(&accept_lang); - - auto getter = browser_context_->GetRequestContext(); - getter->GetNetworkTaskRunner()->PostTask( - FROM_HERE, - base::Bind(&SetUserAgentInIO, getter, accept_lang, user_agent)); -} - -std::string Session::GetUserAgent() { - return browser_context_->GetUserAgent(); -} - -v8::Local Session::Cookies(v8::Isolate* isolate) { - if (cookies_.IsEmpty()) { - auto handle = atom::api::Cookies::Create(isolate, browser_context()); - cookies_.Reset(isolate, handle.ToV8()); - } - return v8::Local::New(isolate, cookies_); -} - -v8::Local Session::Protocol(v8::Isolate* isolate) { - if (protocol_.IsEmpty()) { - auto handle = atom::api::Protocol::Create(isolate, browser_context()); - protocol_.Reset(isolate, handle.ToV8()); - } - return v8::Local::New(isolate, protocol_); -} - -v8::Local Session::WebRequest(v8::Isolate* isolate) { - if (web_request_.IsEmpty()) { - auto handle = atom::api::WebRequest::Create(isolate, browser_context()); - web_request_.Reset(isolate, handle.ToV8()); - } - return v8::Local::New(isolate, web_request_); -} - -// static -mate::Handle Session::CreateFrom( - v8::Isolate* isolate, AtomBrowserContext* browser_context) { - auto existing = TrackableObject::FromWrappedClass(isolate, browser_context); - if (existing) - return mate::CreateHandle(isolate, static_cast(existing)); - - auto handle = mate::CreateHandle( - isolate, new Session(isolate, browser_context)); - - // The Sessions should never be garbage collected, since the common pattern is - // to use partition strings, instead of using the Session object directly. - g_sessions[handle->weak_map_id()] = - v8::Global(isolate, handle.ToV8()); - - return handle; -} - -// static -mate::Handle Session::FromPartition( - v8::Isolate* isolate, const std::string& partition, - const base::DictionaryValue& options) { - scoped_refptr browser_context; - if (partition.empty()) { - browser_context = AtomBrowserContext::From("", false, options); - } else if (base::StartsWith(partition, kPersistPrefix, - base::CompareCase::SENSITIVE)) { - std::string name = partition.substr(8); - browser_context = AtomBrowserContext::From(name, false, options); - } else { - browser_context = AtomBrowserContext::From(partition, true, options); - } - return CreateFrom(isolate, browser_context.get()); -} - -// static -void Session::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "Session")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .MakeDestroyable() - .SetMethod("resolveProxy", &Session::ResolveProxy) - .SetMethod("getCacheSize", &Session::DoCacheAction) - .SetMethod("clearCache", &Session::DoCacheAction) - .SetMethod("clearStorageData", &Session::ClearStorageData) - .SetMethod("flushStorageData", &Session::FlushStorageData) - .SetMethod("setProxy", &Session::SetProxy) - .SetMethod("setDownloadPath", &Session::SetDownloadPath) - .SetMethod("enableNetworkEmulation", &Session::EnableNetworkEmulation) - .SetMethod("disableNetworkEmulation", &Session::DisableNetworkEmulation) - .SetMethod("setCertificateVerifyProc", &Session::SetCertVerifyProc) - .SetMethod("setPermissionRequestHandler", - &Session::SetPermissionRequestHandler) - .SetMethod("clearHostResolverCache", &Session::ClearHostResolverCache) - .SetMethod("allowNTLMCredentialsForDomains", - &Session::AllowNTLMCredentialsForDomains) - .SetMethod("setUserAgent", &Session::SetUserAgent) - .SetMethod("getUserAgent", &Session::GetUserAgent) - .SetProperty("cookies", &Session::Cookies) - .SetProperty("protocol", &Session::Protocol) - .SetProperty("webRequest", &Session::WebRequest); -} - -} // namespace api - -} // namespace atom - -namespace { - -using atom::api::Session; - -v8::Local FromPartition( - const std::string& partition, mate::Arguments* args) { - if (!atom::Browser::Get()->is_ready()) { - args->ThrowError("Session can only be received when app is ready"); - return v8::Null(args->isolate()); - } - base::DictionaryValue options; - args->GetNext(&options); - return Session::FromPartition(args->isolate(), partition, options).ToV8(); -} - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("Session", Session::GetConstructor(isolate)->GetFunction()); - dict.SetMethod("fromPartition", &FromPartition); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_session, Initialize) diff --git a/atom/browser/api/atom_api_session.h b/atom/browser/api/atom_api_session.h deleted file mode 100644 index 18189cf7e5c2e..0000000000000 --- a/atom/browser/api/atom_api_session.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_SESSION_H_ -#define ATOM_BROWSER_API_ATOM_API_SESSION_H_ - -#include - -#include "atom/browser/api/trackable_object.h" -#include "base/values.h" -#include "content/public/browser/download_manager.h" -#include "native_mate/handle.h" -#include "net/base/completion_callback.h" - -class GURL; - -namespace base { -class FilePath; -} - -namespace mate { -class Arguments; -class Dictionary; -} - -namespace net { -class ProxyConfig; -} - -namespace atom { - -class AtomBrowserContext; - -namespace api { - -class Session: public mate::TrackableObject, - public content::DownloadManager::Observer { - public: - using ResolveProxyCallback = base::Callback; - - enum class CacheAction { - CLEAR, - STATS, - }; - - // Gets or creates Session from the |browser_context|. - static mate::Handle CreateFrom( - v8::Isolate* isolate, AtomBrowserContext* browser_context); - - // Gets the Session of |partition|. - static mate::Handle FromPartition( - v8::Isolate* isolate, const std::string& partition, - const base::DictionaryValue& options = base::DictionaryValue()); - - AtomBrowserContext* browser_context() const { return browser_context_.get(); } - - // mate::TrackableObject: - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - // Methods. - void ResolveProxy(const GURL& url, ResolveProxyCallback callback); - template - void DoCacheAction(const net::CompletionCallback& callback); - void ClearStorageData(mate::Arguments* args); - void FlushStorageData(); - void SetProxy(const net::ProxyConfig& config, const base::Closure& callback); - void SetDownloadPath(const base::FilePath& path); - void EnableNetworkEmulation(const mate::Dictionary& options); - void DisableNetworkEmulation(); - void SetCertVerifyProc(v8::Local proc, mate::Arguments* args); - void SetPermissionRequestHandler(v8::Local val, - mate::Arguments* args); - void ClearHostResolverCache(mate::Arguments* args); - void AllowNTLMCredentialsForDomains(const std::string& domains); - void SetUserAgent(const std::string& user_agent, mate::Arguments* args); - std::string GetUserAgent(); - v8::Local Cookies(v8::Isolate* isolate); - v8::Local Protocol(v8::Isolate* isolate); - v8::Local WebRequest(v8::Isolate* isolate); - - protected: - Session(v8::Isolate* isolate, AtomBrowserContext* browser_context); - ~Session(); - - // content::DownloadManager::Observer: - void OnDownloadCreated(content::DownloadManager* manager, - content::DownloadItem* item) override; - - private: - // Cached object. - v8::Global cookies_; - v8::Global protocol_; - v8::Global web_request_; - - // The X-DevTools-Emulate-Network-Conditions-Client-Id. - std::string devtools_network_emulation_client_id_; - - scoped_refptr browser_context_; - - DISALLOW_COPY_AND_ASSIGN(Session); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_SESSION_H_ diff --git a/atom/browser/api/atom_api_system_preferences.cc b/atom/browser/api/atom_api_system_preferences.cc deleted file mode 100644 index b473d9f7ffb0d..0000000000000 --- a/atom/browser/api/atom_api_system_preferences.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_system_preferences.h" - -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_includes.h" -#include "native_mate/dictionary.h" - -#if defined(OS_WIN) -#include "ui/base/win/shell.h" -#endif - -namespace atom { - -namespace api { - -SystemPreferences::SystemPreferences(v8::Isolate* isolate) { - Init(isolate); -} - -SystemPreferences::~SystemPreferences() { -} - -#if defined(OS_WIN) -bool SystemPreferences::IsAeroGlassEnabled() { - return ui::win::IsAeroGlassEnabled(); -} -#endif - -#if !defined(OS_MACOSX) -bool SystemPreferences::IsDarkMode() { - return false; -} -#endif - -// static -mate::Handle SystemPreferences::Create( - v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new SystemPreferences(isolate)); -} - -// static -void SystemPreferences::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "SystemPreferences")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) -#if defined(OS_WIN) - .SetMethod("isAeroGlassEnabled", &SystemPreferences::IsAeroGlassEnabled) -#elif defined(OS_MACOSX) - .SetMethod("subscribeNotification", - &SystemPreferences::SubscribeNotification) - .SetMethod("unsubscribeNotification", - &SystemPreferences::UnsubscribeNotification) - .SetMethod("subscribeLocalNotification", - &SystemPreferences::SubscribeLocalNotification) - .SetMethod("unsubscribeLocalNotification", - &SystemPreferences::UnsubscribeLocalNotification) - .SetMethod("getUserDefault", &SystemPreferences::GetUserDefault) - .SetMethod("isSwipeTrackingFromScrollEventsEnabled", - &SystemPreferences::IsSwipeTrackingFromScrollEventsEnabled) -#endif - .SetMethod("isDarkMode", &SystemPreferences::IsDarkMode); -} - -} // namespace api - -} // namespace atom - -namespace { - -using atom::api::SystemPreferences; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("systemPreferences", SystemPreferences::Create(isolate)); - dict.Set("SystemPreferences", - SystemPreferences::GetConstructor(isolate)->GetFunction()); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_system_preferences, Initialize); diff --git a/atom/browser/api/atom_api_system_preferences.h b/atom/browser/api/atom_api_system_preferences.h deleted file mode 100644 index 3c780059375c3..0000000000000 --- a/atom/browser/api/atom_api_system_preferences.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_SYSTEM_PREFERENCES_H_ -#define ATOM_BROWSER_API_ATOM_API_SYSTEM_PREFERENCES_H_ - -#include - -#include "atom/browser/api/event_emitter.h" -#include "base/callback.h" -#include "native_mate/handle.h" - -namespace base { -class DictionaryValue; -} - -namespace atom { - -namespace api { - -class SystemPreferences : public mate::EventEmitter { - public: - static mate::Handle Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - -#if defined(OS_WIN) - bool IsAeroGlassEnabled(); -#elif defined(OS_MACOSX) - using NotificationCallback = base::Callback< - void(const std::string&, const base::DictionaryValue&)>; - - int SubscribeNotification(const std::string& name, - const NotificationCallback& callback); - void UnsubscribeNotification(int id); - int SubscribeLocalNotification(const std::string& name, - const NotificationCallback& callback); - void UnsubscribeLocalNotification(int request_id); - v8::Local GetUserDefault(const std::string& name, - const std::string& type); - bool IsSwipeTrackingFromScrollEventsEnabled(); -#endif - bool IsDarkMode(); - - protected: - explicit SystemPreferences(v8::Isolate* isolate); - ~SystemPreferences() override; - -#if defined(OS_MACOSX) - int DoSubscribeNotification(const std::string& name, - const NotificationCallback& callback, - bool is_local); - void DoUnsubscribeNotification(int request_id, bool is_local); -#endif - - private: - DISALLOW_COPY_AND_ASSIGN(SystemPreferences); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_SYSTEM_PREFERENCES_H_ diff --git a/atom/browser/api/atom_api_system_preferences_mac.mm b/atom/browser/api/atom_api_system_preferences_mac.mm deleted file mode 100644 index d4264dd6e87a5..0000000000000 --- a/atom/browser/api/atom_api_system_preferences_mac.mm +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_system_preferences.h" - -#include - -#import - -#include "atom/browser/mac/dict_util.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "base/strings/sys_string_conversions.h" -#include "base/values.h" -#include "net/base/mac/url_conversions.h" - -namespace atom { - -namespace api { - -namespace { - -int g_next_id = 0; - -// The map to convert |id| to |int|. -std::map g_id_map; - -} // namespace - -int SystemPreferences::SubscribeNotification( - const std::string& name, const NotificationCallback& callback) { - return DoSubscribeNotification(name, callback, false); -} - -void SystemPreferences::UnsubscribeNotification(int request_id) { - DoUnsubscribeNotification(request_id, false); -} - -int SystemPreferences::SubscribeLocalNotification( - const std::string& name, const NotificationCallback& callback) { - return DoSubscribeNotification(name, callback, true); -} - -void SystemPreferences::UnsubscribeLocalNotification(int request_id) { - DoUnsubscribeNotification(request_id, true); -} - -int SystemPreferences::DoSubscribeNotification(const std::string& name, - const NotificationCallback& callback, bool is_local) { - int request_id = g_next_id++; - __block NotificationCallback copied_callback = callback; - NSNotificationCenter* center = is_local ? - [NSNotificationCenter defaultCenter] : - [NSDistributedNotificationCenter defaultCenter]; - - g_id_map[request_id] = [center - addObserverForName:base::SysUTF8ToNSString(name) - object:nil - queue:nil - usingBlock:^(NSNotification* notification) { - std::unique_ptr user_info = - NSDictionaryToDictionaryValue(notification.userInfo); - if (user_info) { - copied_callback.Run( - base::SysNSStringToUTF8(notification.name), - *user_info); - } else { - copied_callback.Run( - base::SysNSStringToUTF8(notification.name), - base::DictionaryValue()); - } - } - ]; - return request_id; -} - -void SystemPreferences::DoUnsubscribeNotification(int request_id, bool is_local) { - auto iter = g_id_map.find(request_id); - if (iter != g_id_map.end()) { - id observer = iter->second; - NSNotificationCenter* center = is_local ? - [NSNotificationCenter defaultCenter] : - [NSDistributedNotificationCenter defaultCenter]; - [center removeObserver:observer]; - g_id_map.erase(iter); - } -} - -v8::Local SystemPreferences::GetUserDefault( - const std::string& name, const std::string& type) { - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - NSString* key = base::SysUTF8ToNSString(name); - if (type == "string") { - return mate::StringToV8(isolate(), - base::SysNSStringToUTF8([defaults stringForKey:key])); - } else if (type == "boolean") { - return v8::Boolean::New(isolate(), [defaults boolForKey:key]); - } else if (type == "float") { - return v8::Number::New(isolate(), [defaults floatForKey:key]); - } else if (type == "integer") { - return v8::Integer::New(isolate(), [defaults integerForKey:key]); - } else if (type == "double") { - return v8::Number::New(isolate(), [defaults doubleForKey:key]); - } else if (type == "url") { - return mate::ConvertToV8(isolate(), - net::GURLWithNSURL([defaults URLForKey:key])); - } else if (type == "array") { - return mate::ConvertToV8(isolate(), - *NSArrayToListValue([defaults arrayForKey:key])); - } else if (type == "dictionary") { - return mate::ConvertToV8(isolate(), - *NSDictionaryToDictionaryValue([defaults dictionaryForKey:key])); - } else { - return v8::Undefined(isolate()); - } -} - -bool SystemPreferences::IsDarkMode() { - NSString* mode = [[NSUserDefaults standardUserDefaults] - stringForKey:@"AppleInterfaceStyle"]; - return [mode isEqualToString:@"Dark"]; -} - -bool SystemPreferences::IsSwipeTrackingFromScrollEventsEnabled() { - return [NSEvent isSwipeTrackingFromScrollEventsEnabled]; -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/atom_api_tray.cc b/atom/browser/api/atom_api_tray.cc deleted file mode 100644 index 3f0386ab70aba..0000000000000 --- a/atom/browser/api/atom_api_tray.cc +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_tray.h" - -#include - -#include "atom/browser/api/atom_api_menu.h" -#include "atom/browser/browser.h" -#include "atom/common/api/atom_api_native_image.h" -#include "atom/common/native_mate_converters/gfx_converter.h" -#include "atom/common/native_mate_converters/image_converter.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "atom/common/node_includes.h" -#include "native_mate/constructor.h" -#include "native_mate/dictionary.h" -#include "ui/gfx/image/image.h" - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - atom::TrayIcon::HighlightMode* out) { - std::string mode; - if (ConvertFromV8(isolate, val, &mode)) { - if (mode == "always") { - *out = atom::TrayIcon::HighlightMode::ALWAYS; - return true; - } - if (mode == "selection") { - *out = atom::TrayIcon::HighlightMode::SELECTION; - return true; - } - if (mode == "never") { - *out = atom::TrayIcon::HighlightMode::NEVER; - return true; - } - } - - // Support old boolean parameter - // TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings - bool highlight; - if (ConvertFromV8(isolate, val, &highlight)) { - if (highlight) - *out = atom::TrayIcon::HighlightMode::SELECTION; - else - *out = atom::TrayIcon::HighlightMode::NEVER; - return true; - } - - return false; - } -}; -} // namespace mate - - -namespace atom { - -namespace api { - -Tray::Tray(v8::Isolate* isolate, v8::Local wrapper, - mate::Handle image) - : tray_icon_(TrayIcon::Create()) { - SetImage(isolate, image); - tray_icon_->AddObserver(this); - - InitWith(isolate, wrapper); -} - -Tray::~Tray() { - // Destroy the native tray in next tick. - base::MessageLoop::current()->DeleteSoon(FROM_HERE, tray_icon_.release()); -} - -// static -mate::WrappableBase* Tray::New(mate::Handle image, - mate::Arguments* args) { - if (!Browser::Get()->is_ready()) { - args->ThrowError("Cannot create Tray before app is ready"); - return nullptr; - } - return new Tray(args->isolate(), args->GetThis(), image); -} - -void Tray::OnClicked(const gfx::Rect& bounds, int modifiers) { - EmitWithFlags("click", modifiers, bounds); -} - -void Tray::OnDoubleClicked(const gfx::Rect& bounds, int modifiers) { - EmitWithFlags("double-click", modifiers, bounds); -} - -void Tray::OnRightClicked(const gfx::Rect& bounds, int modifiers) { - EmitWithFlags("right-click", modifiers, bounds); -} - -void Tray::OnBalloonShow() { - Emit("balloon-show"); -} - -void Tray::OnBalloonClicked() { - Emit("balloon-click"); -} - -void Tray::OnBalloonClosed() { - Emit("balloon-closed"); -} - -void Tray::OnDrop() { - Emit("drop"); -} - -void Tray::OnDropFiles(const std::vector& files) { - Emit("drop-files", files); -} - -void Tray::OnDropText(const std::string& text) { - Emit("drop-text", text); -} - -void Tray::OnDragEntered() { - Emit("drag-enter"); -} - -void Tray::OnDragExited() { - Emit("drag-leave"); -} - -void Tray::OnDragEnded() { - Emit("drag-end"); -} - -void Tray::SetImage(v8::Isolate* isolate, mate::Handle image) { -#if defined(OS_WIN) - tray_icon_->SetImage(image->GetHICON(GetSystemMetrics(SM_CXSMICON))); -#else - tray_icon_->SetImage(image->image()); -#endif -} - -void Tray::SetPressedImage(v8::Isolate* isolate, - mate::Handle image) { -#if defined(OS_WIN) - tray_icon_->SetPressedImage(image->GetHICON(GetSystemMetrics(SM_CXSMICON))); -#else - tray_icon_->SetPressedImage(image->image()); -#endif -} - -void Tray::SetToolTip(const std::string& tool_tip) { - tray_icon_->SetToolTip(tool_tip); -} - -void Tray::SetTitle(const std::string& title) { - tray_icon_->SetTitle(title); -} - -void Tray::SetHighlightMode(TrayIcon::HighlightMode mode) { - tray_icon_->SetHighlightMode(mode); -} - -void Tray::DisplayBalloon(mate::Arguments* args, - const mate::Dictionary& options) { - mate::Handle icon; - options.Get("icon", &icon); - base::string16 title, content; - if (!options.Get("title", &title) || - !options.Get("content", &content)) { - args->ThrowError("'title' and 'content' must be defined"); - return; - } - -#if defined(OS_WIN) - tray_icon_->DisplayBalloon( - icon.IsEmpty() ? NULL : icon->GetHICON(GetSystemMetrics(SM_CXSMICON)), - title, content); -#else - tray_icon_->DisplayBalloon( - icon.IsEmpty() ? gfx::Image() : icon->image(), title, content); -#endif -} - -void Tray::PopUpContextMenu(mate::Arguments* args) { - mate::Handle menu; - args->GetNext(&menu); - gfx::Point pos; - args->GetNext(&pos); - tray_icon_->PopUpContextMenu(pos, menu.IsEmpty() ? nullptr : menu->model()); -} - -void Tray::SetContextMenu(v8::Isolate* isolate, mate::Handle menu) { - menu_.Reset(isolate, menu.ToV8()); - tray_icon_->SetContextMenu(menu->model()); -} - -gfx::Rect Tray::GetBounds() { - return tray_icon_->GetBounds(); -} - -// static -void Tray::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "Tray")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .MakeDestroyable() - .SetMethod("setImage", &Tray::SetImage) - .SetMethod("setPressedImage", &Tray::SetPressedImage) - .SetMethod("setToolTip", &Tray::SetToolTip) - .SetMethod("setTitle", &Tray::SetTitle) - .SetMethod("setHighlightMode", &Tray::SetHighlightMode) - .SetMethod("displayBalloon", &Tray::DisplayBalloon) - .SetMethod("popUpContextMenu", &Tray::PopUpContextMenu) - .SetMethod("setContextMenu", &Tray::SetContextMenu) - .SetMethod("getBounds", &Tray::GetBounds); -} - -} // namespace api - -} // namespace atom - - -namespace { - -using atom::api::Tray; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - Tray::SetConstructor(isolate, base::Bind(&Tray::New)); - - mate::Dictionary dict(isolate, exports); - dict.Set("Tray", Tray::GetConstructor(isolate)->GetFunction()); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_tray, Initialize) diff --git a/atom/browser/api/atom_api_tray.h b/atom/browser/api/atom_api_tray.h deleted file mode 100644 index 61ee72bedf9f1..0000000000000 --- a/atom/browser/api/atom_api_tray.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_TRAY_H_ -#define ATOM_BROWSER_API_ATOM_API_TRAY_H_ - -#include -#include -#include - -#include "atom/browser/api/trackable_object.h" -#include "atom/browser/ui/tray_icon.h" -#include "atom/browser/ui/tray_icon_observer.h" -#include "native_mate/handle.h" - -namespace gfx { -class Image; -} - -namespace mate { -class Arguments; -class Dictionary; -} - -namespace atom { - -class TrayIcon; - -namespace api { - -class Menu; -class NativeImage; - -class Tray : public mate::TrackableObject, - public TrayIconObserver { - public: - static mate::WrappableBase* New(mate::Handle image, - mate::Arguments* args); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - Tray(v8::Isolate* isolate, v8::Local wrapper, - mate::Handle image); - ~Tray() override; - - // TrayIconObserver: - void OnClicked(const gfx::Rect& bounds, int modifiers) override; - void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) override; - void OnRightClicked(const gfx::Rect& bounds, int modifiers) override; - void OnBalloonShow() override; - void OnBalloonClicked() override; - void OnBalloonClosed() override; - void OnDrop() override; - void OnDropFiles(const std::vector& files) override; - void OnDropText(const std::string& text) override; - void OnDragEntered() override; - void OnDragExited() override; - void OnDragEnded() override; - - void SetImage(v8::Isolate* isolate, mate::Handle image); - void SetPressedImage(v8::Isolate* isolate, mate::Handle image); - void SetToolTip(const std::string& tool_tip); - void SetTitle(const std::string& title); - void SetHighlightMode(TrayIcon::HighlightMode mode); - void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options); - void PopUpContextMenu(mate::Arguments* args); - void SetContextMenu(v8::Isolate* isolate, mate::Handle menu); - gfx::Rect GetBounds(); - - private: - v8::Global menu_; - std::unique_ptr tray_icon_; - - DISALLOW_COPY_AND_ASSIGN(Tray); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_TRAY_H_ diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc deleted file mode 100644 index 5e1dc70980ec8..0000000000000 --- a/atom/browser/api/atom_api_web_contents.cc +++ /dev/null @@ -1,1581 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_web_contents.h" - -#include -#include - -#include "atom/browser/api/atom_api_debugger.h" -#include "atom/browser/api/atom_api_session.h" -#include "atom/browser/api/atom_api_window.h" -#include "atom/browser/atom_browser_client.h" -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/browser/atom_security_state_model_client.h" -#include "atom/browser/lib/bluetooth_chooser.h" -#include "atom/browser/native_window.h" -#include "atom/browser/net/atom_network_delegate.h" -#include "atom/browser/osr/osr_output_device.h" -#include "atom/browser/osr/osr_web_contents_view.h" -#include "atom/browser/osr/osr_render_widget_host_view.h" -#include "atom/browser/ui/drag_util.h" -#include "atom/browser/web_contents_permission_helper.h" -#include "atom/browser/web_contents_preferences.h" -#include "atom/browser/web_view_guest_delegate.h" -#include "atom/common/api/api_messages.h" -#include "atom/common/api/event_emitter_caller.h" -#include "atom/common/color_util.h" -#include "atom/common/mouse_util.h" -#include "atom/common/native_mate_converters/blink_converter.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/content_converter.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/native_mate_converters/gfx_converter.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/native_mate_converters/image_converter.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/options_switches.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "brightray/browser/inspectable_web_contents.h" -#include "brightray/browser/inspectable_web_contents_view.h" -#include "chrome/browser/printing/print_view_manager_basic.h" -#include "chrome/browser/printing/print_preview_message_handler.h" -#include "content/browser/renderer_host/render_widget_host_impl.h" -#include "content/browser/web_contents/web_contents_impl.h" -#include "content/common/view_messages.h" -#include "content/public/browser/favicon_status.h" -#include "content/public/browser/native_web_keyboard_event.h" -#include "content/public/browser/navigation_details.h" -#include "content/public/browser/navigation_entry.h" -#include "content/public/browser/navigation_handle.h" -#include "content/public/browser/plugin_service.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host.h" -#include "content/public/browser/render_widget_host_view.h" -#include "content/public/browser/resource_request_details.h" -#include "content/public/browser/service_worker_context.h" -#include "content/public/browser/storage_partition.h" -#include "content/public/browser/site_instance.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/context_menu_params.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" -#include "net/http/http_response_headers.h" -#include "net/url_request/url_request_context.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" -#include "third_party/WebKit/public/web/WebFindOptions.h" -#include "ui/display/screen.h" - -#include "atom/common/node_includes.h" - -namespace { - -struct PrintSettings { - bool silent; - bool print_background; -}; - -} // namespace - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - atom::SetSizeParams* out) { - mate::Dictionary params; - if (!ConvertFromV8(isolate, val, ¶ms)) - return false; - bool autosize; - if (params.Get("enableAutoSize", &autosize)) - out->enable_auto_size.reset(new bool(true)); - gfx::Size size; - if (params.Get("min", &size)) - out->min_size.reset(new gfx::Size(size)); - if (params.Get("max", &size)) - out->max_size.reset(new gfx::Size(size)); - if (params.Get("normal", &size)) - out->normal_size.reset(new gfx::Size(size)); - return true; - } -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - PrintSettings* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - dict.Get("silent", &(out->silent)); - dict.Get("printBackground", &(out->print_background)); - return true; - } -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - WindowOpenDisposition val) { - std::string disposition = "other"; - switch (val) { - case CURRENT_TAB: disposition = "default"; break; - case NEW_FOREGROUND_TAB: disposition = "foreground-tab"; break; - case NEW_BACKGROUND_TAB: disposition = "background-tab"; break; - case NEW_POPUP: case NEW_WINDOW: disposition = "new-window"; break; - default: break; - } - return mate::ConvertToV8(isolate, disposition); - } -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - net::HttpResponseHeaders* headers) { - base::DictionaryValue response_headers; - if (headers) { - size_t iter = 0; - std::string key; - std::string value; - while (headers->EnumerateHeaderLines(&iter, &key, &value)) { - key = base::ToLowerASCII(key); - if (response_headers.HasKey(key)) { - base::ListValue* values = nullptr; - if (response_headers.GetList(key, &values)) - values->AppendString(value); - } else { - std::unique_ptr values(new base::ListValue()); - values->AppendString(value); - response_headers.Set(key, std::move(values)); - } - } - } - return ConvertToV8(isolate, response_headers); - } -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - content::SavePageType* out) { - std::string save_type; - if (!ConvertFromV8(isolate, val, &save_type)) - return false; - save_type = base::ToLowerASCII(save_type); - if (save_type == "htmlonly") { - *out = content::SAVE_PAGE_TYPE_AS_ONLY_HTML; - } else if (save_type == "htmlcomplete") { - *out = content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML; - } else if (save_type == "mhtml") { - *out = content::SAVE_PAGE_TYPE_AS_MHTML; - } else { - return false; - } - return true; - } -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - atom::api::WebContents::Type val) { - using Type = atom::api::WebContents::Type; - std::string type = ""; - switch (val) { - case Type::BACKGROUND_PAGE: type = "backgroundPage"; break; - case Type::BROWSER_WINDOW: type = "window"; break; - case Type::REMOTE: type = "remote"; break; - case Type::WEB_VIEW: type = "webview"; break; - case Type::OFF_SCREEN: type = "offscreen"; break; - default: break; - } - return mate::ConvertToV8(isolate, type); - } - - static bool FromV8(v8::Isolate* isolate, v8::Local val, - atom::api::WebContents::Type* out) { - using Type = atom::api::WebContents::Type; - std::string type; - if (!ConvertFromV8(isolate, val, &type)) - return false; - if (type == "webview") { - *out = Type::WEB_VIEW; - } else if (type == "backgroundPage") { - *out = Type::BACKGROUND_PAGE; - } else if (type == "offscreen") { - *out = Type::OFF_SCREEN; - } else { - return false; - } - return true; - } -}; - -} // namespace mate - - -namespace atom { - -namespace api { - -namespace { - -content::ServiceWorkerContext* GetServiceWorkerContext( - const content::WebContents* web_contents) { - auto context = web_contents->GetBrowserContext(); - auto site_instance = web_contents->GetSiteInstance(); - if (!context || !site_instance) - return nullptr; - - auto storage_partition = - content::BrowserContext::GetStoragePartition(context, site_instance); - if (!storage_partition) - return nullptr; - - return storage_partition->GetServiceWorkerContext(); -} - -// Called when CapturePage is done. -void OnCapturePageDone(base::Callback callback, - const SkBitmap& bitmap, - content::ReadbackResponse response) { - callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap)); -} - -} // namespace - -WebContents::WebContents(v8::Isolate* isolate, - content::WebContents* web_contents) - : content::WebContentsObserver(web_contents), - embedder_(nullptr), - type_(REMOTE), - request_id_(0), - background_throttling_(true) { - web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); - - Init(isolate); - AttachAsUserData(web_contents); -} - -WebContents::WebContents(v8::Isolate* isolate, - const mate::Dictionary& options) - : embedder_(nullptr), - type_(BROWSER_WINDOW), - request_id_(0), - background_throttling_(true) { - // Read options. - options.Get("backgroundThrottling", &background_throttling_); - - // FIXME(zcbenz): We should read "type" parameter for better design, but - // on Windows we have encountered a compiler bug that if we read "type" - // from |options| and then set |type_|, a memory corruption will happen - // and Electron will soon crash. - // Remvoe this after we upgraded to use VS 2015 Update 3. - bool b = false; - if (options.Get("isGuest", &b) && b) - type_ = WEB_VIEW; - else if (options.Get("isBackgroundPage", &b) && b) - type_ = BACKGROUND_PAGE; - else if (options.Get("offscreen", &b) && b) - type_ = OFF_SCREEN; - - // Obtain the session. - std::string partition; - mate::Handle session; - if (options.Get("session", &session)) { - } else if (options.Get("partition", &partition)) { - session = Session::FromPartition(isolate, partition); - } else { - // Use the default session if not specified. - session = Session::FromPartition(isolate, ""); - } - session_.Reset(isolate, session.ToV8()); - - content::WebContents* web_contents; - if (IsGuest()) { - scoped_refptr site_instance = - content::SiteInstance::CreateForURL( - session->browser_context(), GURL("chrome-guest://fake-host")); - content::WebContents::CreateParams params( - session->browser_context(), site_instance); - guest_delegate_.reset(new WebViewGuestDelegate); - params.guest_delegate = guest_delegate_.get(); - web_contents = content::WebContents::Create(params); - } else if (IsOffScreen()) { - bool transparent = false; - options.Get("transparent", &transparent); - - content::WebContents::CreateParams params(session->browser_context()); - auto* view = new OffScreenWebContentsView( - transparent, base::Bind(&WebContents::OnPaint, base::Unretained(this))); - params.view = view; - params.delegate_view = view; - - web_contents = content::WebContents::Create(params); - view->SetWebContents(web_contents); - } else { - content::WebContents::CreateParams params(session->browser_context()); - web_contents = content::WebContents::Create(params); - } - - Observe(web_contents); - InitWithWebContents(web_contents, session->browser_context()); - - managed_web_contents()->GetView()->SetDelegate(this); - - // Save the preferences in C++. - new WebContentsPreferences(web_contents, options); - - // Intialize permission helper. - WebContentsPermissionHelper::CreateForWebContents(web_contents); - // Intialize security state client. - AtomSecurityStateModelClient::CreateForWebContents(web_contents); - - web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); - - if (IsGuest()) { - guest_delegate_->Initialize(this); - - NativeWindow* owner_window = nullptr; - if (options.Get("embedder", &embedder_) && embedder_) { - // New WebContents's owner_window is the embedder's owner_window. - auto relay = - NativeWindowRelay::FromWebContents(embedder_->web_contents()); - if (relay) - owner_window = relay->window.get(); - } - if (owner_window) - SetOwnerWindow(owner_window); - } - - Init(isolate); - AttachAsUserData(web_contents); -} - -WebContents::~WebContents() { - // The destroy() is called. - if (managed_web_contents()) { - // For webview we need to tell content module to do some cleanup work before - // destroying it. - if (type_ == WEB_VIEW) - guest_delegate_->Destroy(); - - // The WebContentsDestroyed will not be called automatically because we - // unsubscribe from webContents before destroying it. So we have to manually - // call it here to make sure "destroyed" event is emitted. - RenderViewDeleted(web_contents()->GetRenderViewHost()); - WebContentsDestroyed(); - } -} - -bool WebContents::AddMessageToConsole(content::WebContents* source, - int32_t level, - const base::string16& message, - int32_t line_no, - const base::string16& source_id) { - if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) { - return false; - } else { - Emit("console-message", level, message, line_no, source_id); - return true; - } -} - -void WebContents::OnCreateWindow(const GURL& target_url, - const std::string& frame_name, - WindowOpenDisposition disposition) { - if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) - Emit("-new-window", target_url, frame_name, disposition); - else - Emit("new-window", target_url, frame_name, disposition); -} - -content::WebContents* WebContents::OpenURLFromTab( - content::WebContents* source, - const content::OpenURLParams& params) { - if (params.disposition != CURRENT_TAB) { - if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) - Emit("-new-window", params.url, "", params.disposition); - else - Emit("new-window", params.url, "", params.disposition); - return nullptr; - } - - // Give user a chance to cancel navigation. - if (Emit("will-navigate", params.url)) - return nullptr; - - return CommonWebContentsDelegate::OpenURLFromTab(source, params); -} - -void WebContents::BeforeUnloadFired(content::WebContents* tab, - bool proceed, - bool* proceed_to_fire_unload) { - if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) - *proceed_to_fire_unload = proceed; - else - *proceed_to_fire_unload = true; -} - -void WebContents::MoveContents(content::WebContents* source, - const gfx::Rect& pos) { - Emit("move", pos); -} - -void WebContents::CloseContents(content::WebContents* source) { - Emit("close"); - - if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window()) - owner_window()->CloseContents(source); -} - -void WebContents::ActivateContents(content::WebContents* source) { - Emit("activate"); -} - -void WebContents::UpdateTargetURL(content::WebContents* source, - const GURL& url) { - Emit("update-target-url", url); -} - -bool WebContents::IsPopupOrPanel(const content::WebContents* source) const { - return type_ == BROWSER_WINDOW; -} - -void WebContents::HandleKeyboardEvent( - content::WebContents* source, - const content::NativeWebKeyboardEvent& event) { - if (type_ == WEB_VIEW && embedder_) { - // Send the unhandled keyboard events back to the embedder. - embedder_->HandleKeyboardEvent(source, event); - } else { - // Go to the default keyboard handling. - CommonWebContentsDelegate::HandleKeyboardEvent(source, event); - } -} - -void WebContents::EnterFullscreenModeForTab(content::WebContents* source, - const GURL& origin) { - auto permission_helper = - WebContentsPermissionHelper::FromWebContents(source); - auto callback = base::Bind(&WebContents::OnEnterFullscreenModeForTab, - base::Unretained(this), source, origin); - permission_helper->RequestFullscreenPermission(callback); -} - -void WebContents::OnEnterFullscreenModeForTab(content::WebContents* source, - const GURL& origin, - bool allowed) { - if (!allowed) - return; - CommonWebContentsDelegate::EnterFullscreenModeForTab(source, origin); - Emit("enter-html-full-screen"); -} - -void WebContents::ExitFullscreenModeForTab(content::WebContents* source) { - CommonWebContentsDelegate::ExitFullscreenModeForTab(source); - Emit("leave-html-full-screen"); -} - -void WebContents::RendererUnresponsive(content::WebContents* source) { - Emit("unresponsive"); - if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window()) - owner_window()->RendererUnresponsive(source); -} - -void WebContents::RendererResponsive(content::WebContents* source) { - Emit("responsive"); - if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window()) - owner_window()->RendererResponsive(source); -} - -bool WebContents::HandleContextMenu(const content::ContextMenuParams& params) { - if (params.custom_context.is_pepper_menu) { - Emit("pepper-context-menu", std::make_pair(params, web_contents())); - web_contents()->NotifyContextMenuClosed(params.custom_context); - } else { - Emit("context-menu", std::make_pair(params, web_contents())); - } - - return true; -} - -bool WebContents::OnGoToEntryOffset(int offset) { - GoToOffset(offset); - return false; -} - -void WebContents::FindReply(content::WebContents* web_contents, - int request_id, - int number_of_matches, - const gfx::Rect& selection_rect, - int active_match_ordinal, - bool final_update) { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - - mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate()); - if (number_of_matches == -1) { - result.Set("requestId", request_id); - result.Set("selectionArea", selection_rect); - result.Set("finalUpdate", final_update); - result.Set("activeMatchOrdinal", active_match_ordinal); - Emit("found-in-page", result); - } else if (final_update) { - result.Set("requestId", request_id); - result.Set("matches", number_of_matches); - result.Set("finalUpdate", final_update); - Emit("found-in-page", result); - } -} - -bool WebContents::CheckMediaAccessPermission( - content::WebContents* web_contents, - const GURL& security_origin, - content::MediaStreamType type) { - return true; -} - -void WebContents::RequestMediaAccessPermission( - content::WebContents* web_contents, - const content::MediaStreamRequest& request, - const content::MediaResponseCallback& callback) { - auto permission_helper = - WebContentsPermissionHelper::FromWebContents(web_contents); - permission_helper->RequestMediaAccessPermission(request, callback); -} - -void WebContents::RequestToLockMouse( - content::WebContents* web_contents, - bool user_gesture, - bool last_unlocked_by_target) { - auto permission_helper = - WebContentsPermissionHelper::FromWebContents(web_contents); - permission_helper->RequestPointerLockPermission(user_gesture); -} - -std::unique_ptr WebContents::RunBluetoothChooser( - content::RenderFrameHost* frame, - const content::BluetoothChooser::EventHandler& event_handler) { - std::unique_ptr bluetooth_chooser( - new BluetoothChooser(this, event_handler)); - return std::move(bluetooth_chooser); -} - -void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) { - // Do nothing, we override this method just to avoid compilation error since - // there are two virtual functions named BeforeUnloadFired. -} - -void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) { - Emit("render-view-deleted", render_view_host->GetProcess()->GetID()); -} - -void WebContents::RenderProcessGone(base::TerminationStatus status) { - Emit("crashed"); -} - -void WebContents::PluginCrashed(const base::FilePath& plugin_path, - base::ProcessId plugin_pid) { - content::WebPluginInfo info; - auto plugin_service = content::PluginService::GetInstance(); - plugin_service->GetPluginInfoByPath(plugin_path, &info); - Emit("plugin-crashed", info.name, info.version); -} - -void WebContents::MediaStartedPlaying(const MediaPlayerId& id) { - Emit("media-started-playing"); -} - -void WebContents::MediaStoppedPlaying(const MediaPlayerId& id) { - Emit("media-paused"); -} - -void WebContents::DidChangeThemeColor(SkColor theme_color) { - std::string hex_theme_color = base::StringPrintf("#%02X%02X%02X", - SkColorGetR(theme_color), - SkColorGetG(theme_color), - SkColorGetB(theme_color)); - Emit("did-change-theme-color", hex_theme_color); -} - -void WebContents::DocumentLoadedInFrame( - content::RenderFrameHost* render_frame_host) { - if (!render_frame_host->GetParent()) - Emit("dom-ready"); -} - -void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host, - const GURL& validated_url) { - bool is_main_frame = !render_frame_host->GetParent(); - Emit("did-frame-finish-load", is_main_frame); - - if (is_main_frame) - Emit("did-finish-load"); -} - -void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host, - const GURL& url, - int error_code, - const base::string16& error_description, - bool was_ignored_by_handler) { - bool is_main_frame = !render_frame_host->GetParent(); - Emit("did-fail-load", error_code, error_description, url, is_main_frame); -} - -void WebContents::DidStartLoading() { - Emit("did-start-loading"); -} - -void WebContents::DidStopLoading() { - Emit("did-stop-loading"); -} - -void WebContents::DidGetResourceResponseStart( - const content::ResourceRequestDetails& details) { - Emit("did-get-response-details", - details.socket_address.IsEmpty(), - details.url, - details.original_url, - details.http_response_code, - details.method, - details.referrer, - details.headers.get(), - ResourceTypeToString(details.resource_type)); -} - -void WebContents::DidGetRedirectForResourceRequest( - content::RenderFrameHost* render_frame_host, - const content::ResourceRedirectDetails& details) { - Emit("did-get-redirect-request", - details.url, - details.new_url, - (details.resource_type == content::RESOURCE_TYPE_MAIN_FRAME), - details.http_response_code, - details.method, - details.referrer, - details.headers.get()); -} - -void WebContents::DidFinishNavigation( - content::NavigationHandle* navigation_handle) { - bool is_main_frame = navigation_handle->IsInMainFrame(); - if (navigation_handle->HasCommitted() && !navigation_handle->IsErrorPage()) { - auto url = navigation_handle->GetURL(); - bool is_in_page = navigation_handle->IsSamePage(); - if (is_main_frame && !is_in_page) { - Emit("did-navigate", url); - } else if (is_in_page) { - Emit("did-navigate-in-page", url); - } - } else { - auto url = navigation_handle->GetURL(); - int code = navigation_handle->GetNetErrorCode(); - auto description = net::ErrorToShortString(code); - Emit("did-fail-provisional-load", code, description, url, is_main_frame); - - // Do not emit "did-fail-load" for canceled requests. - if (code != net::ERR_ABORTED) - Emit("did-fail-load", code, description, url, is_main_frame); - } -} - -void WebContents::TitleWasSet(content::NavigationEntry* entry, - bool explicit_set) { - if (entry) - Emit("-page-title-updated", entry->GetTitle(), explicit_set); - else - Emit("-page-title-updated", "", explicit_set); -} - -void WebContents::DidUpdateFaviconURL( - const std::vector& urls) { - std::set unique_urls; - for (const auto& iter : urls) { - if (iter.icon_type != content::FaviconURL::FAVICON) - continue; - const GURL& url = iter.icon_url; - if (url.is_valid()) - unique_urls.insert(url); - } - Emit("page-favicon-updated", unique_urls); -} - -void WebContents::DevToolsReloadPage() { - Emit("devtools-reload-page"); -} - -void WebContents::DevToolsFocused() { - Emit("devtools-focused"); -} - -void WebContents::DevToolsOpened() { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - auto handle = WebContents::CreateFrom( - isolate(), managed_web_contents()->GetDevToolsWebContents()); - devtools_web_contents_.Reset(isolate(), handle.ToV8()); - - // Set inspected tabID. - base::FundamentalValue tab_id(ID()); - managed_web_contents()->CallClientFunction( - "DevToolsAPI.setInspectedTabId", &tab_id, nullptr, nullptr); - - // Inherit owner window in devtools. - if (owner_window()) - handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(), - owner_window()); - - Emit("devtools-opened"); -} - -void WebContents::DevToolsClosed() { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - devtools_web_contents_.Reset(); - - Emit("devtools-closed"); -} - -bool WebContents::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(WebContents, message) - IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage) - IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync, - OnRendererMessageSync) - IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange, - handled = false) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - return handled; -} - -// There are three ways of destroying a webContents: -// 1. call webContents.destroy(); -// 2. garbage collection; -// 3. user closes the window of webContents; -// For webview only #1 will happen, for BrowserWindow both #1 and #3 may -// happen. The #2 should never happen for webContents, because webview is -// managed by GuestViewManager, and BrowserWindow's webContents is managed -// by api::Window. -// For #1, the destructor will do the cleanup work and we only need to make -// sure "destroyed" event is emitted. For #3, the content::WebContents will -// be destroyed on close, and WebContentsDestroyed would be called for it, so -// we need to make sure the api::WebContents is also deleted. -void WebContents::WebContentsDestroyed() { - // This event is only for internal use, which is emitted when WebContents is - // being destroyed. - Emit("will-destroy"); - - // Cleanup relationships with other parts. - RemoveFromWeakMap(); - - // We can not call Destroy here because we need to call Emit first, but we - // also do not want any method to be used, so just mark as destroyed here. - MarkDestroyed(); - - Emit("destroyed"); - - // Destroy the native class in next tick. - base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure()); -} - -void WebContents::NavigationEntryCommitted( - const content::LoadCommittedDetails& details) { - Emit("navigation-entry-commited", details.entry->GetURL(), - details.is_in_page, details.did_replace_entry); -} - -int WebContents::GetID() const { - return web_contents()->GetRenderProcessHost()->GetID(); -} - -WebContents::Type WebContents::GetType() const { - return type_; -} - -bool WebContents::Equal(const WebContents* web_contents) const { - return GetID() == web_contents->GetID(); -} - -void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) { - if (!url.is_valid()) { - Emit("did-fail-load", - static_cast(net::ERR_INVALID_URL), - net::ErrorToShortString(net::ERR_INVALID_URL), - url.possibly_invalid_spec(), - true); - return; - } - - content::NavigationController::LoadURLParams params(url); - - GURL http_referrer; - if (options.Get("httpReferrer", &http_referrer)) - params.referrer = content::Referrer(http_referrer.GetAsReferrer(), - blink::WebReferrerPolicyDefault); - - std::string user_agent; - if (options.Get("userAgent", &user_agent)) - web_contents()->SetUserAgentOverride(user_agent); - - std::string extra_headers; - if (options.Get("extraHeaders", &extra_headers)) - params.extra_headers = extra_headers; - - params.transition_type = ui::PAGE_TRANSITION_TYPED; - params.should_clear_history_list = true; - params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE; - web_contents()->GetController().LoadURLWithParams(params); - - // Set the background color of RenderWidgetHostView. - // We have to call it right after LoadURL because the RenderViewHost is only - // created after loading a page. - const auto view = web_contents()->GetRenderWidgetHostView(); - WebContentsPreferences* web_preferences = - WebContentsPreferences::FromWebContents(web_contents()); - std::string color_name; - if (web_preferences->web_preferences()->GetString(options::kBackgroundColor, - &color_name)) { - view->SetBackgroundColor(ParseHexColor(color_name)); - } else { - view->SetBackgroundColor(SK_ColorTRANSPARENT); - } - - // For the same reason we can only disable hidden here. - const auto host = static_cast( - view->GetRenderWidgetHost()); - host->disable_hidden_ = !background_throttling_; -} - -void WebContents::DownloadURL(const GURL& url) { - auto browser_context = web_contents()->GetBrowserContext(); - auto download_manager = - content::BrowserContext::GetDownloadManager(browser_context); - - download_manager->DownloadUrl( - content::DownloadUrlParameters::FromWebContents(web_contents(), url)); -} - -GURL WebContents::GetURL() const { - return web_contents()->GetURL(); -} - -base::string16 WebContents::GetTitle() const { - return web_contents()->GetTitle(); -} - -bool WebContents::IsLoading() const { - return web_contents()->IsLoading(); -} - -bool WebContents::IsLoadingMainFrame() const { - // Comparing site instances works because Electron always creates a new site - // instance when navigating, regardless of origin. See AtomBrowserClient. - return (web_contents()->GetLastCommittedURL().is_empty() || - web_contents()->GetSiteInstance() != - web_contents()->GetPendingSiteInstance()) && IsLoading(); -} - -bool WebContents::IsWaitingForResponse() const { - return web_contents()->IsWaitingForResponse(); -} - -void WebContents::Stop() { - web_contents()->Stop(); -} - -void WebContents::GoBack() { - atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); - web_contents()->GetController().GoBack(); -} - -void WebContents::GoForward() { - atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); - web_contents()->GetController().GoForward(); -} - -void WebContents::GoToOffset(int offset) { - atom::AtomBrowserClient::SuppressRendererProcessRestartForOnce(); - web_contents()->GetController().GoToOffset(offset); -} - -bool WebContents::IsCrashed() const { - return web_contents()->IsCrashed(); -} - -void WebContents::SetUserAgent(const std::string& user_agent, - mate::Arguments* args) { - web_contents()->SetUserAgentOverride(user_agent); -} - -std::string WebContents::GetUserAgent() { - return web_contents()->GetUserAgentOverride(); -} - -void WebContents::InsertCSS(const std::string& css) { - web_contents()->InsertCSS(css); -} - -bool WebContents::SavePage(const base::FilePath& full_file_path, - const content::SavePageType& save_type, - const SavePageHandler::SavePageCallback& callback) { - auto handler = new SavePageHandler(web_contents(), callback); - return handler->Handle(full_file_path, save_type); -} - -void WebContents::OpenDevTools(mate::Arguments* args) { - if (type_ == REMOTE) - return; - - std::string state; - if (type_ == WEB_VIEW || !owner_window()) { - state = "detach"; - } else if (args && args->Length() == 1) { - bool detach = false; - mate::Dictionary options; - if (args->GetNext(&options)) { - options.Get("mode", &state); - options.Get("detach", &detach); - if (state.empty() && detach) - state = "detach"; - } - } - managed_web_contents()->SetDockState(state); - managed_web_contents()->ShowDevTools(); -} - -void WebContents::CloseDevTools() { - if (type_ == REMOTE) - return; - - managed_web_contents()->CloseDevTools(); -} - -bool WebContents::IsDevToolsOpened() { - if (type_ == REMOTE) - return false; - - return managed_web_contents()->IsDevToolsViewShowing(); -} - -bool WebContents::IsDevToolsFocused() { - if (type_ == REMOTE) - return false; - - return managed_web_contents()->GetView()->IsDevToolsViewFocused(); -} - -void WebContents::EnableDeviceEmulation( - const blink::WebDeviceEmulationParams& params) { - if (type_ == REMOTE) - return; - - Send(new ViewMsg_EnableDeviceEmulation(routing_id(), params)); -} - -void WebContents::DisableDeviceEmulation() { - if (type_ == REMOTE) - return; - - Send(new ViewMsg_DisableDeviceEmulation(routing_id())); -} - -void WebContents::ToggleDevTools() { - if (IsDevToolsOpened()) - CloseDevTools(); - else - OpenDevTools(nullptr); -} - -void WebContents::InspectElement(int x, int y) { - if (type_ == REMOTE) - return; - - OpenDevTools(nullptr); - scoped_refptr agent( - content::DevToolsAgentHost::GetOrCreateFor(web_contents())); - agent->InspectElement(x, y); -} - -void WebContents::InspectServiceWorker() { - if (type_ == REMOTE) - return; - - for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) { - if (agent_host->GetType() == - content::DevToolsAgentHost::TYPE_SERVICE_WORKER) { - OpenDevTools(nullptr); - managed_web_contents()->AttachTo(agent_host); - break; - } - } -} - -void WebContents::HasServiceWorker( - const base::Callback& callback) { - auto context = GetServiceWorkerContext(web_contents()); - if (!context) - return; - - context->CheckHasServiceWorker(web_contents()->GetLastCommittedURL(), - GURL::EmptyGURL(), - callback); -} - -void WebContents::UnregisterServiceWorker( - const base::Callback& callback) { - auto context = GetServiceWorkerContext(web_contents()); - if (!context) - return; - - context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(), - callback); -} - -void WebContents::SetAudioMuted(bool muted) { - web_contents()->SetAudioMuted(muted); -} - -bool WebContents::IsAudioMuted() { - return web_contents()->IsAudioMuted(); -} - -void WebContents::Print(mate::Arguments* args) { - PrintSettings settings = { false, false }; - if (args->Length() == 1 && !args->GetNext(&settings)) { - args->ThrowError(); - return; - } - - printing::PrintViewManagerBasic::FromWebContents(web_contents())-> - PrintNow(settings.silent, settings.print_background); -} - -void WebContents::PrintToPDF(const base::DictionaryValue& setting, - const PrintToPDFCallback& callback) { - printing::PrintPreviewMessageHandler::FromWebContents(web_contents())-> - PrintToPDF(setting, callback); -} - -void WebContents::AddWorkSpace(mate::Arguments* args, - const base::FilePath& path) { - if (path.empty()) { - args->ThrowError("path cannot be empty"); - return; - } - DevToolsAddFileSystem(path); -} - -void WebContents::RemoveWorkSpace(mate::Arguments* args, - const base::FilePath& path) { - if (path.empty()) { - args->ThrowError("path cannot be empty"); - return; - } - DevToolsRemoveFileSystem(path); -} - -void WebContents::Undo() { - web_contents()->Undo(); -} - -void WebContents::Redo() { - web_contents()->Redo(); -} - -void WebContents::Cut() { - web_contents()->Cut(); -} - -void WebContents::Copy() { - web_contents()->Copy(); -} - -void WebContents::Paste() { - web_contents()->Paste(); -} - -void WebContents::PasteAndMatchStyle() { - web_contents()->PasteAndMatchStyle(); -} - -void WebContents::Delete() { - web_contents()->Delete(); -} - -void WebContents::SelectAll() { - web_contents()->SelectAll(); -} - -void WebContents::Unselect() { - web_contents()->Unselect(); -} - -void WebContents::Replace(const base::string16& word) { - web_contents()->Replace(word); -} - -void WebContents::ReplaceMisspelling(const base::string16& word) { - web_contents()->ReplaceMisspelling(word); -} - -uint32_t WebContents::FindInPage(mate::Arguments* args) { - uint32_t request_id = GetNextRequestId(); - base::string16 search_text; - blink::WebFindOptions options; - if (!args->GetNext(&search_text) || search_text.empty()) { - args->ThrowError("Must provide a non-empty search content"); - return 0; - } - - args->GetNext(&options); - - web_contents()->Find(request_id, search_text, options); - return request_id; -} - -void WebContents::StopFindInPage(content::StopFindAction action) { - web_contents()->StopFinding(action); -} - -void WebContents::ShowDefinitionForSelection() { -#if defined(OS_MACOSX) - const auto view = web_contents()->GetRenderWidgetHostView(); - if (view) - view->ShowDefinitionForSelection(); -#endif -} - -void WebContents::CopyImageAt(int x, int y) { - const auto host = web_contents()->GetRenderViewHost(); - if (host) - host->CopyImageAt(x, y); -} - -void WebContents::Focus() { - web_contents()->Focus(); -} - -#if !defined(OS_MACOSX) -bool WebContents::IsFocused() const { - auto view = web_contents()->GetRenderWidgetHostView(); - return view && view->HasFocus(); -} -#endif - -void WebContents::TabTraverse(bool reverse) { - web_contents()->FocusThroughTabTraversal(reverse); -} - -bool WebContents::SendIPCMessage(bool all_frames, - const base::string16& channel, - const base::ListValue& args) { - return Send(new AtomViewMsg_Message(routing_id(), all_frames, channel, args)); -} - -void WebContents::SendInputEvent(v8::Isolate* isolate, - v8::Local input_event) { - const auto view = web_contents()->GetRenderWidgetHostView(); - if (!view) - return; - const auto host = view->GetRenderWidgetHost(); - if (!host) - return; - - int type = mate::GetWebInputEventType(isolate, input_event); - if (blink::WebInputEvent::isMouseEventType(type)) { - blink::WebMouseEvent mouse_event; - if (mate::ConvertFromV8(isolate, input_event, &mouse_event)) { - host->ForwardMouseEvent(mouse_event); - return; - } - } else if (blink::WebInputEvent::isKeyboardEventType(type)) { - content::NativeWebKeyboardEvent keyboard_event; - if (mate::ConvertFromV8(isolate, input_event, &keyboard_event)) { - host->ForwardKeyboardEvent(keyboard_event); - return; - } - } else if (type == blink::WebInputEvent::MouseWheel) { - blink::WebMouseWheelEvent mouse_wheel_event; - if (mate::ConvertFromV8(isolate, input_event, &mouse_wheel_event)) { - host->ForwardWheelEvent(mouse_wheel_event); - return; - } - } - - isolate->ThrowException(v8::Exception::Error(mate::StringToV8( - isolate, "Invalid event object"))); -} - -void WebContents::BeginFrameSubscription(mate::Arguments* args) { - bool only_dirty = false; - FrameSubscriber::FrameCaptureCallback callback; - - args->GetNext(&only_dirty); - if (!args->GetNext(&callback)) { - args->ThrowError(); - return; - } - - const auto view = web_contents()->GetRenderWidgetHostView(); - if (view) { - std::unique_ptr frame_subscriber(new FrameSubscriber( - isolate(), view, callback, only_dirty)); - view->BeginFrameSubscription(std::move(frame_subscriber)); - } -} - -void WebContents::EndFrameSubscription() { - const auto view = web_contents()->GetRenderWidgetHostView(); - if (view) - view->EndFrameSubscription(); -} - -void WebContents::StartDrag(const mate::Dictionary& item, - mate::Arguments* args) { - base::FilePath file; - std::vector files; - if (!item.Get("files", &files) && item.Get("file", &file)) { - files.push_back(file); - } - - mate::Handle icon; - if (!item.Get("icon", &icon) && !file.empty()) { - // TODO(zcbenz): Set default icon from file. - } - - // Error checking. - if (icon.IsEmpty()) { - args->ThrowError("icon must be set"); - return; - } - - // Start dragging. - if (!files.empty()) { - base::MessageLoop::ScopedNestableTaskAllower allow( - base::MessageLoop::current()); - DragFileItems(files, icon->image(), web_contents()->GetNativeView()); - } else { - args->ThrowError("There is nothing to drag"); - } -} - -void WebContents::CapturePage(mate::Arguments* args) { - gfx::Rect rect; - base::Callback callback; - - if (!(args->Length() == 1 && args->GetNext(&callback)) && - !(args->Length() == 2 && args->GetNext(&rect) - && args->GetNext(&callback))) { - args->ThrowError(); - return; - } - - const auto view = web_contents()->GetRenderWidgetHostView(); - const auto host = view ? view->GetRenderWidgetHost() : nullptr; - if (!view || !host) { - callback.Run(gfx::Image()); - return; - } - - // Capture full page if user doesn't specify a |rect|. - const gfx::Size view_size = rect.IsEmpty() ? view->GetViewBounds().size() : - rect.size(); - - // By default, the requested bitmap size is the view size in screen - // coordinates. However, if there's more pixel detail available on the - // current system, increase the requested bitmap size to capture it all. - gfx::Size bitmap_size = view_size; - const gfx::NativeView native_view = view->GetNativeView(); - const float scale = - display::Screen::GetScreen()->GetDisplayNearestWindow(native_view) - .device_scale_factor(); - if (scale > 1.0f) - bitmap_size = gfx::ScaleToCeiledSize(view_size, scale); - - host->CopyFromBackingStore(gfx::Rect(rect.origin(), view_size), - bitmap_size, - base::Bind(&OnCapturePageDone, callback), - kBGRA_8888_SkColorType); -} - -void WebContents::OnCursorChange(const content::WebCursor& cursor) { - content::WebCursor::CursorInfo info; - cursor.GetCursorInfo(&info); - - if (cursor.IsCustom()) { - Emit("cursor-changed", CursorTypeToString(info), - gfx::Image::CreateFrom1xBitmap(info.custom_image), - info.image_scale_factor, - gfx::Size(info.custom_image.width(), info.custom_image.height()), - info.hotspot); - } else { - Emit("cursor-changed", CursorTypeToString(info)); - } -} - -void WebContents::SetSize(const SetSizeParams& params) { - if (guest_delegate_) - guest_delegate_->SetSize(params); -} - -bool WebContents::IsGuest() const { - return type_ == WEB_VIEW; -} - -bool WebContents::IsOffScreen() const { - return type_ == OFF_SCREEN; -} - -void WebContents::OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap) { - mate::Handle image = - NativeImage::Create(isolate(), gfx::Image::CreateFrom1xBitmap(bitmap)); - Emit("paint", dirty_rect, image); -} - -void WebContents::StartPainting() { - if (!IsOffScreen()) - return; - - auto* osr_rwhv = static_cast( - web_contents()->GetRenderWidgetHostView()); - if (osr_rwhv) - osr_rwhv->SetPainting(true); -} - -void WebContents::StopPainting() { - if (!IsOffScreen()) - return; - - auto* osr_rwhv = static_cast( - web_contents()->GetRenderWidgetHostView()); - if (osr_rwhv) - osr_rwhv->SetPainting(false); -} - -bool WebContents::IsPainting() const { - if (!IsOffScreen()) - return false; - - const auto* osr_rwhv = static_cast( - web_contents()->GetRenderWidgetHostView()); - return osr_rwhv && osr_rwhv->IsPainting(); -} - -void WebContents::SetFrameRate(int frame_rate) { - if (!IsOffScreen()) - return; - - auto* osr_rwhv = static_cast( - web_contents()->GetRenderWidgetHostView()); - if (osr_rwhv) - osr_rwhv->SetFrameRate(frame_rate); -} - -int WebContents::GetFrameRate() const { - if (!IsOffScreen()) - return 0; - - const auto* osr_rwhv = static_cast( - web_contents()->GetRenderWidgetHostView()); - return osr_rwhv ? osr_rwhv->GetFrameRate() : 0; -} - - -v8::Local WebContents::GetWebPreferences(v8::Isolate* isolate) { - WebContentsPreferences* web_preferences = - WebContentsPreferences::FromWebContents(web_contents()); - return mate::ConvertToV8(isolate, *web_preferences->web_preferences()); -} - -v8::Local WebContents::GetOwnerBrowserWindow() { - if (owner_window()) - return Window::From(isolate(), owner_window()); - else - return v8::Null(isolate()); -} - -int32_t WebContents::ID() const { - return weak_map_id(); -} - -v8::Local WebContents::Session(v8::Isolate* isolate) { - return v8::Local::New(isolate, session_); -} - -content::WebContents* WebContents::HostWebContents() { - if (!embedder_) - return nullptr; - return embedder_->web_contents(); -} - -v8::Local WebContents::DevToolsWebContents(v8::Isolate* isolate) { - if (devtools_web_contents_.IsEmpty()) - return v8::Null(isolate); - else - return v8::Local::New(isolate, devtools_web_contents_); -} - -v8::Local WebContents::Debugger(v8::Isolate* isolate) { - if (debugger_.IsEmpty()) { - auto handle = atom::api::Debugger::Create(isolate, web_contents()); - debugger_.Reset(isolate, handle.ToV8()); - } - return v8::Local::New(isolate, debugger_); -} - -// static -void WebContents::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "WebContents")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .MakeDestroyable() - .SetMethod("getId", &WebContents::GetID) - .SetMethod("equal", &WebContents::Equal) - .SetMethod("_loadURL", &WebContents::LoadURL) - .SetMethod("downloadURL", &WebContents::DownloadURL) - .SetMethod("_getURL", &WebContents::GetURL) - .SetMethod("getTitle", &WebContents::GetTitle) - .SetMethod("isLoading", &WebContents::IsLoading) - .SetMethod("isLoadingMainFrame", &WebContents::IsLoadingMainFrame) - .SetMethod("isWaitingForResponse", &WebContents::IsWaitingForResponse) - .SetMethod("_stop", &WebContents::Stop) - .SetMethod("_goBack", &WebContents::GoBack) - .SetMethod("_goForward", &WebContents::GoForward) - .SetMethod("_goToOffset", &WebContents::GoToOffset) - .SetMethod("isCrashed", &WebContents::IsCrashed) - .SetMethod("setUserAgent", &WebContents::SetUserAgent) - .SetMethod("getUserAgent", &WebContents::GetUserAgent) - .SetMethod("insertCSS", &WebContents::InsertCSS) - .SetMethod("savePage", &WebContents::SavePage) - .SetMethod("openDevTools", &WebContents::OpenDevTools) - .SetMethod("closeDevTools", &WebContents::CloseDevTools) - .SetMethod("isDevToolsOpened", &WebContents::IsDevToolsOpened) - .SetMethod("isDevToolsFocused", &WebContents::IsDevToolsFocused) - .SetMethod("enableDeviceEmulation", - &WebContents::EnableDeviceEmulation) - .SetMethod("disableDeviceEmulation", - &WebContents::DisableDeviceEmulation) - .SetMethod("toggleDevTools", &WebContents::ToggleDevTools) - .SetMethod("inspectElement", &WebContents::InspectElement) - .SetMethod("setAudioMuted", &WebContents::SetAudioMuted) - .SetMethod("isAudioMuted", &WebContents::IsAudioMuted) - .SetMethod("undo", &WebContents::Undo) - .SetMethod("redo", &WebContents::Redo) - .SetMethod("cut", &WebContents::Cut) - .SetMethod("copy", &WebContents::Copy) - .SetMethod("paste", &WebContents::Paste) - .SetMethod("pasteAndMatchStyle", &WebContents::PasteAndMatchStyle) - .SetMethod("delete", &WebContents::Delete) - .SetMethod("selectAll", &WebContents::SelectAll) - .SetMethod("unselect", &WebContents::Unselect) - .SetMethod("replace", &WebContents::Replace) - .SetMethod("replaceMisspelling", &WebContents::ReplaceMisspelling) - .SetMethod("findInPage", &WebContents::FindInPage) - .SetMethod("stopFindInPage", &WebContents::StopFindInPage) - .SetMethod("focus", &WebContents::Focus) - .SetMethod("isFocused", &WebContents::IsFocused) - .SetMethod("tabTraverse", &WebContents::TabTraverse) - .SetMethod("_send", &WebContents::SendIPCMessage) - .SetMethod("sendInputEvent", &WebContents::SendInputEvent) - .SetMethod("beginFrameSubscription", - &WebContents::BeginFrameSubscription) - .SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription) - .SetMethod("startDrag", &WebContents::StartDrag) - .SetMethod("setSize", &WebContents::SetSize) - .SetMethod("isGuest", &WebContents::IsGuest) - .SetMethod("isOffscreen", &WebContents::IsOffScreen) - .SetMethod("startPainting", &WebContents::StartPainting) - .SetMethod("stopPainting", &WebContents::StopPainting) - .SetMethod("isPainting", &WebContents::IsPainting) - .SetMethod("setFrameRate", &WebContents::SetFrameRate) - .SetMethod("getFrameRate", &WebContents::GetFrameRate) - .SetMethod("getType", &WebContents::GetType) - .SetMethod("getWebPreferences", &WebContents::GetWebPreferences) - .SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow) - .SetMethod("hasServiceWorker", &WebContents::HasServiceWorker) - .SetMethod("unregisterServiceWorker", - &WebContents::UnregisterServiceWorker) - .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker) - .SetMethod("print", &WebContents::Print) - .SetMethod("_printToPDF", &WebContents::PrintToPDF) - .SetMethod("addWorkSpace", &WebContents::AddWorkSpace) - .SetMethod("removeWorkSpace", &WebContents::RemoveWorkSpace) - .SetMethod("showDefinitionForSelection", - &WebContents::ShowDefinitionForSelection) - .SetMethod("copyImageAt", &WebContents::CopyImageAt) - .SetMethod("capturePage", &WebContents::CapturePage) - .SetProperty("id", &WebContents::ID) - .SetProperty("session", &WebContents::Session) - .SetProperty("hostWebContents", &WebContents::HostWebContents) - .SetProperty("devToolsWebContents", &WebContents::DevToolsWebContents) - .SetProperty("debugger", &WebContents::Debugger); -} - -AtomBrowserContext* WebContents::GetBrowserContext() const { - return static_cast(web_contents()->GetBrowserContext()); -} - -void WebContents::OnRendererMessage(const base::string16& channel, - const base::ListValue& args) { - // webContents.emit(channel, new Event(), args...); - Emit(base::UTF16ToUTF8(channel), args); -} - -void WebContents::OnRendererMessageSync(const base::string16& channel, - const base::ListValue& args, - IPC::Message* message) { - // webContents.emit(channel, new Event(sender, message), args...); - EmitWithSender(base::UTF16ToUTF8(channel), web_contents(), message, args); -} - -// static -mate::Handle WebContents::CreateFrom( - v8::Isolate* isolate, content::WebContents* web_contents) { - // We have an existing WebContents object in JS. - auto existing = TrackableObject::FromWrappedClass(isolate, web_contents); - if (existing) - return mate::CreateHandle(isolate, static_cast(existing)); - - // Otherwise create a new WebContents wrapper object. - return mate::CreateHandle(isolate, new WebContents(isolate, web_contents)); -} - -// static -mate::Handle WebContents::Create( - v8::Isolate* isolate, const mate::Dictionary& options) { - return mate::CreateHandle(isolate, new WebContents(isolate, options)); -} - -} // namespace api - -} // namespace atom - -namespace { - -using atom::api::WebContents; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("WebContents", WebContents::GetConstructor(isolate)->GetFunction()); - dict.SetMethod("create", &WebContents::Create); - dict.SetMethod("fromId", &mate::TrackableObject::FromWeakMapID); - dict.SetMethod("getAllWebContents", - &mate::TrackableObject::GetAll); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_web_contents, Initialize) diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h deleted file mode 100644 index 4fbe7247e1e84..0000000000000 --- a/atom/browser/api/atom_api_web_contents.h +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_ -#define ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_ - -#include -#include - -#include "atom/browser/api/frame_subscriber.h" -#include "atom/browser/api/save_page_handler.h" -#include "atom/browser/api/trackable_object.h" -#include "atom/browser/common_web_contents_delegate.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/common/favicon_url.h" -#include "content/common/cursors/webcursor.h" -#include "native_mate/handle.h" -#include "ui/gfx/image/image.h" - -namespace blink { -struct WebDeviceEmulationParams; -} - -namespace brightray { -class InspectableWebContents; -} - -namespace mate { -class Arguments; -class Dictionary; -} - -namespace atom { - -struct SetSizeParams; -class AtomBrowserContext; -class WebViewGuestDelegate; - -namespace api { - -class WebContents : public mate::TrackableObject, - public CommonWebContentsDelegate, - public content::WebContentsObserver { - public: - enum Type { - BACKGROUND_PAGE, // A DevTools extension background page. - BROWSER_WINDOW, // Used by BrowserWindow. - REMOTE, // Thin wrap around an existing WebContents. - WEB_VIEW, // Used by . - OFF_SCREEN, // Used for offscreen rendering - }; - - // For node.js callback function type: function(error, buffer) - using PrintToPDFCallback = - base::Callback, v8::Local)>; - - // Create from an existing WebContents. - static mate::Handle CreateFrom( - v8::Isolate* isolate, content::WebContents* web_contents); - - // Create a new WebContents. - static mate::Handle Create( - v8::Isolate* isolate, const mate::Dictionary& options); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - int GetID() const; - Type GetType() const; - bool Equal(const WebContents* web_contents) const; - void LoadURL(const GURL& url, const mate::Dictionary& options); - void DownloadURL(const GURL& url); - GURL GetURL() const; - base::string16 GetTitle() const; - bool IsLoading() const; - bool IsLoadingMainFrame() const; - bool IsWaitingForResponse() const; - void Stop(); - void ReloadIgnoringCache(); - void GoBack(); - void GoForward(); - void GoToOffset(int offset); - bool IsCrashed() const; - void SetUserAgent(const std::string& user_agent, mate::Arguments* args); - std::string GetUserAgent(); - void InsertCSS(const std::string& css); - bool SavePage(const base::FilePath& full_file_path, - const content::SavePageType& save_type, - const SavePageHandler::SavePageCallback& callback); - void OpenDevTools(mate::Arguments* args); - void CloseDevTools(); - bool IsDevToolsOpened(); - bool IsDevToolsFocused(); - void ToggleDevTools(); - void EnableDeviceEmulation(const blink::WebDeviceEmulationParams& params); - void DisableDeviceEmulation(); - void InspectElement(int x, int y); - void InspectServiceWorker(); - void HasServiceWorker(const base::Callback&); - void UnregisterServiceWorker(const base::Callback&); - void SetAudioMuted(bool muted); - bool IsAudioMuted(); - void Print(mate::Arguments* args); - - // Print current page as PDF. - void PrintToPDF(const base::DictionaryValue& setting, - const PrintToPDFCallback& callback); - - // DevTools workspace api. - void AddWorkSpace(mate::Arguments* args, const base::FilePath& path); - void RemoveWorkSpace(mate::Arguments* args, const base::FilePath& path); - - // Editing commands. - void Undo(); - void Redo(); - void Cut(); - void Copy(); - void Paste(); - void PasteAndMatchStyle(); - void Delete(); - void SelectAll(); - void Unselect(); - void Replace(const base::string16& word); - void ReplaceMisspelling(const base::string16& word); - uint32_t FindInPage(mate::Arguments* args); - void StopFindInPage(content::StopFindAction action); - void ShowDefinitionForSelection(); - void CopyImageAt(int x, int y); - - // Focus. - void Focus(); - bool IsFocused() const; - void TabTraverse(bool reverse); - - // Send messages to browser. - bool SendIPCMessage(bool all_frames, - const base::string16& channel, - const base::ListValue& args); - - // Send WebInputEvent to the page. - void SendInputEvent(v8::Isolate* isolate, v8::Local input_event); - - // Subscribe to the frame updates. - void BeginFrameSubscription(mate::Arguments* args); - void EndFrameSubscription(); - - // Dragging native items. - void StartDrag(const mate::Dictionary& item, mate::Arguments* args); - - // Captures the page with |rect|, |callback| would be called when capturing is - // done. - void CapturePage(mate::Arguments* args); - - // Methods for creating . - void SetSize(const SetSizeParams& params); - bool IsGuest() const; - - // Methods for offscreen rendering - bool IsOffScreen() const; - void OnPaint(const gfx::Rect& dirty_rect, const SkBitmap& bitmap); - void StartPainting(); - void StopPainting(); - bool IsPainting() const; - void SetFrameRate(int frame_rate); - int GetFrameRate() const; - - // Callback triggered on permission response. - void OnEnterFullscreenModeForTab(content::WebContents* source, - const GURL& origin, - bool allowed); - - // Create window with the given disposition. - void OnCreateWindow(const GURL& target_url, - const std::string& frame_name, - WindowOpenDisposition disposition); - - // Returns the web preferences of current WebContents. - v8::Local GetWebPreferences(v8::Isolate* isolate); - - // Returns the owner window. - v8::Local GetOwnerBrowserWindow(); - - // Properties. - int32_t ID() const; - v8::Local Session(v8::Isolate* isolate); - content::WebContents* HostWebContents(); - v8::Local DevToolsWebContents(v8::Isolate* isolate); - v8::Local Debugger(v8::Isolate* isolate); - - protected: - WebContents(v8::Isolate* isolate, content::WebContents* web_contents); - WebContents(v8::Isolate* isolate, const mate::Dictionary& options); - ~WebContents(); - - // content::WebContentsDelegate: - bool AddMessageToConsole(content::WebContents* source, - int32_t level, - const base::string16& message, - int32_t line_no, - const base::string16& source_id) override; - content::WebContents* OpenURLFromTab( - content::WebContents* source, - const content::OpenURLParams& params) override; - void BeforeUnloadFired(content::WebContents* tab, - bool proceed, - bool* proceed_to_fire_unload) override; - void MoveContents(content::WebContents* source, - const gfx::Rect& pos) override; - void CloseContents(content::WebContents* source) override; - void ActivateContents(content::WebContents* contents) override; - void UpdateTargetURL(content::WebContents* source, const GURL& url) override; - bool IsPopupOrPanel(const content::WebContents* source) const override; - void HandleKeyboardEvent( - content::WebContents* source, - const content::NativeWebKeyboardEvent& event) override; - void EnterFullscreenModeForTab(content::WebContents* source, - const GURL& origin) override; - void ExitFullscreenModeForTab(content::WebContents* source) override; - void RendererUnresponsive(content::WebContents* source) override; - void RendererResponsive(content::WebContents* source) override; - bool HandleContextMenu(const content::ContextMenuParams& params) override; - bool OnGoToEntryOffset(int offset) override; - void FindReply(content::WebContents* web_contents, - int request_id, - int number_of_matches, - const gfx::Rect& selection_rect, - int active_match_ordinal, - bool final_update) override; - bool CheckMediaAccessPermission( - content::WebContents* web_contents, - const GURL& security_origin, - content::MediaStreamType type) override; - void RequestMediaAccessPermission( - content::WebContents* web_contents, - const content::MediaStreamRequest& request, - const content::MediaResponseCallback& callback) override; - void RequestToLockMouse( - content::WebContents* web_contents, - bool user_gesture, - bool last_unlocked_by_target) override; - std::unique_ptr RunBluetoothChooser( - content::RenderFrameHost* frame, - const content::BluetoothChooser::EventHandler& handler) override; - - // content::WebContentsObserver: - void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; - void RenderViewDeleted(content::RenderViewHost*) override; - void RenderProcessGone(base::TerminationStatus status) override; - void DocumentLoadedInFrame( - content::RenderFrameHost* render_frame_host) override; - void DidFinishLoad(content::RenderFrameHost* render_frame_host, - const GURL& validated_url) override; - void DidFailLoad(content::RenderFrameHost* render_frame_host, - const GURL& validated_url, - int error_code, - const base::string16& error_description, - bool was_ignored_by_handler) override; - void DidStartLoading() override; - void DidStopLoading() override; - void DidGetResourceResponseStart( - const content::ResourceRequestDetails& details) override; - void DidGetRedirectForResourceRequest( - content::RenderFrameHost* render_frame_host, - const content::ResourceRedirectDetails& details) override; - void DidFinishNavigation( - content::NavigationHandle* navigation_handle) override; - bool OnMessageReceived(const IPC::Message& message) override; - void WebContentsDestroyed() override; - void NavigationEntryCommitted( - const content::LoadCommittedDetails& load_details) override; - void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override; - void DidUpdateFaviconURL( - const std::vector& urls) override; - void PluginCrashed(const base::FilePath& plugin_path, - base::ProcessId plugin_pid) override; - void MediaStartedPlaying(const MediaPlayerId& id) override; - void MediaStoppedPlaying(const MediaPlayerId& id) override; - void DidChangeThemeColor(SkColor theme_color) override; - - // brightray::InspectableWebContentsDelegate: - void DevToolsReloadPage() override; - - // brightray::InspectableWebContentsViewDelegate: - void DevToolsFocused() override; - void DevToolsOpened() override; - void DevToolsClosed() override; - - private: - AtomBrowserContext* GetBrowserContext() const; - - uint32_t GetNextRequestId() { - return ++request_id_; - } - - // Called when we receive a CursorChange message from chromium. - void OnCursorChange(const content::WebCursor& cursor); - - // Called when received a message from renderer. - void OnRendererMessage(const base::string16& channel, - const base::ListValue& args); - - // Called when received a synchronous message from renderer. - void OnRendererMessageSync(const base::string16& channel, - const base::ListValue& args, - IPC::Message* message); - - v8::Global session_; - v8::Global devtools_web_contents_; - v8::Global debugger_; - - std::unique_ptr guest_delegate_; - - // The host webcontents that may contain this webcontents. - WebContents* embedder_; - - // The type of current WebContents. - Type type_; - - // Request id used for findInPage request. - uint32_t request_id_; - - // Whether background throttling is disabled. - bool background_throttling_; - - DISALLOW_COPY_AND_ASSIGN(WebContents); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_WEB_CONTENTS_H_ diff --git a/atom/browser/api/atom_api_web_contents_mac.mm b/atom/browser/api/atom_api_web_contents_mac.mm deleted file mode 100644 index 913951737fe88..0000000000000 --- a/atom/browser/api/atom_api_web_contents_mac.mm +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_web_contents.h" - -@interface NSWindow -- (BOOL)isKeyWindow; -@end - -namespace atom { - -namespace api { - -bool WebContents::IsFocused() const { - auto view = web_contents()->GetRenderWidgetHostView(); - if (!view) return false; - - if (GetType() != BACKGROUND_PAGE) { - auto window = web_contents()->GetTopLevelNativeWindow(); - // On Mac the render widget host view does not lose focus when the window - // loses focus so check if the top level window is the key window. - if (window && ![window isKeyWindow]) - return false; - } - - return view->HasFocus(); -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/atom_api_web_request.cc b/atom/browser/api/atom_api_web_request.cc deleted file mode 100644 index 2a39347d02ab3..0000000000000 --- a/atom/browser/api/atom_api_web_request.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_web_request.h" - -#include - -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/net/atom_network_delegate.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/net_converter.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "content/public/browser/browser_thread.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" - -using content::BrowserThread; - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - extensions::URLPattern* out) { - std::string pattern; - if (!ConvertFromV8(isolate, val, &pattern)) - return false; - return out->Parse(pattern) == extensions::URLPattern::PARSE_SUCCESS; - } -}; - -} // namespace mate - -namespace atom { - -namespace api { - -WebRequest::WebRequest(v8::Isolate* isolate, - AtomBrowserContext* browser_context) - : browser_context_(browser_context) { - Init(isolate); -} - -WebRequest::~WebRequest() { -} - -template -void WebRequest::SetSimpleListener(mate::Arguments* args) { - SetListener( - &AtomNetworkDelegate::SetSimpleListenerInIO, type, args); -} - -template -void WebRequest::SetResponseListener(mate::Arguments* args) { - SetListener( - &AtomNetworkDelegate::SetResponseListenerInIO, type, args); -} - -template -void WebRequest::SetListener(Method method, Event type, mate::Arguments* args) { - // { urls }. - URLPatterns patterns; - mate::Dictionary dict; - args->GetNext(&dict) && dict.Get("urls", &patterns); - - // Function or null. - v8::Local value; - Listener listener; - if (!args->GetNext(&listener) && - !(args->GetNext(&value) && value->IsNull())) { - args->ThrowError("Must pass null or a Function"); - return; - } - - auto delegate = browser_context_->network_delegate(); - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(method, base::Unretained(delegate), type, - patterns, listener)); -} - -// static -mate::Handle WebRequest::Create( - v8::Isolate* isolate, - AtomBrowserContext* browser_context) { - return mate::CreateHandle(isolate, new WebRequest(isolate, browser_context)); -} - -// static -void WebRequest::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "WebRequest")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("onBeforeRequest", - &WebRequest::SetResponseListener< - AtomNetworkDelegate::kOnBeforeRequest>) - .SetMethod("onBeforeSendHeaders", - &WebRequest::SetResponseListener< - AtomNetworkDelegate::kOnBeforeSendHeaders>) - .SetMethod("onHeadersReceived", - &WebRequest::SetResponseListener< - AtomNetworkDelegate::kOnHeadersReceived>) - .SetMethod("onSendHeaders", - &WebRequest::SetSimpleListener< - AtomNetworkDelegate::kOnSendHeaders>) - .SetMethod("onBeforeRedirect", - &WebRequest::SetSimpleListener< - AtomNetworkDelegate::kOnBeforeRedirect>) - .SetMethod("onResponseStarted", - &WebRequest::SetSimpleListener< - AtomNetworkDelegate::kOnResponseStarted>) - .SetMethod("onCompleted", - &WebRequest::SetSimpleListener< - AtomNetworkDelegate::kOnCompleted>) - .SetMethod("onErrorOccurred", - &WebRequest::SetSimpleListener< - AtomNetworkDelegate::kOnErrorOccurred>); -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/atom_api_web_request.h b/atom/browser/api/atom_api_web_request.h deleted file mode 100644 index b05a4e11b989f..0000000000000 --- a/atom/browser/api/atom_api_web_request.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_ -#define ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_ - -#include "atom/browser/api/trackable_object.h" -#include "atom/browser/net/atom_network_delegate.h" -#include "native_mate/arguments.h" -#include "native_mate/handle.h" - -namespace atom { - -class AtomBrowserContext; - -namespace api { - -class WebRequest : public mate::TrackableObject { - public: - static mate::Handle Create(v8::Isolate* isolate, - AtomBrowserContext* browser_context); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - protected: - WebRequest(v8::Isolate* isolate, AtomBrowserContext* browser_context); - ~WebRequest() override; - - // C++ can not distinguish overloaded member function. - template - void SetSimpleListener(mate::Arguments* args); - template - void SetResponseListener(mate::Arguments* args); - template - void SetListener(Method method, Event type, mate::Arguments* args); - - private: - scoped_refptr browser_context_; - - DISALLOW_COPY_AND_ASSIGN(WebRequest); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_ATOM_API_WEB_REQUEST_H_ diff --git a/atom/browser/api/atom_api_web_view_manager.cc b/atom/browser/api/atom_api_web_view_manager.cc deleted file mode 100644 index 1586c3a10dded..0000000000000 --- a/atom/browser/api/atom_api_web_view_manager.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/web_contents_preferences.h" -#include "atom/browser/web_view_manager.h" -#include "atom/common/native_mate_converters/content_converter.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_includes.h" -#include "content/public/browser/browser_context.h" -#include "native_mate/dictionary.h" - -using atom::WebContentsPreferences; - -namespace { - -void AddGuest(int guest_instance_id, - int element_instance_id, - content::WebContents* embedder, - content::WebContents* guest_web_contents, - const base::DictionaryValue& options) { - auto manager = atom::WebViewManager::GetWebViewManager(embedder); - if (manager) - manager->AddGuest(guest_instance_id, element_instance_id, embedder, - guest_web_contents); - - WebContentsPreferences::FromWebContents(guest_web_contents)->Merge(options); -} - -void RemoveGuest(content::WebContents* embedder, int guest_instance_id) { - auto manager = atom::WebViewManager::GetWebViewManager(embedder); - if (manager) - manager->RemoveGuest(guest_instance_id); -} - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("addGuest", &AddGuest); - dict.SetMethod("removeGuest", &RemoveGuest); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_web_view_manager, Initialize) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc deleted file mode 100644 index fad41417755ac..0000000000000 --- a/atom/browser/api/atom_api_window.cc +++ /dev/null @@ -1,906 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/atom_api_window.h" -#include "atom/common/native_mate_converters/value_converter.h" - -#include "atom/browser/api/atom_api_menu.h" -#include "atom/browser/api/atom_api_web_contents.h" -#include "atom/browser/browser.h" -#include "atom/browser/native_window.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/gfx_converter.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/native_mate_converters/image_converter.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "atom/common/node_includes.h" -#include "atom/common/options_switches.h" -#include "base/command_line.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/common/content_switches.h" -#include "native_mate/constructor.h" -#include "native_mate/dictionary.h" -#include "ui/gfx/geometry/rect.h" - -#if defined(TOOLKIT_VIEWS) -#include "atom/browser/native_window_views.h" -#endif - -#if defined(OS_WIN) -#include "atom/browser/ui/win/taskbar_host.h" -#endif - -#if defined(OS_WIN) -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Handle val, - atom::TaskbarHost::ThumbarButton* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - dict.Get("click", &(out->clicked_callback)); - dict.Get("tooltip", &(out->tooltip)); - dict.Get("flags", &out->flags); - return dict.Get("icon", &(out->icon)); - } -}; - -} // namespace mate -#endif - -namespace atom { - -namespace api { - -namespace { - -// Converts binary data to Buffer. -v8::Local ToBuffer(v8::Isolate* isolate, void* val, int size) { - auto buffer = node::Buffer::Copy(isolate, static_cast(val), size); - if (buffer.IsEmpty()) - return v8::Null(isolate); - else - return buffer.ToLocalChecked(); -} - -} // namespace - - -Window::Window(v8::Isolate* isolate, v8::Local wrapper, - const mate::Dictionary& options) { - // Use options.webPreferences to create WebContents. - mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate); - options.Get(options::kWebPreferences, &web_preferences); - - // Copy the backgroundColor to webContents. - v8::Local value; - if (options.Get(options::kBackgroundColor, &value)) - web_preferences.Set(options::kBackgroundColor, value); - - v8::Local transparent; - if (options.Get("transparent", &transparent)) - web_preferences.Set("transparent", transparent); - - // Creates the WebContents used by BrowserWindow. - auto web_contents = WebContents::Create(isolate, web_preferences); - web_contents_.Reset(isolate, web_contents.ToV8()); - api_web_contents_ = web_contents.get(); - - // Keep a copy of the options for later use. - mate::Dictionary(isolate, web_contents->GetWrapper()).Set( - "browserWindowOptions", options); - - // The parent window. - mate::Handle parent; - if (options.Get("parent", &parent)) - parent_window_.Reset(isolate, parent.ToV8()); - - // Creates BrowserWindow. - window_.reset(NativeWindow::Create( - web_contents->managed_web_contents(), - options, - parent.IsEmpty() ? nullptr : parent->window_.get())); - web_contents->SetOwnerWindow(window_.get()); - -#if defined(TOOLKIT_VIEWS) - // Sets the window icon. - mate::Handle icon; - if (options.Get(options::kIcon, &icon)) - SetIcon(icon); -#endif - - window_->InitFromOptions(options); - window_->AddObserver(this); - - InitWith(isolate, wrapper); - AttachAsUserData(window_.get()); - - // We can only append this window to parent window's child windows after this - // window's JS wrapper gets initialized. - if (!parent.IsEmpty()) - parent->child_windows_.Set(isolate, ID(), wrapper); -} - -Window::~Window() { - if (!window_->IsClosed()) - window_->CloseContents(nullptr); - - // Destroy the native window in next tick because the native code might be - // iterating all windows. - base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release()); -} - -void Window::WillCloseWindow(bool* prevent_default) { - *prevent_default = Emit("close"); -} - -void Window::WillDestoryNativeObject() { - // Close all child windows before closing current window. - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - for (v8::Local value : child_windows_.Values(isolate())) { - mate::Handle child; - if (mate::ConvertFromV8(isolate(), value, &child)) - child->window_->CloseImmediately(); - } -} - -void Window::OnWindowClosed() { - api_web_contents_->DestroyWebContents(); - - RemoveFromWeakMap(); - window_->RemoveObserver(this); - - // We can not call Destroy here because we need to call Emit first, but we - // also do not want any method to be used, so just mark as destroyed here. - MarkDestroyed(); - - Emit("closed"); - - RemoveFromParentChildWindows(); - - // Destroy the native class when window is closed. - base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure()); -} - -void Window::OnWindowBlur() { - Emit("blur"); -} - -void Window::OnWindowFocus() { - Emit("focus"); -} - -void Window::OnWindowShow() { - Emit("show"); -} - -void Window::OnWindowHide() { - Emit("hide"); -} - -void Window::OnReadyToShow() { - Emit("ready-to-show"); -} - -void Window::OnWindowMaximize() { - Emit("maximize"); -} - -void Window::OnWindowUnmaximize() { - Emit("unmaximize"); -} - -void Window::OnWindowMinimize() { - Emit("minimize"); -} - -void Window::OnWindowRestore() { - Emit("restore"); -} - -void Window::OnWindowResize() { - Emit("resize"); -} - -void Window::OnWindowMove() { - Emit("move"); -} - -void Window::OnWindowMoved() { - Emit("moved"); -} - -void Window::OnWindowEnterFullScreen() { - Emit("enter-full-screen"); -} - -void Window::OnWindowLeaveFullScreen() { - Emit("leave-full-screen"); -} - -void Window::OnWindowScrollTouchBegin() { - Emit("scroll-touch-begin"); -} - -void Window::OnWindowScrollTouchEnd() { - Emit("scroll-touch-end"); -} - -void Window::OnWindowSwipe(const std::string& direction) { - Emit("swipe", direction); -} - -void Window::OnWindowEnterHtmlFullScreen() { - Emit("enter-html-full-screen"); -} - -void Window::OnWindowLeaveHtmlFullScreen() { - Emit("leave-html-full-screen"); -} - -void Window::OnRendererUnresponsive() { - Emit("unresponsive"); -} - -void Window::OnRendererResponsive() { - Emit("responsive"); -} - -void Window::OnExecuteWindowsCommand(const std::string& command_name) { - Emit("app-command", command_name); -} - -#if defined(OS_WIN) -void Window::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) { - if (IsWindowMessageHooked(message)) { - messages_callback_map_[message].Run( - ToBuffer(isolate(), static_cast(&w_param), sizeof(WPARAM)), - ToBuffer(isolate(), static_cast(&l_param), sizeof(LPARAM))); - } -} -#endif - -// static -mate::WrappableBase* Window::New(mate::Arguments* args) { - if (!Browser::Get()->is_ready()) { - args->ThrowError("Cannot create BrowserWindow before app is ready"); - return nullptr; - } - - if (args->Length() > 1) { - args->ThrowError(); - return nullptr; - } - - mate::Dictionary options; - if (!(args->Length() == 1 && args->GetNext(&options))) { - options = mate::Dictionary::CreateEmpty(args->isolate()); - } - - return new Window(args->isolate(), args->GetThis(), options); -} - -void Window::Close() { - window_->Close(); -} - -void Window::Focus() { - window_->Focus(true); -} - -void Window::Blur() { - window_->Focus(false); -} - -bool Window::IsFocused() { - return window_->IsFocused(); -} - -void Window::Show() { - window_->Show(); -} - -void Window::ShowInactive() { - // This method doesn't make sense for modal window.. - if (IsModal()) - return; - - window_->ShowInactive(); -} - -void Window::Hide() { - window_->Hide(); -} - -bool Window::IsVisible() { - return window_->IsVisible(); -} - -bool Window::IsEnabled() { - return window_->IsEnabled(); -} - -void Window::Maximize() { - window_->Maximize(); -} - -void Window::Unmaximize() { - window_->Unmaximize(); -} - -bool Window::IsMaximized() { - return window_->IsMaximized(); -} - -void Window::Minimize() { - window_->Minimize(); -} - -void Window::Restore() { - window_->Restore(); -} - -bool Window::IsMinimized() { - return window_->IsMinimized(); -} - -void Window::SetFullScreen(bool fullscreen) { - window_->SetFullScreen(fullscreen); -} - -bool Window::IsFullscreen() { - return window_->IsFullscreen(); -} - -void Window::SetBounds(const gfx::Rect& bounds, mate::Arguments* args) { - bool animate = false; - args->GetNext(&animate); - window_->SetBounds(bounds, animate); -} - -gfx::Rect Window::GetBounds() { - return window_->GetBounds(); -} - -void Window::SetContentBounds(const gfx::Rect& bounds, mate::Arguments* args) { - bool animate = false; - args->GetNext(&animate); - window_->SetContentBounds(bounds, animate); -} - -gfx::Rect Window::GetContentBounds() { - return window_->GetContentBounds(); -} - -void Window::SetSize(int width, int height, mate::Arguments* args) { - bool animate = false; - args->GetNext(&animate); - window_->SetSize(gfx::Size(width, height), animate); -} - -std::vector Window::GetSize() { - std::vector result(2); - gfx::Size size = window_->GetSize(); - result[0] = size.width(); - result[1] = size.height(); - return result; -} - -void Window::SetContentSize(int width, int height, mate::Arguments* args) { - bool animate = false; - args->GetNext(&animate); - window_->SetContentSize(gfx::Size(width, height), animate); -} - -std::vector Window::GetContentSize() { - std::vector result(2); - gfx::Size size = window_->GetContentSize(); - result[0] = size.width(); - result[1] = size.height(); - return result; -} - -void Window::SetMinimumSize(int width, int height) { - window_->SetMinimumSize(gfx::Size(width, height)); -} - -std::vector Window::GetMinimumSize() { - std::vector result(2); - gfx::Size size = window_->GetMinimumSize(); - result[0] = size.width(); - result[1] = size.height(); - return result; -} - -void Window::SetMaximumSize(int width, int height) { - window_->SetMaximumSize(gfx::Size(width, height)); -} - -std::vector Window::GetMaximumSize() { - std::vector result(2); - gfx::Size size = window_->GetMaximumSize(); - result[0] = size.width(); - result[1] = size.height(); - return result; -} - -void Window::SetSheetOffset(double offsetY, mate::Arguments* args) { - double offsetX = 0.0; - args->GetNext(&offsetX); - window_->SetSheetOffset(offsetX, offsetY); -} - -void Window::SetResizable(bool resizable) { - window_->SetResizable(resizable); -} - -bool Window::IsResizable() { - return window_->IsResizable(); -} - -void Window::SetMovable(bool movable) { - window_->SetMovable(movable); -} - -bool Window::IsMovable() { - return window_->IsMovable(); -} - -void Window::SetMinimizable(bool minimizable) { - window_->SetMinimizable(minimizable); -} - -bool Window::IsMinimizable() { - return window_->IsMinimizable(); -} - -void Window::SetMaximizable(bool maximizable) { - window_->SetMaximizable(maximizable); -} - -bool Window::IsMaximizable() { - return window_->IsMaximizable(); -} - -void Window::SetFullScreenable(bool fullscreenable) { - window_->SetFullScreenable(fullscreenable); -} - -bool Window::IsFullScreenable() { - return window_->IsFullScreenable(); -} - -void Window::SetClosable(bool closable) { - window_->SetClosable(closable); -} - -bool Window::IsClosable() { - return window_->IsClosable(); -} - -void Window::SetAlwaysOnTop(bool top) { - window_->SetAlwaysOnTop(top); -} - -bool Window::IsAlwaysOnTop() { - return window_->IsAlwaysOnTop(); -} - -void Window::Center() { - window_->Center(); -} - -void Window::SetPosition(int x, int y, mate::Arguments* args) { - bool animate = false; - args->GetNext(&animate); - window_->SetPosition(gfx::Point(x, y), animate); -} - -std::vector Window::GetPosition() { - std::vector result(2); - gfx::Point pos = window_->GetPosition(); - result[0] = pos.x(); - result[1] = pos.y(); - return result; -} - -void Window::SetTitle(const std::string& title) { - window_->SetTitle(title); -} - -std::string Window::GetTitle() { - return window_->GetTitle(); -} - -void Window::FlashFrame(bool flash) { - window_->FlashFrame(flash); -} - -void Window::SetSkipTaskbar(bool skip) { - window_->SetSkipTaskbar(skip); -} - -void Window::SetKiosk(bool kiosk) { - window_->SetKiosk(kiosk); -} - -bool Window::IsKiosk() { - return window_->IsKiosk(); -} - -void Window::SetBackgroundColor(const std::string& color_name) { - window_->SetBackgroundColor(color_name); -} - -void Window::SetHasShadow(bool has_shadow) { - window_->SetHasShadow(has_shadow); -} - -bool Window::HasShadow() { - return window_->HasShadow(); -} - -void Window::FocusOnWebView() { - window_->FocusOnWebView(); -} - -void Window::BlurWebView() { - window_->BlurWebView(); -} - -bool Window::IsWebViewFocused() { - return window_->IsWebViewFocused(); -} - -void Window::SetRepresentedFilename(const std::string& filename) { - window_->SetRepresentedFilename(filename); -} - -std::string Window::GetRepresentedFilename() { - return window_->GetRepresentedFilename(); -} - -void Window::SetDocumentEdited(bool edited) { - window_->SetDocumentEdited(edited); -} - -bool Window::IsDocumentEdited() { - return window_->IsDocumentEdited(); -} - -void Window::SetIgnoreMouseEvents(bool ignore) { - return window_->SetIgnoreMouseEvents(ignore); -} - -void Window::SetContentProtection(bool enable) { - return window_->SetContentProtection(enable); -} - -void Window::SetFocusable(bool focusable) { - return window_->SetFocusable(focusable); -} - -void Window::SetProgressBar(double progress) { - window_->SetProgressBar(progress); -} - -void Window::SetOverlayIcon(const gfx::Image& overlay, - const std::string& description) { - window_->SetOverlayIcon(overlay, description); -} - -bool Window::SetThumbarButtons(mate::Arguments* args) { -#if defined(OS_WIN) - std::vector buttons; - if (!args->GetNext(&buttons)) { - args->ThrowError(); - return false; - } - auto window = static_cast(window_.get()); - return window->taskbar_host().SetThumbarButtons( - window->GetAcceleratedWidget(), buttons); -#else - return false; -#endif -} - -void Window::SetMenu(v8::Isolate* isolate, v8::Local value) { - mate::Handle menu; - if (value->IsObject() && - mate::V8ToString(value->ToObject()->GetConstructorName()) == "Menu" && - mate::ConvertFromV8(isolate, value, &menu)) { - menu_.Reset(isolate, menu.ToV8()); - window_->SetMenu(menu->model()); - } else if (value->IsNull()) { - menu_.Reset(); - window_->SetMenu(nullptr); - } else { - isolate->ThrowException(v8::Exception::TypeError( - mate::StringToV8(isolate, "Invalid Menu"))); - } -} - -void Window::SetAutoHideMenuBar(bool auto_hide) { - window_->SetAutoHideMenuBar(auto_hide); -} - -bool Window::IsMenuBarAutoHide() { - return window_->IsMenuBarAutoHide(); -} - -void Window::SetMenuBarVisibility(bool visible) { - window_->SetMenuBarVisibility(visible); -} - -bool Window::IsMenuBarVisible() { - return window_->IsMenuBarVisible(); -} - -#if defined(OS_WIN) -bool Window::HookWindowMessage(UINT message, - const MessageCallback& callback) { - messages_callback_map_[message] = callback; - return true; -} - -void Window::UnhookWindowMessage(UINT message) { - if (!ContainsKey(messages_callback_map_, message)) - return; - - messages_callback_map_.erase(message); -} - -bool Window::IsWindowMessageHooked(UINT message) { - return ContainsKey(messages_callback_map_, message); -} - -void Window::UnhookAllWindowMessages() { - messages_callback_map_.clear(); -} - -bool Window::SetThumbnailClip(const gfx::Rect& region) { - auto window = static_cast(window_.get()); - return window->taskbar_host().SetThumbnailClip( - window_->GetAcceleratedWidget(), region); -} -#endif - -#if defined(TOOLKIT_VIEWS) -void Window::SetIcon(mate::Handle icon) { -#if defined(OS_WIN) - static_cast(window_.get())->SetIcon( - icon->GetHICON(GetSystemMetrics(SM_CXSMICON)), - icon->GetHICON(GetSystemMetrics(SM_CXICON))); -#elif defined(USE_X11) - static_cast(window_.get())->SetIcon( - icon->image().AsImageSkia()); -#endif -} -#endif - -void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) { - gfx::Size extra_size; - args->GetNext(&extra_size); - window_->SetAspectRatio(aspect_ratio, extra_size); -} - -void Window::SetParentWindow(v8::Local value, - mate::Arguments* args) { - if (IsModal()) { - args->ThrowError("Can not be called for modal window"); - return; - } - - mate::Handle parent; - if (value->IsNull()) { - RemoveFromParentChildWindows(); - parent_window_.Reset(); - window_->SetParentWindow(nullptr); - } else if (mate::ConvertFromV8(isolate(), value, &parent)) { - parent_window_.Reset(isolate(), value); - window_->SetParentWindow(parent->window_.get()); - parent->child_windows_.Set(isolate(), ID(), GetWrapper()); - } else { - args->ThrowError("Must pass BrowserWindow instance or null"); - } -} - -v8::Local Window::GetParentWindow() const { - if (parent_window_.IsEmpty()) - return v8::Null(isolate()); - else - return v8::Local::New(isolate(), parent_window_); -} - -std::vector> Window::GetChildWindows() const { - return child_windows_.Values(isolate()); -} - -bool Window::IsModal() const { - return window_->is_modal(); -} - -v8::Local Window::GetNativeWindowHandle() { - gfx::AcceleratedWidget handle = window_->GetAcceleratedWidget(); - return ToBuffer( - isolate(), static_cast(&handle), sizeof(gfx::AcceleratedWidget)); -} - -void Window::SetVisibleOnAllWorkspaces(bool visible) { - return window_->SetVisibleOnAllWorkspaces(visible); -} - -bool Window::IsVisibleOnAllWorkspaces() { - return window_->IsVisibleOnAllWorkspaces(); -} - -int32_t Window::ID() const { - return weak_map_id(); -} - -v8::Local Window::WebContents(v8::Isolate* isolate) { - if (web_contents_.IsEmpty()) - return v8::Null(isolate); - else - return v8::Local::New(isolate, web_contents_); -} - -void Window::RemoveFromParentChildWindows() { - if (parent_window_.IsEmpty()) - return; - - mate::Handle parent; - if (!mate::ConvertFromV8(isolate(), GetParentWindow(), &parent)) - return; - - parent->child_windows_.Remove(ID()); -} - -// static -void Window::BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "BrowserWindow")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .MakeDestroyable() - .SetMethod("close", &Window::Close) - .SetMethod("focus", &Window::Focus) - .SetMethod("blur", &Window::Blur) - .SetMethod("isFocused", &Window::IsFocused) - .SetMethod("show", &Window::Show) - .SetMethod("showInactive", &Window::ShowInactive) - .SetMethod("hide", &Window::Hide) - .SetMethod("isVisible", &Window::IsVisible) - .SetMethod("isEnabled", &Window::IsEnabled) - .SetMethod("maximize", &Window::Maximize) - .SetMethod("unmaximize", &Window::Unmaximize) - .SetMethod("isMaximized", &Window::IsMaximized) - .SetMethod("minimize", &Window::Minimize) - .SetMethod("restore", &Window::Restore) - .SetMethod("isMinimized", &Window::IsMinimized) - .SetMethod("setFullScreen", &Window::SetFullScreen) - .SetMethod("isFullScreen", &Window::IsFullscreen) - .SetMethod("setAspectRatio", &Window::SetAspectRatio) -#if !defined(OS_WIN) - .SetMethod("setParentWindow", &Window::SetParentWindow) -#endif - .SetMethod("getParentWindow", &Window::GetParentWindow) - .SetMethod("getChildWindows", &Window::GetChildWindows) - .SetMethod("isModal", &Window::IsModal) - .SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle) - .SetMethod("getBounds", &Window::GetBounds) - .SetMethod("setBounds", &Window::SetBounds) - .SetMethod("getSize", &Window::GetSize) - .SetMethod("setSize", &Window::SetSize) - .SetMethod("getContentBounds", &Window::GetContentBounds) - .SetMethod("setContentBounds", &Window::SetContentBounds) - .SetMethod("getContentSize", &Window::GetContentSize) - .SetMethod("setContentSize", &Window::SetContentSize) - .SetMethod("setMinimumSize", &Window::SetMinimumSize) - .SetMethod("getMinimumSize", &Window::GetMinimumSize) - .SetMethod("setMaximumSize", &Window::SetMaximumSize) - .SetMethod("getMaximumSize", &Window::GetMaximumSize) - .SetMethod("setSheetOffset", &Window::SetSheetOffset) - .SetMethod("setResizable", &Window::SetResizable) - .SetMethod("isResizable", &Window::IsResizable) - .SetMethod("setMovable", &Window::SetMovable) - .SetMethod("isMovable", &Window::IsMovable) - .SetMethod("setMinimizable", &Window::SetMinimizable) - .SetMethod("isMinimizable", &Window::IsMinimizable) - .SetMethod("setMaximizable", &Window::SetMaximizable) - .SetMethod("isMaximizable", &Window::IsMaximizable) - .SetMethod("setFullScreenable", &Window::SetFullScreenable) - .SetMethod("isFullScreenable", &Window::IsFullScreenable) - .SetMethod("setClosable", &Window::SetClosable) - .SetMethod("isClosable", &Window::IsClosable) - .SetMethod("setAlwaysOnTop", &Window::SetAlwaysOnTop) - .SetMethod("isAlwaysOnTop", &Window::IsAlwaysOnTop) - .SetMethod("center", &Window::Center) - .SetMethod("setPosition", &Window::SetPosition) - .SetMethod("getPosition", &Window::GetPosition) - .SetMethod("setTitle", &Window::SetTitle) - .SetMethod("getTitle", &Window::GetTitle) - .SetMethod("flashFrame", &Window::FlashFrame) - .SetMethod("setSkipTaskbar", &Window::SetSkipTaskbar) - .SetMethod("setKiosk", &Window::SetKiosk) - .SetMethod("isKiosk", &Window::IsKiosk) - .SetMethod("setBackgroundColor", &Window::SetBackgroundColor) - .SetMethod("setHasShadow", &Window::SetHasShadow) - .SetMethod("hasShadow", &Window::HasShadow) - .SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename) - .SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename) - .SetMethod("setDocumentEdited", &Window::SetDocumentEdited) - .SetMethod("isDocumentEdited", &Window::IsDocumentEdited) - .SetMethod("setIgnoreMouseEvents", &Window::SetIgnoreMouseEvents) - .SetMethod("setContentProtection", &Window::SetContentProtection) - .SetMethod("setFocusable", &Window::SetFocusable) - .SetMethod("focusOnWebView", &Window::FocusOnWebView) - .SetMethod("blurWebView", &Window::BlurWebView) - .SetMethod("isWebViewFocused", &Window::IsWebViewFocused) - .SetMethod("setProgressBar", &Window::SetProgressBar) - .SetMethod("setOverlayIcon", &Window::SetOverlayIcon) - .SetMethod("setThumbarButtons", &Window::SetThumbarButtons) - .SetMethod("setMenu", &Window::SetMenu) - .SetMethod("setAutoHideMenuBar", &Window::SetAutoHideMenuBar) - .SetMethod("isMenuBarAutoHide", &Window::IsMenuBarAutoHide) - .SetMethod("setMenuBarVisibility", &Window::SetMenuBarVisibility) - .SetMethod("isMenuBarVisible", &Window::IsMenuBarVisible) - .SetMethod("setVisibleOnAllWorkspaces", - &Window::SetVisibleOnAllWorkspaces) - .SetMethod("isVisibleOnAllWorkspaces", - &Window::IsVisibleOnAllWorkspaces) -#if defined(OS_WIN) - .SetMethod("hookWindowMessage", &Window::HookWindowMessage) - .SetMethod("isWindowMessageHooked", &Window::IsWindowMessageHooked) - .SetMethod("unhookWindowMessage", &Window::UnhookWindowMessage) - .SetMethod("unhookAllWindowMessages", &Window::UnhookAllWindowMessages) - .SetMethod("setThumbnailClip", &Window::SetThumbnailClip) -#endif -#if defined(TOOLKIT_VIEWS) - .SetMethod("setIcon", &Window::SetIcon) -#endif - .SetProperty("id", &Window::ID) - .SetProperty("webContents", &Window::WebContents); -} - -// static -v8::Local Window::From(v8::Isolate* isolate, - NativeWindow* native_window) { - auto existing = TrackableObject::FromWrappedClass(isolate, native_window); - if (existing) - return existing->GetWrapper(); - else - return v8::Null(isolate); -} - -} // namespace api - -} // namespace atom - - -namespace { - -using atom::api::Window; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - Window::SetConstructor(isolate, base::Bind(&Window::New)); - - mate::Dictionary browser_window( - isolate, Window::GetConstructor(isolate)->GetFunction()); - browser_window.SetMethod("fromId", - &mate::TrackableObject::FromWeakMapID); - browser_window.SetMethod("getAllWindows", - &mate::TrackableObject::GetAll); - - mate::Dictionary dict(isolate, exports); - dict.Set("BrowserWindow", browser_window); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_window, Initialize) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h deleted file mode 100644 index e027ceabc7c6e..0000000000000 --- a/atom/browser/api/atom_api_window.h +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_ATOM_API_WINDOW_H_ -#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_ - -#include -#include -#include -#include - -#include "ui/gfx/image/image.h" -#include "atom/browser/api/trackable_object.h" -#include "atom/browser/native_window.h" -#include "atom/browser/native_window_observer.h" -#include "atom/common/api/atom_api_native_image.h" -#include "atom/common/key_weak_map.h" -#include "native_mate/handle.h" - -class GURL; - -namespace gfx { -class Rect; -} - -namespace mate { -class Arguments; -class Dictionary; -} - -namespace atom { - -class NativeWindow; - -namespace api { - -class WebContents; - -class Window : public mate::TrackableObject, - public NativeWindowObserver { - public: - static mate::WrappableBase* New(mate::Arguments* args); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - // Returns the BrowserWindow object from |native_window|. - static v8::Local From(v8::Isolate* isolate, - NativeWindow* native_window); - - NativeWindow* window() const { return window_.get(); } - - protected: - Window(v8::Isolate* isolate, v8::Local wrapper, - const mate::Dictionary& options); - ~Window() override; - - // NativeWindowObserver: - void WillCloseWindow(bool* prevent_default) override; - void WillDestoryNativeObject() override; - void OnWindowClosed() override; - void OnWindowBlur() override; - void OnWindowFocus() override; - void OnWindowShow() override; - void OnWindowHide() override; - void OnReadyToShow() override; - void OnWindowMaximize() override; - void OnWindowUnmaximize() override; - void OnWindowMinimize() override; - void OnWindowRestore() override; - void OnWindowResize() override; - void OnWindowMove() override; - void OnWindowMoved() override; - void OnWindowScrollTouchBegin() override; - void OnWindowScrollTouchEnd() override; - void OnWindowSwipe(const std::string& direction) override; - void OnWindowEnterFullScreen() override; - void OnWindowLeaveFullScreen() override; - void OnWindowEnterHtmlFullScreen() override; - void OnWindowLeaveHtmlFullScreen() override; - void OnRendererUnresponsive() override; - void OnRendererResponsive() override; - void OnExecuteWindowsCommand(const std::string& command_name) override; - - #if defined(OS_WIN) - void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override; - #endif - - private: - // APIs for NativeWindow. - void Close(); - void Focus(); - void Blur(); - bool IsFocused(); - void Show(); - void ShowInactive(); - void Hide(); - bool IsVisible(); - bool IsEnabled(); - void Maximize(); - void Unmaximize(); - bool IsMaximized(); - void Minimize(); - void Restore(); - bool IsMinimized(); - void SetFullScreen(bool fullscreen); - bool IsFullscreen(); - void SetBounds(const gfx::Rect& bounds, mate::Arguments* args); - gfx::Rect GetBounds(); - void SetSize(int width, int height, mate::Arguments* args); - std::vector GetSize(); - void SetContentSize(int width, int height, mate::Arguments* args); - std::vector GetContentSize(); - void SetContentBounds(const gfx::Rect& bounds, mate::Arguments* args); - gfx::Rect GetContentBounds(); - void SetMinimumSize(int width, int height); - std::vector GetMinimumSize(); - void SetMaximumSize(int width, int height); - std::vector GetMaximumSize(); - void SetSheetOffset(double offsetY, mate::Arguments* args); - void SetResizable(bool resizable); - bool IsResizable(); - void SetMovable(bool movable); - bool IsMovable(); - void SetMinimizable(bool minimizable); - bool IsMinimizable(); - void SetMaximizable(bool maximizable); - bool IsMaximizable(); - void SetFullScreenable(bool fullscreenable); - bool IsFullScreenable(); - void SetClosable(bool closable); - bool IsClosable(); - void SetAlwaysOnTop(bool top); - bool IsAlwaysOnTop(); - void Center(); - void SetPosition(int x, int y, mate::Arguments* args); - std::vector GetPosition(); - void SetTitle(const std::string& title); - std::string GetTitle(); - void FlashFrame(bool flash); - void SetSkipTaskbar(bool skip); - void SetKiosk(bool kiosk); - bool IsKiosk(); - void SetBackgroundColor(const std::string& color_name); - void SetHasShadow(bool has_shadow); - bool HasShadow(); - void FocusOnWebView(); - void BlurWebView(); - bool IsWebViewFocused(); - void SetRepresentedFilename(const std::string& filename); - std::string GetRepresentedFilename(); - void SetDocumentEdited(bool edited); - bool IsDocumentEdited(); - void SetIgnoreMouseEvents(bool ignore); - void SetContentProtection(bool enable); - void SetFocusable(bool focusable); - void SetProgressBar(double progress); - void SetOverlayIcon(const gfx::Image& overlay, - const std::string& description); - bool SetThumbarButtons(mate::Arguments* args); - void SetMenu(v8::Isolate* isolate, v8::Local menu); - void SetAutoHideMenuBar(bool auto_hide); - bool IsMenuBarAutoHide(); - void SetMenuBarVisibility(bool visible); - bool IsMenuBarVisible(); - void SetAspectRatio(double aspect_ratio, mate::Arguments* args); - void SetParentWindow(v8::Local value, mate::Arguments* args); - v8::Local GetParentWindow() const; - std::vector> GetChildWindows() const; - bool IsModal() const; - v8::Local GetNativeWindowHandle(); - -#if defined(OS_WIN) - typedef base::Callback, - v8::Local)> MessageCallback; - - bool HookWindowMessage(UINT message, const MessageCallback& callback); - bool IsWindowMessageHooked(UINT message); - void UnhookWindowMessage(UINT message); - void UnhookAllWindowMessages(); - bool SetThumbnailClip(const gfx::Rect& region); -#endif - -#if defined(TOOLKIT_VIEWS) - void SetIcon(mate::Handle icon); -#endif - - void SetVisibleOnAllWorkspaces(bool visible); - bool IsVisibleOnAllWorkspaces(); - - int32_t ID() const; - v8::Local WebContents(v8::Isolate* isolate); - - // Remove this window from parent window's |child_windows_|. - void RemoveFromParentChildWindows(); - -#if defined(OS_WIN) - typedef std::map MessageCallbackMap; - MessageCallbackMap messages_callback_map_; -#endif - - v8::Global web_contents_; - v8::Global menu_; - v8::Global parent_window_; - KeyWeakMap child_windows_; - - api::WebContents* api_web_contents_; - - std::unique_ptr window_; - - DISALLOW_COPY_AND_ASSIGN(Window); -}; - -} // namespace api - -} // namespace atom - - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - atom::NativeWindow** out) { - // null would be tranfered to NULL. - if (val->IsNull()) { - *out = NULL; - return true; - } - - atom::api::Window* window; - if (!Converter::FromV8(isolate, val, &window)) - return false; - *out = window->window(); - return true; - } -}; - -} // namespace mate - -#endif // ATOM_BROWSER_API_ATOM_API_WINDOW_H_ diff --git a/atom/browser/api/event.cc b/atom/browser/api/event.cc deleted file mode 100644 index 8810fed4b9aef..0000000000000 --- a/atom/browser/api/event.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/event.h" - -#include "atom/common/api/api_messages.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "content/public/browser/web_contents.h" -#include "native_mate/object_template_builder.h" - -namespace mate { - -Event::Event(v8::Isolate* isolate) - : sender_(nullptr), - message_(nullptr) { - Init(isolate); -} - -Event::~Event() { -} - -void Event::SetSenderAndMessage(content::WebContents* sender, - IPC::Message* message) { - DCHECK(!sender_); - DCHECK(!message_); - sender_ = sender; - message_ = message; - - Observe(sender); -} - -void Event::WebContentsDestroyed() { - sender_ = nullptr; - message_ = nullptr; -} - -void Event::PreventDefault(v8::Isolate* isolate) { - GetWrapper()->Set(StringToV8(isolate, "defaultPrevented"), - v8::True(isolate)); -} - -bool Event::SendReply(const base::string16& json) { - if (message_ == nullptr || sender_ == nullptr) - return false; - - AtomViewHostMsg_Message_Sync::WriteReplyParams(message_, json); - bool success = sender_->Send(message_); - message_ = nullptr; - sender_ = nullptr; - return success; -} - -// static -Handle Event::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new Event(isolate)); -} - -// static -void Event::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "Event")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("preventDefault", &Event::PreventDefault) - .SetMethod("sendReply", &Event::SendReply); -} - -} // namespace mate diff --git a/atom/browser/api/event.h b/atom/browser/api/event.h deleted file mode 100644 index f08802b4ed15d..0000000000000 --- a/atom/browser/api/event.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_EVENT_H_ -#define ATOM_BROWSER_API_EVENT_H_ - -#include "content/public/browser/web_contents_observer.h" -#include "native_mate/wrappable.h" -#include "native_mate/handle.h" - -namespace IPC { -class Message; -} - -namespace mate { - -class Event : public Wrappable, - public content::WebContentsObserver { - public: - static Handle Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - // Pass the sender and message to be replied. - void SetSenderAndMessage(content::WebContents* sender, IPC::Message* message); - - // event.PreventDefault(). - void PreventDefault(v8::Isolate* isolate); - - // event.sendReply(json), used for replying synchronous message. - bool SendReply(const base::string16& json); - - protected: - explicit Event(v8::Isolate* isolate); - ~Event() override; - - // content::WebContentsObserver implementations: - void WebContentsDestroyed() override; - - private: - // Replyer for the synchronous messages. - content::WebContents* sender_; - IPC::Message* message_; - - DISALLOW_COPY_AND_ASSIGN(Event); -}; - -} // namespace mate - -#endif // ATOM_BROWSER_API_EVENT_H_ diff --git a/atom/browser/api/event_emitter.cc b/atom/browser/api/event_emitter.cc deleted file mode 100644 index 3dbcd0601ef8a..0000000000000 --- a/atom/browser/api/event_emitter.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/event_emitter.h" - -#include "atom/browser/api/event.h" -#include "native_mate/arguments.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" -#include "ui/events/event_constants.h" - -#include "atom/common/node_includes.h" - -namespace mate { - -namespace { - -v8::Persistent event_template; - -void PreventDefault(mate::Arguments* args) { - mate::Dictionary self(args->isolate(), args->GetThis()); - self.Set("defaultPrevented", true); -} - -// Create a pure JavaScript Event object. -v8::Local CreateEventObject(v8::Isolate* isolate) { - if (event_template.IsEmpty()) { - event_template.Reset(isolate, ObjectTemplateBuilder(isolate) - .SetMethod("preventDefault", &PreventDefault) - .Build()); - } - - return v8::Local::New( - isolate, event_template)->NewInstance(); -} - -} // namespace - -namespace internal { - -v8::Local CreateJSEvent( - v8::Isolate* isolate, - v8::Local object, - content::WebContents* sender, - IPC::Message* message) { - v8::Local event; - bool use_native_event = sender && message; - - if (use_native_event) { - mate::Handle native_event = mate::Event::Create(isolate); - native_event->SetSenderAndMessage(sender, message); - event = v8::Local::Cast(native_event.ToV8()); - } else { - event = CreateEventObject(isolate); - } - mate::Dictionary(isolate, event).Set("sender", object); - return event; -} - -v8::Local CreateCustomEvent( - v8::Isolate* isolate, - v8::Local object, - v8::Local custom_event) { - v8::Local event = CreateEventObject(isolate); - (void)event->SetPrototype(custom_event->CreationContext(), custom_event); - mate::Dictionary(isolate, event).Set("sender", object); - return event; -} - -v8::Local CreateEventFromFlags(v8::Isolate* isolate, int flags) { - mate::Dictionary obj = mate::Dictionary::CreateEmpty(isolate); - obj.Set("shiftKey", static_cast(flags & ui::EF_SHIFT_DOWN)); - obj.Set("ctrlKey", static_cast(flags & ui::EF_CONTROL_DOWN)); - obj.Set("altKey", static_cast(flags & ui::EF_ALT_DOWN)); - obj.Set("metaKey", static_cast(flags & ui::EF_COMMAND_DOWN)); - return obj.GetHandle(); -} - -} // namespace internal - -} // namespace mate diff --git a/atom/browser/api/event_emitter.h b/atom/browser/api/event_emitter.h deleted file mode 100644 index ead3beddaac54..0000000000000 --- a/atom/browser/api/event_emitter.h +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_EVENT_EMITTER_H_ -#define ATOM_BROWSER_API_EVENT_EMITTER_H_ - -#include - -#include "atom/common/api/event_emitter_caller.h" -#include "native_mate/wrappable.h" - -namespace content { -class WebContents; -} - -namespace IPC { -class Message; -} - -namespace mate { - -namespace internal { - -v8::Local CreateJSEvent(v8::Isolate* isolate, - v8::Local object, - content::WebContents* sender, - IPC::Message* message); -v8::Local CreateCustomEvent( - v8::Isolate* isolate, - v8::Local object, - v8::Local event); -v8::Local CreateEventFromFlags(v8::Isolate* isolate, int flags); - -} // namespace internal - -// Provide helperers to emit event in JavaScript. -template -class EventEmitter : public Wrappable { - public: - typedef std::vector> ValueArray; - - // Make the convinient methods visible: - // https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-members - v8::Local GetWrapper() { return Wrappable::GetWrapper(); } - v8::Isolate* isolate() const { return Wrappable::isolate(); } - - // this.emit(name, event, args...); - template - bool EmitCustomEvent(const base::StringPiece& name, - v8::Local event, - const Args&... args) { - return EmitWithEvent( - name, - internal::CreateCustomEvent(isolate(), GetWrapper(), event), args...); - } - - // this.emit(name, new Event(flags), args...); - template - bool EmitWithFlags(const base::StringPiece& name, - int flags, - const Args&... args) { - return EmitCustomEvent( - name, - internal::CreateEventFromFlags(isolate(), flags), args...); - } - - // this.emit(name, new Event(), args...); - template - bool Emit(const base::StringPiece& name, const Args&... args) { - return EmitWithSender(name, nullptr, nullptr, args...); - } - - // this.emit(name, new Event(sender, message), args...); - template - bool EmitWithSender(const base::StringPiece& name, - content::WebContents* sender, - IPC::Message* message, - const Args&... args) { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - v8::Local event = internal::CreateJSEvent( - isolate(), GetWrapper(), sender, message); - return EmitWithEvent(name, event, args...); - } - - protected: - EventEmitter() {} - - private: - // this.emit(name, event, args...); - template - bool EmitWithEvent(const base::StringPiece& name, - v8::Local event, - const Args&... args) { - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - EmitEvent(isolate(), GetWrapper(), name, event, args...); - return event->Get( - StringToV8(isolate(), "defaultPrevented"))->BooleanValue(); - } - - DISALLOW_COPY_AND_ASSIGN(EventEmitter); -}; - -} // namespace mate - -#endif // ATOM_BROWSER_API_EVENT_EMITTER_H_ diff --git a/atom/browser/api/frame_subscriber.cc b/atom/browser/api/frame_subscriber.cc deleted file mode 100644 index d6d2cf759e14d..0000000000000 --- a/atom/browser/api/frame_subscriber.cc +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/frame_subscriber.h" - -#include "base/bind.h" -#include "atom/common/native_mate_converters/gfx_converter.h" -#include "atom/common/node_includes.h" -#include "content/public/browser/render_widget_host.h" - -namespace atom { - -namespace api { - -FrameSubscriber::FrameSubscriber(v8::Isolate* isolate, - content::RenderWidgetHostView* view, - const FrameCaptureCallback& callback, - bool only_dirty) - : isolate_(isolate), - view_(view), - callback_(callback), - only_dirty_(only_dirty), - weak_factory_(this) { -} - -bool FrameSubscriber::ShouldCaptureFrame( - const gfx::Rect& dirty_rect, - base::TimeTicks present_time, - scoped_refptr* storage, - DeliverFrameCallback* callback) { - const auto host = view_ ? view_->GetRenderWidgetHost() : nullptr; - if (!view_ || !host) - return false; - - if (dirty_rect.IsEmpty()) - return false; - - gfx::Rect rect = gfx::Rect(view_->GetVisibleViewportSize()); - if (only_dirty_) - rect = dirty_rect; - - host->CopyFromBackingStore( - rect, - rect.size(), - base::Bind(&FrameSubscriber::OnFrameDelivered, - weak_factory_.GetWeakPtr(), callback_, rect), - kBGRA_8888_SkColorType); - - return false; -} - -void FrameSubscriber::OnFrameDelivered(const FrameCaptureCallback& callback, - const gfx::Rect& damage_rect, - const SkBitmap& bitmap, - content::ReadbackResponse response) { - if (response != content::ReadbackResponse::READBACK_SUCCESS) - return; - - v8::Locker locker(isolate_); - v8::HandleScope handle_scope(isolate_); - - size_t rgb_arr_size = bitmap.width() * bitmap.height() * - bitmap.bytesPerPixel(); - v8::MaybeLocal buffer = node::Buffer::New(isolate_, rgb_arr_size); - if (buffer.IsEmpty()) - return; - - bitmap.copyPixelsTo( - reinterpret_cast(node::Buffer::Data(buffer.ToLocalChecked())), - rgb_arr_size); - - v8::Local damage = - mate::Converter::ToV8(isolate_, damage_rect); - - callback_.Run(buffer.ToLocalChecked(), damage); -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/frame_subscriber.h b/atom/browser/api/frame_subscriber.h deleted file mode 100644 index 0da554ac4795f..0000000000000 --- a/atom/browser/api/frame_subscriber.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_FRAME_SUBSCRIBER_H_ -#define ATOM_BROWSER_API_FRAME_SUBSCRIBER_H_ - -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "content/public/browser/render_widget_host_view.h" -#include "content/public/browser/render_widget_host_view_frame_subscriber.h" -#include "content/public/browser/readback_types.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/geometry/size.h" -#include "v8/include/v8.h" - -namespace atom { - -namespace api { - -class FrameSubscriber : public content::RenderWidgetHostViewFrameSubscriber { - public: - using FrameCaptureCallback = - base::Callback, v8::Local)>; - - FrameSubscriber(v8::Isolate* isolate, - content::RenderWidgetHostView* view, - const FrameCaptureCallback& callback, - bool only_dirty); - - bool ShouldCaptureFrame(const gfx::Rect& damage_rect, - base::TimeTicks present_time, - scoped_refptr* storage, - DeliverFrameCallback* callback) override; - - private: - void OnFrameDelivered(const FrameCaptureCallback& callback, - const gfx::Rect& damage_rect, - const SkBitmap& bitmap, - content::ReadbackResponse response); - - v8::Isolate* isolate_; - content::RenderWidgetHostView* view_; - FrameCaptureCallback callback_; - bool only_dirty_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(FrameSubscriber); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_FRAME_SUBSCRIBER_H_ diff --git a/atom/browser/api/save_page_handler.cc b/atom/browser/api/save_page_handler.cc deleted file mode 100644 index e07ec3ac0abb8..0000000000000 --- a/atom/browser/api/save_page_handler.cc +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/save_page_handler.h" - -#include - -#include "atom/browser/atom_browser_context.h" -#include "base/callback.h" -#include "base/files/file_path.h" -#include "content/public/browser/web_contents.h" - -namespace atom { - -namespace api { - -SavePageHandler::SavePageHandler(content::WebContents* web_contents, - const SavePageCallback& callback) - : web_contents_(web_contents), - callback_(callback) { -} - -SavePageHandler::~SavePageHandler() { -} - -void SavePageHandler::OnDownloadCreated(content::DownloadManager* manager, - content::DownloadItem* item) { - // OnDownloadCreated is invoked during WebContents::SavePage, so the |item| - // here is the one stated by WebContents::SavePage. - item->AddObserver(this); -} - -bool SavePageHandler::Handle(const base::FilePath& full_path, - const content::SavePageType& save_type) { - auto download_manager = content::BrowserContext::GetDownloadManager( - web_contents_->GetBrowserContext()); - download_manager->AddObserver(this); - // Chromium will create a 'foo_files' directory under the directory of saving - // page 'foo.html' for holding other resource files of 'foo.html'. - base::FilePath saved_main_directory_path = full_path.DirName().Append( - full_path.RemoveExtension().BaseName().value() + - FILE_PATH_LITERAL("_files")); - bool result = web_contents_->SavePage(full_path, - saved_main_directory_path, - save_type); - download_manager->RemoveObserver(this); - // If initialization fails which means fail to create |DownloadItem|, we need - // to delete the |SavePageHandler| instance to avoid memory-leak. - if (!result) - delete this; - return result; -} - -void SavePageHandler::OnDownloadUpdated(content::DownloadItem* item) { - if (item->IsDone()) { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::Locker locker(isolate); - v8::HandleScope handle_scope(isolate); - if (item->GetState() == content::DownloadItem::COMPLETE) { - callback_.Run(v8::Null(isolate)); - } else { - v8::Local error_message = v8::String::NewFromUtf8( - isolate, "Fail to save page"); - callback_.Run(v8::Exception::Error(error_message)); - } - Destroy(item); - } -} - -void SavePageHandler::Destroy(content::DownloadItem* item) { - item->RemoveObserver(this); - delete this; -} - -} // namespace api - -} // namespace atom diff --git a/atom/browser/api/save_page_handler.h b/atom/browser/api/save_page_handler.h deleted file mode 100644 index 951a9414e03f9..0000000000000 --- a/atom/browser/api/save_page_handler.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_ -#define ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_ - -#include - -#include "content/public/browser/download_item.h" -#include "content/public/browser/download_manager.h" -#include "content/public/browser/save_page_type.h" -#include "v8/include/v8.h" - -namespace base { -class FilePath; -} - -namespace content { -class WebContents; -} - -namespace atom { - -namespace api { - -// A self-destroyed class for handling save page request. -class SavePageHandler : public content::DownloadManager::Observer, - public content::DownloadItem::Observer { - public: - using SavePageCallback = base::Callback)>; - - SavePageHandler(content::WebContents* web_contents, - const SavePageCallback& callback); - ~SavePageHandler(); - - bool Handle(const base::FilePath& full_path, - const content::SavePageType& save_type); - - private: - void Destroy(content::DownloadItem* item); - - // content::DownloadManager::Observer: - void OnDownloadCreated(content::DownloadManager* manager, - content::DownloadItem* item) override; - - // content::DownloadItem::Observer: - void OnDownloadUpdated(content::DownloadItem* item) override; - - content::WebContents* web_contents_; // weak - SavePageCallback callback_; -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_BROWSER_API_SAVE_PAGE_HANDLER_H_ diff --git a/atom/browser/api/trackable_object.cc b/atom/browser/api/trackable_object.cc deleted file mode 100644 index 502757aa237d8..0000000000000 --- a/atom/browser/api/trackable_object.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/api/trackable_object.h" - -#include "atom/browser/atom_browser_main_parts.h" -#include "base/bind.h" -#include "base/supports_user_data.h" - -namespace mate { - -namespace { - -const char* kTrackedObjectKey = "TrackedObjectKey"; - -class IDUserData : public base::SupportsUserData::Data { - public: - explicit IDUserData(int32_t id) : id_(id) {} - - operator int32_t() const { return id_; } - - private: - int32_t id_; - - DISALLOW_COPY_AND_ASSIGN(IDUserData); -}; - -} // namespace - -TrackableObjectBase::TrackableObjectBase() - : weak_map_id_(0), weak_factory_(this) { - cleanup_ = RegisterDestructionCallback(GetDestroyClosure()); -} - -TrackableObjectBase::~TrackableObjectBase() { - cleanup_.Run(); -} - -base::Closure TrackableObjectBase::GetDestroyClosure() { - return base::Bind(&TrackableObjectBase::Destroy, weak_factory_.GetWeakPtr()); -} - -void TrackableObjectBase::Destroy() { - delete this; -} - -void TrackableObjectBase::AttachAsUserData(base::SupportsUserData* wrapped) { - wrapped->SetUserData(kTrackedObjectKey, new IDUserData(weak_map_id_)); -} - -// static -int32_t TrackableObjectBase::GetIDFromWrappedClass(base::SupportsUserData* w) { - auto id = static_cast(w->GetUserData(kTrackedObjectKey)); - if (id) - return *id; - else - return 0; -} - -// static -base::Closure TrackableObjectBase::RegisterDestructionCallback( - const base::Closure& c) { - return atom::AtomBrowserMainParts::Get()->RegisterDestructionCallback(c); -} - -} // namespace mate diff --git a/atom/browser/api/trackable_object.h b/atom/browser/api/trackable_object.h deleted file mode 100644 index 3f04783bcd55f..0000000000000 --- a/atom/browser/api/trackable_object.h +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_API_TRACKABLE_OBJECT_H_ -#define ATOM_BROWSER_API_TRACKABLE_OBJECT_H_ - -#include - -#include "atom/browser/api/event_emitter.h" -#include "atom/common/key_weak_map.h" -#include "base/bind.h" -#include "base/memory/weak_ptr.h" -#include "native_mate/object_template_builder.h" - -namespace base { -class SupportsUserData; -} - -namespace mate { - -// Users should use TrackableObject instead. -class TrackableObjectBase { - public: - TrackableObjectBase(); - - // The ID in weak map. - int32_t weak_map_id() const { return weak_map_id_; } - - // Wrap TrackableObject into a class that SupportsUserData. - void AttachAsUserData(base::SupportsUserData* wrapped); - - protected: - virtual ~TrackableObjectBase(); - - // Returns a closure that can destroy the native class. - base::Closure GetDestroyClosure(); - - // Get the weak_map_id from SupportsUserData. - static int32_t GetIDFromWrappedClass(base::SupportsUserData* wrapped); - - // Register a callback that should be destroyed before JavaScript environment - // gets destroyed. - static base::Closure RegisterDestructionCallback(const base::Closure& c); - - int32_t weak_map_id_; - - private: - void Destroy(); - - base::Closure cleanup_; - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(TrackableObjectBase); -}; - -// All instances of TrackableObject will be kept in a weak map and can be got -// from its ID. -template -class TrackableObject : public TrackableObjectBase, - public mate::EventEmitter { - public: - // Mark the JS object as destroyed. - void MarkDestroyed() { - Wrappable::GetWrapper()->SetAlignedPointerInInternalField(0, nullptr); - } - - // Finds out the TrackableObject from its ID in weak map. - static T* FromWeakMapID(v8::Isolate* isolate, int32_t id) { - if (!weak_map_) - return nullptr; - - v8::MaybeLocal object = weak_map_->Get(isolate, id); - if (object.IsEmpty()) - return nullptr; - - T* self = nullptr; - mate::ConvertFromV8(isolate, object.ToLocalChecked(), &self); - return self; - } - - // Finds out the TrackableObject from the class it wraps. - static T* FromWrappedClass(v8::Isolate* isolate, - base::SupportsUserData* wrapped) { - int32_t id = GetIDFromWrappedClass(wrapped); - if (!id) - return nullptr; - return FromWeakMapID(isolate, id); - } - - // Returns all objects in this class's weak map. - static std::vector> GetAll(v8::Isolate* isolate) { - if (weak_map_) - return weak_map_->Values(isolate); - else - return std::vector>(); - } - - // Removes this instance from the weak map. - void RemoveFromWeakMap() { - if (weak_map_ && weak_map_->Has(weak_map_id())) - weak_map_->Remove(weak_map_id()); - } - - protected: - TrackableObject() {} - - ~TrackableObject() override { - RemoveFromWeakMap(); - } - - void InitWith(v8::Isolate* isolate, v8::Local wrapper) override { - WrappableBase::InitWith(isolate, wrapper); - if (!weak_map_) { - weak_map_ = new atom::KeyWeakMap; - } - weak_map_id_ = ++next_id_; - weak_map_->Set(isolate, weak_map_id_, wrapper); - } - - private: - static int32_t next_id_; - static atom::KeyWeakMap* weak_map_; // leaked on purpose - - DISALLOW_COPY_AND_ASSIGN(TrackableObject); -}; - -template -int32_t TrackableObject::next_id_ = 0; - -template -atom::KeyWeakMap* TrackableObject::weak_map_ = nullptr; - -} // namespace mate - -#endif // ATOM_BROWSER_API_TRACKABLE_OBJECT_H_ diff --git a/atom/browser/atom_access_token_store.cc b/atom/browser/atom_access_token_store.cc deleted file mode 100644 index 5a4482b00b41d..0000000000000 --- a/atom/browser/atom_access_token_store.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_access_token_store.h" - -#include - -#include "atom/browser/atom_browser_context.h" -#include "atom/common/google_api_key.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/geolocation_provider.h" - -namespace atom { - -namespace { - -// Notice that we just combined the api key with the url together here, because -// if we use the standard {url: key} format Chromium would override our key with -// the predefined one in common.gypi of libchromiumcontent, which is empty. -const char* kGeolocationProviderURL = - "https://www.googleapis.com/geolocation/v1/geolocate?key=" - GOOGLEAPIS_API_KEY; - -} // namespace - -AtomAccessTokenStore::AtomAccessTokenStore() { - content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices(); -} - -AtomAccessTokenStore::~AtomAccessTokenStore() { -} - -void AtomAccessTokenStore::LoadAccessTokens( - const LoadAccessTokensCallback& callback) { - content::BrowserThread::PostTaskAndReply( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&AtomAccessTokenStore::GetRequestContextOnUIThread, this), - base::Bind(&AtomAccessTokenStore::RespondOnOriginatingThread, - this, callback)); -} - -void AtomAccessTokenStore::SaveAccessToken(const GURL& server_url, - const base::string16& access_token) { -} - -void AtomAccessTokenStore::GetRequestContextOnUIThread() { - auto browser_context = AtomBrowserContext::From("", false); - request_context_getter_ = browser_context->GetRequestContext(); -} - -void AtomAccessTokenStore::RespondOnOriginatingThread( - const LoadAccessTokensCallback& callback) { - // Equivelent to access_token_map[kGeolocationProviderURL]. - // Somehow base::string16 is causing compilation errors when used in a pair - // of std::map on Linux, this can work around it. - AccessTokenMap access_token_map; - std::pair token_pair; - token_pair.first = GURL(kGeolocationProviderURL); - access_token_map.insert(token_pair); - - callback.Run(access_token_map, request_context_getter_.get()); - request_context_getter_ = nullptr; -} - -} // namespace atom diff --git a/atom/browser/atom_access_token_store.h b/atom/browser/atom_access_token_store.h deleted file mode 100644 index 27c1911a65fa2..0000000000000 --- a/atom/browser/atom_access_token_store.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_ACCESS_TOKEN_STORE_H_ -#define ATOM_BROWSER_ATOM_ACCESS_TOKEN_STORE_H_ - -#include "content/public/browser/access_token_store.h" - -namespace atom { - -class AtomAccessTokenStore : public content::AccessTokenStore { - public: - AtomAccessTokenStore(); - ~AtomAccessTokenStore(); - - // content::AccessTokenStore: - void LoadAccessTokens( - const LoadAccessTokensCallback& callback) override; - void SaveAccessToken(const GURL& server_url, - const base::string16& access_token) override; - - private: - void GetRequestContextOnUIThread(); - void RespondOnOriginatingThread(const LoadAccessTokensCallback& callback); - - scoped_refptr request_context_getter_; - - DISALLOW_COPY_AND_ASSIGN(AtomAccessTokenStore); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_ACCESS_TOKEN_STORE_H_ diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc deleted file mode 100644 index 323acdd9b370a..0000000000000 --- a/atom/browser/atom_browser_client.cc +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_browser_client.h" - -#if defined(OS_WIN) -#include -#endif - -#include "atom/browser/api/atom_api_app.h" -#include "atom/browser/atom_access_token_store.h" -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/browser/atom_quota_permission_context.h" -#include "atom/browser/atom_resource_dispatcher_host_delegate.h" -#include "atom/browser/atom_speech_recognition_manager_delegate.h" -#include "atom/browser/native_window.h" -#include "atom/browser/web_contents_permission_helper.h" -#include "atom/browser/web_contents_preferences.h" -#include "atom/browser/window_list.h" -#include "atom/common/options_switches.h" -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "base/strings/string_number_conversions.h" -#include "chrome/browser/printing/printing_message_filter.h" -#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h" -#include "chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.h" -#include "chrome/browser/speech/tts_message_filter.h" -#include "content/public/browser/browser_ppapi_host.h" -#include "content/public/browser/client_certificate_delegate.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/resource_dispatcher_host.h" -#include "content/public/browser/site_instance.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/web_preferences.h" -#include "net/ssl/ssl_cert_request_info.h" -#include "ppapi/host/ppapi_host.h" -#include "ui/base/l10n/l10n_util.h" -#include "v8/include/v8.h" - -namespace atom { - -namespace { - -// Next navigation should not restart renderer process. -bool g_suppress_renderer_process_restart = false; - -// Custom schemes to be registered to handle service worker. -std::string g_custom_service_worker_schemes = ""; - -void Noop(scoped_refptr) { -} - -} // namespace - -// static -void AtomBrowserClient::SuppressRendererProcessRestartForOnce() { - g_suppress_renderer_process_restart = true; -} - -void AtomBrowserClient::SetCustomServiceWorkerSchemes( - const std::vector& schemes) { - g_custom_service_worker_schemes = base::JoinString(schemes, ","); -} - -AtomBrowserClient::AtomBrowserClient() : delegate_(nullptr) { -} - -AtomBrowserClient::~AtomBrowserClient() { -} - -content::WebContents* AtomBrowserClient::GetWebContentsFromProcessID( - int process_id) { - // If the process is a pending process, we should use the old one. - if (ContainsKey(pending_processes_, process_id)) - process_id = pending_processes_[process_id]; - - // Certain render process will be created with no associated render view, - // for example: ServiceWorker. - return WebContentsPreferences::GetWebContentsFromProcessID(process_id); -} - -void AtomBrowserClient::RenderProcessWillLaunch( - content::RenderProcessHost* host) { - int process_id = host->GetID(); - host->AddFilter(new printing::PrintingMessageFilter(process_id)); - host->AddFilter(new TtsMessageFilter(process_id, host->GetBrowserContext())); - host->AddFilter( - new WidevineCdmMessageFilter(process_id, host->GetBrowserContext())); -} - -content::SpeechRecognitionManagerDelegate* - AtomBrowserClient::CreateSpeechRecognitionManagerDelegate() { - return new AtomSpeechRecognitionManagerDelegate; -} - -content::AccessTokenStore* AtomBrowserClient::CreateAccessTokenStore() { - return new AtomAccessTokenStore; -} - -void AtomBrowserClient::OverrideWebkitPrefs( - content::RenderViewHost* host, content::WebPreferences* prefs) { - prefs->javascript_enabled = true; - prefs->web_security_enabled = true; - prefs->javascript_can_open_windows_automatically = true; - prefs->plugins_enabled = true; - prefs->dom_paste_enabled = true; - prefs->allow_scripts_to_close_windows = true; - prefs->javascript_can_access_clipboard = true; - prefs->local_storage_enabled = true; - prefs->databases_enabled = true; - prefs->application_cache_enabled = true; - prefs->allow_universal_access_from_file_urls = true; - prefs->allow_file_access_from_file_urls = true; - prefs->experimental_webgl_enabled = true; - prefs->allow_displaying_insecure_content = false; - prefs->allow_running_insecure_content = false; - - // Custom preferences of guest page. - auto web_contents = content::WebContents::FromRenderViewHost(host); - WebContentsPreferences::OverrideWebkitPrefs(web_contents, prefs); -} - -std::string AtomBrowserClient::GetApplicationLocale() { - return l10n_util::GetApplicationLocale(""); -} - -void AtomBrowserClient::OverrideSiteInstanceForNavigation( - content::BrowserContext* browser_context, - content::SiteInstance* current_instance, - const GURL& url, - content::SiteInstance** new_instance) { - if (g_suppress_renderer_process_restart) { - g_suppress_renderer_process_restart = false; - return; - } - - // Restart renderer process for all navigations except "javacript:" scheme. - if (url.SchemeIs(url::kJavaScriptScheme)) - return; - - scoped_refptr site_instance = - content::SiteInstance::CreateForURL(browser_context, url); - *new_instance = site_instance.get(); - - // Make sure the |site_instance| is not freed when this function returns. - // FIXME(zcbenz): We should adjust OverrideSiteInstanceForNavigation's - // interface to solve this. - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&Noop, base::RetainedRef(site_instance))); - - // Remember the original renderer process of the pending renderer process. - auto current_process = current_instance->GetProcess(); - auto pending_process = (*new_instance)->GetProcess(); - pending_processes_[pending_process->GetID()] = current_process->GetID(); - // Clear the entry in map when process ends. - current_process->AddObserver(this); -} - -void AtomBrowserClient::AppendExtraCommandLineSwitches( - base::CommandLine* command_line, - int process_id) { - std::string process_type = command_line->GetSwitchValueASCII("type"); - if (process_type != "renderer") - return; - - // Copy following switches to child process. - static const char* const kCommonSwitchNames[] = { - switches::kStandardSchemes, - }; - command_line->CopySwitchesFrom( - *base::CommandLine::ForCurrentProcess(), - kCommonSwitchNames, arraysize(kCommonSwitchNames)); - - // The registered service worker schemes. - if (!g_custom_service_worker_schemes.empty()) - command_line->AppendSwitchASCII(switches::kRegisterServiceWorkerSchemes, - g_custom_service_worker_schemes); - -#if defined(OS_WIN) - // Append --app-user-model-id. - PWSTR current_app_id; - if (SUCCEEDED(GetCurrentProcessExplicitAppUserModelID(¤t_app_id))) { - command_line->AppendSwitchNative(switches::kAppUserModelId, current_app_id); - CoTaskMemFree(current_app_id); - } -#endif - - content::WebContents* web_contents = GetWebContentsFromProcessID(process_id); - if (!web_contents) - return; - - WebContentsPreferences::AppendExtraCommandLineSwitches( - web_contents, command_line); -} - -void AtomBrowserClient::DidCreatePpapiPlugin( - content::BrowserPpapiHost* host) { - host->GetPpapiHost()->AddHostFactoryFilter( - base::WrapUnique(new chrome::ChromeBrowserPepperHostFactory(host))); -} - -content::QuotaPermissionContext* - AtomBrowserClient::CreateQuotaPermissionContext() { - return new AtomQuotaPermissionContext; -} - -void AtomBrowserClient::AllowCertificateError( - content::WebContents* web_contents, - int cert_error, - const net::SSLInfo& ssl_info, - const GURL& request_url, - content::ResourceType resource_type, - bool overridable, - bool strict_enforcement, - bool expired_previous_decision, - const base::Callback& callback, - content::CertificateRequestResultType* request) { - if (delegate_) { - delegate_->AllowCertificateError( - web_contents, cert_error, ssl_info, request_url, - resource_type, overridable, strict_enforcement, - expired_previous_decision, callback, request); - } -} - -void AtomBrowserClient::SelectClientCertificate( - content::WebContents* web_contents, - net::SSLCertRequestInfo* cert_request_info, - std::unique_ptr delegate) { - if (!cert_request_info->client_certs.empty() && delegate_) { - delegate_->SelectClientCertificate( - web_contents, cert_request_info, std::move(delegate)); - } -} - -void AtomBrowserClient::ResourceDispatcherHostCreated() { - resource_dispatcher_host_delegate_.reset( - new AtomResourceDispatcherHostDelegate); - content::ResourceDispatcherHost::Get()->SetDelegate( - resource_dispatcher_host_delegate_.get()); -} - -bool AtomBrowserClient::CanCreateWindow( - const GURL& opener_url, - const GURL& opener_top_level_frame_url, - const GURL& source_origin, - WindowContainerType container_type, - const std::string& frame_name, - const GURL& target_url, - const content::Referrer& referrer, - WindowOpenDisposition disposition, - const blink::WebWindowFeatures& features, - bool user_gesture, - bool opener_suppressed, - content::ResourceContext* context, - int render_process_id, - int opener_render_view_id, - int opener_render_frame_id, - bool* no_javascript_access) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - if (delegate_) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&api::App::OnCreateWindow, - base::Unretained(static_cast(delegate_)), - target_url, - frame_name, - disposition, - render_process_id, - opener_render_frame_id)); - } - - return false; -} - -brightray::BrowserMainParts* AtomBrowserClient::OverrideCreateBrowserMainParts( - const content::MainFunctionParams&) { - v8::V8::Initialize(); // Init V8 before creating main parts. - return new AtomBrowserMainParts; -} - -void AtomBrowserClient::WebNotificationAllowed( - int render_process_id, - const base::Callback& callback) { - content::WebContents* web_contents = - WebContentsPreferences::GetWebContentsFromProcessID(render_process_id); - if (!web_contents) { - callback.Run(false, false); - return; - } - auto permission_helper = - WebContentsPermissionHelper::FromWebContents(web_contents); - if (!permission_helper) { - callback.Run(false, false); - return; - } - permission_helper->RequestWebNotificationPermission( - base::Bind(callback, web_contents->IsAudioMuted())); -} - -void AtomBrowserClient::RenderProcessHostDestroyed( - content::RenderProcessHost* host) { - int process_id = host->GetID(); - for (const auto& entry : pending_processes_) { - if (entry.first == process_id || entry.second == process_id) { - pending_processes_.erase(entry.first); - break; - } - } -} - -} // namespace atom diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h deleted file mode 100644 index a61706534aa87..0000000000000 --- a/atom/browser/atom_browser_client.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_ -#define ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_ - -#include -#include -#include - -#include "brightray/browser/browser_client.h" -#include "content/public/browser/render_process_host_observer.h" - -namespace content { -class QuotaPermissionContext; -class ClientCertificateDelegate; -} - -namespace net { -class SSLCertRequestInfo; -} - -namespace atom { - -class AtomResourceDispatcherHostDelegate; - -class AtomBrowserClient : public brightray::BrowserClient, - public content::RenderProcessHostObserver { - public: - AtomBrowserClient(); - virtual ~AtomBrowserClient(); - - using Delegate = content::ContentBrowserClient; - void set_delegate(Delegate* delegate) { delegate_ = delegate; } - - // Returns the WebContents for pending render processes. - content::WebContents* GetWebContentsFromProcessID(int process_id); - - // Don't force renderer process to restart for once. - static void SuppressRendererProcessRestartForOnce(); - - // Custom schemes to be registered to handle service worker. - static void SetCustomServiceWorkerSchemes( - const std::vector& schemes); - - protected: - // content::ContentBrowserClient: - void RenderProcessWillLaunch(content::RenderProcessHost* host) override; - content::SpeechRecognitionManagerDelegate* - CreateSpeechRecognitionManagerDelegate() override; - content::AccessTokenStore* CreateAccessTokenStore() override; - void OverrideWebkitPrefs(content::RenderViewHost* render_view_host, - content::WebPreferences* prefs) override; - std::string GetApplicationLocale() override; - void OverrideSiteInstanceForNavigation( - content::BrowserContext* browser_context, - content::SiteInstance* current_instance, - const GURL& dest_url, - content::SiteInstance** new_instance) override; - void AppendExtraCommandLineSwitches(base::CommandLine* command_line, - int child_process_id) override; - void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override; - content::QuotaPermissionContext* CreateQuotaPermissionContext() override; - void AllowCertificateError( - content::WebContents* web_contents, - int cert_error, - const net::SSLInfo& ssl_info, - const GURL& request_url, - content::ResourceType resource_type, - bool overridable, - bool strict_enforcement, - bool expired_previous_decision, - const base::Callback& callback, - content::CertificateRequestResultType* request) override; - void SelectClientCertificate( - content::WebContents* web_contents, - net::SSLCertRequestInfo* cert_request_info, - std::unique_ptr delegate) override; - void ResourceDispatcherHostCreated() override; - bool CanCreateWindow(const GURL& opener_url, - const GURL& opener_top_level_frame_url, - const GURL& source_origin, - WindowContainerType container_type, - const std::string& frame_name, - const GURL& target_url, - const content::Referrer& referrer, - WindowOpenDisposition disposition, - const blink::WebWindowFeatures& features, - bool user_gesture, - bool opener_suppressed, - content::ResourceContext* context, - int render_process_id, - int opener_render_view_id, - int opener_render_frame_id, - bool* no_javascript_access) override; - - // brightray::BrowserClient: - brightray::BrowserMainParts* OverrideCreateBrowserMainParts( - const content::MainFunctionParams&) override; - void WebNotificationAllowed( - int render_process_id, - const base::Callback& callback) override; - - // content::RenderProcessHostObserver: - void RenderProcessHostDestroyed(content::RenderProcessHost* host) override; - - private: - // pending_render_process => current_render_process. - std::map pending_processes_; - - std::unique_ptr - resource_dispatcher_host_delegate_; - - Delegate* delegate_; - - DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_BROWSER_CLIENT_H_ diff --git a/atom/browser/atom_browser_context.cc b/atom/browser/atom_browser_context.cc deleted file mode 100644 index f9bfe1a94c183..0000000000000 --- a/atom/browser/atom_browser_context.cc +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_browser_context.h" - -#include "atom/browser/api/atom_api_protocol.h" -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/browser/atom_download_manager_delegate.h" -#include "atom/browser/browser.h" -#include "atom/browser/net/atom_cert_verifier.h" -#include "atom/browser/net/atom_network_delegate.h" -#include "atom/browser/net/atom_ssl_config_service.h" -#include "atom/browser/net/atom_url_request_job_factory.h" -#include "atom/browser/net/asar/asar_protocol_handler.h" -#include "atom/browser/net/http_protocol_handler.h" -#include "atom/browser/atom_permission_manager.h" -#include "atom/browser/web_view_manager.h" -#include "atom/common/atom_version.h" -#include "atom/common/chrome_version.h" -#include "atom/common/options_switches.h" -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/memory/ptr_util.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/threading/sequenced_worker_pool.h" -#include "base/threading/worker_pool.h" -#include "chrome/common/chrome_paths.h" -#include "chrome/common/pref_names.h" -#include "components/prefs/pref_registry_simple.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/common/url_constants.h" -#include "content/public/common/user_agent.h" -#include "net/ftp/ftp_network_layer.h" -#include "net/url_request/data_protocol_handler.h" -#include "net/url_request/ftp_protocol_handler.h" -#include "net/url_request/url_request_intercepting_job_factory.h" -#include "net/url_request/url_request_context.h" -#include "url/url_constants.h" - -using content::BrowserThread; - -namespace atom { - -namespace { - -class NoCacheBackend : public net::HttpCache::BackendFactory { - int CreateBackend(net::NetLog* net_log, - std::unique_ptr* backend, - const net::CompletionCallback& callback) override { - return net::ERR_FAILED; - } -}; - -std::string RemoveWhitespace(const std::string& str) { - std::string trimmed; - if (base::RemoveChars(str, " ", &trimmed)) - return trimmed; - else - return str; -} - -} // namespace - -AtomBrowserContext::AtomBrowserContext( - const std::string& partition, bool in_memory, - const base::DictionaryValue& options) - : brightray::BrowserContext(partition, in_memory), - network_delegate_(new AtomNetworkDelegate) { - // Construct user agent string. - Browser* browser = Browser::Get(); - std::string name = RemoveWhitespace(browser->GetName()); - std::string user_agent; - if (name == ATOM_PRODUCT_NAME) { - user_agent = "Chrome/" CHROME_VERSION_STRING " " - ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING; - } else { - user_agent = base::StringPrintf( - "%s/%s Chrome/%s " ATOM_PRODUCT_NAME "/" ATOM_VERSION_STRING, - name.c_str(), - browser->GetVersion().c_str(), - CHROME_VERSION_STRING); - } - user_agent_ = content::BuildUserAgentFromProduct(user_agent); - - // Read options. - use_cache_ = true; - options.GetBoolean("cache", &use_cache_); - - // Initialize Pref Registry in brightray. - InitPrefs(); -} - -AtomBrowserContext::~AtomBrowserContext() { -} - -void AtomBrowserContext::SetUserAgent(const std::string& user_agent) { - user_agent_ = user_agent; -} - -net::NetworkDelegate* AtomBrowserContext::CreateNetworkDelegate() { - return network_delegate_; -} - -std::string AtomBrowserContext::GetUserAgent() { - return user_agent_; -} - -std::unique_ptr -AtomBrowserContext::CreateURLRequestJobFactory( - content::ProtocolHandlerMap* protocol_handlers) { - std::unique_ptr job_factory( - new AtomURLRequestJobFactory); - - for (auto& it : *protocol_handlers) { - job_factory->SetProtocolHandler(it.first, - base::WrapUnique(it.second.release())); - } - protocol_handlers->clear(); - - job_factory->SetProtocolHandler( - url::kDataScheme, base::WrapUnique(new net::DataProtocolHandler)); - job_factory->SetProtocolHandler( - url::kFileScheme, base::WrapUnique(new asar::AsarProtocolHandler( - BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)))); - job_factory->SetProtocolHandler( - url::kHttpScheme, - base::WrapUnique(new HttpProtocolHandler(url::kHttpScheme))); - job_factory->SetProtocolHandler( - url::kHttpsScheme, - base::WrapUnique(new HttpProtocolHandler(url::kHttpsScheme))); - job_factory->SetProtocolHandler( - url::kWsScheme, - base::WrapUnique(new HttpProtocolHandler(url::kWsScheme))); - job_factory->SetProtocolHandler( - url::kWssScheme, - base::WrapUnique(new HttpProtocolHandler(url::kWssScheme))); - - auto host_resolver = - url_request_context_getter()->GetURLRequestContext()->host_resolver(); - job_factory->SetProtocolHandler( - url::kFtpScheme, - base::WrapUnique(new net::FtpProtocolHandler( - new net::FtpNetworkLayer(host_resolver)))); - - return std::move(job_factory); -} - -net::HttpCache::BackendFactory* -AtomBrowserContext::CreateHttpCacheBackendFactory( - const base::FilePath& base_path) { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (!use_cache_ || command_line->HasSwitch(switches::kDisableHttpCache)) - return new NoCacheBackend; - else - return brightray::BrowserContext::CreateHttpCacheBackendFactory(base_path); -} - -content::DownloadManagerDelegate* -AtomBrowserContext::GetDownloadManagerDelegate() { - if (!download_manager_delegate_.get()) { - auto download_manager = content::BrowserContext::GetDownloadManager(this); - download_manager_delegate_.reset( - new AtomDownloadManagerDelegate(download_manager)); - } - return download_manager_delegate_.get(); -} - -content::BrowserPluginGuestManager* AtomBrowserContext::GetGuestManager() { - if (!guest_manager_) - guest_manager_.reset(new WebViewManager); - return guest_manager_.get(); -} - -content::PermissionManager* AtomBrowserContext::GetPermissionManager() { - if (!permission_manager_.get()) - permission_manager_.reset(new AtomPermissionManager); - return permission_manager_.get(); -} - -std::unique_ptr AtomBrowserContext::CreateCertVerifier() { - return base::WrapUnique(new AtomCertVerifier); -} - -net::SSLConfigService* AtomBrowserContext::CreateSSLConfigService() { - return new AtomSSLConfigService; -} - -std::vector AtomBrowserContext::GetCookieableSchemes() { - auto default_schemes = brightray::BrowserContext::GetCookieableSchemes(); - const auto& standard_schemes = atom::api::GetStandardSchemes(); - default_schemes.insert(default_schemes.end(), - standard_schemes.begin(), standard_schemes.end()); - return default_schemes; -} - -void AtomBrowserContext::RegisterPrefs(PrefRegistrySimple* pref_registry) { - pref_registry->RegisterFilePathPref(prefs::kSelectFileLastDirectory, - base::FilePath()); - base::FilePath download_dir; - PathService::Get(chrome::DIR_DEFAULT_DOWNLOADS, &download_dir); - pref_registry->RegisterFilePathPref(prefs::kDownloadDefaultDirectory, - download_dir); - pref_registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths); -} - -// static -scoped_refptr AtomBrowserContext::From( - const std::string& partition, bool in_memory, - const base::DictionaryValue& options) { - auto browser_context = brightray::BrowserContext::Get(partition, in_memory); - if (browser_context) - return static_cast(browser_context.get()); - - return new AtomBrowserContext(partition, in_memory, options); -} - -} // namespace atom diff --git a/atom/browser/atom_browser_context.h b/atom/browser/atom_browser_context.h deleted file mode 100644 index fa3186396ca0b..0000000000000 --- a/atom/browser/atom_browser_context.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_ -#define ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_ - -#include -#include - -#include "brightray/browser/browser_context.h" - -namespace atom { - -class AtomDownloadManagerDelegate; -class AtomNetworkDelegate; -class AtomPermissionManager; -class WebViewManager; - -class AtomBrowserContext : public brightray::BrowserContext { - public: - // Get or create the BrowserContext according to its |partition| and - // |in_memory|. The |options| will be passed to constructor when there is no - // existing BrowserContext. - static scoped_refptr From( - const std::string& partition, bool in_memory, - const base::DictionaryValue& options = base::DictionaryValue()); - - void SetUserAgent(const std::string& user_agent); - - // brightray::URLRequestContextGetter::Delegate: - net::NetworkDelegate* CreateNetworkDelegate() override; - std::string GetUserAgent() override; - std::unique_ptr CreateURLRequestJobFactory( - content::ProtocolHandlerMap* protocol_handlers) override; - net::HttpCache::BackendFactory* CreateHttpCacheBackendFactory( - const base::FilePath& base_path) override; - std::unique_ptr CreateCertVerifier() override; - net::SSLConfigService* CreateSSLConfigService() override; - std::vector GetCookieableSchemes() override; - - // content::BrowserContext: - content::DownloadManagerDelegate* GetDownloadManagerDelegate() override; - content::BrowserPluginGuestManager* GetGuestManager() override; - content::PermissionManager* GetPermissionManager() override; - - // brightray::BrowserContext: - void RegisterPrefs(PrefRegistrySimple* pref_registry) override; - - AtomNetworkDelegate* network_delegate() const { return network_delegate_; } - - protected: - AtomBrowserContext(const std::string& partition, bool in_memory, - const base::DictionaryValue& options); - ~AtomBrowserContext() override; - - private: - std::unique_ptr download_manager_delegate_; - std::unique_ptr guest_manager_; - std::unique_ptr permission_manager_; - std::string user_agent_; - bool use_cache_; - - // Managed by brightray::BrowserContext. - AtomNetworkDelegate* network_delegate_; - - DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_BROWSER_CONTEXT_H_ diff --git a/atom/browser/atom_browser_main_parts.cc b/atom/browser/atom_browser_main_parts.cc deleted file mode 100644 index 6c2f18be0f6e4..0000000000000 --- a/atom/browser/atom_browser_main_parts.cc +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_browser_main_parts.h" - -#include "atom/browser/api/trackable_object.h" -#include "atom/browser/atom_browser_client.h" -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/bridge_task_runner.h" -#include "atom/browser/browser.h" -#include "atom/browser/javascript_environment.h" -#include "atom/browser/node_debugger.h" -#include "atom/common/api/atom_bindings.h" -#include "atom/common/node_bindings.h" -#include "atom/common/node_includes.h" -#include "base/command_line.h" -#include "base/threading/thread_task_runner_handle.h" -#include "chrome/browser/browser_process.h" -#include "content/public/browser/child_process_security_policy.h" -#include "v8/include/v8-debug.h" - -#if defined(USE_X11) -#include "chrome/browser/ui/libgtk2ui/gtk2_util.h" -#include "ui/events/devices/x11/touch_factory_x11.h" -#endif - -namespace atom { - -template -void Erase(T* container, typename T::iterator iter) { - container->erase(iter); -} - -// static -AtomBrowserMainParts* AtomBrowserMainParts::self_ = nullptr; - -AtomBrowserMainParts::AtomBrowserMainParts() - : fake_browser_process_(new BrowserProcess), - exit_code_(nullptr), - browser_(new Browser), - node_bindings_(NodeBindings::Create(true)), - atom_bindings_(new AtomBindings), - gc_timer_(true, true) { - DCHECK(!self_) << "Cannot have two AtomBrowserMainParts"; - self_ = this; - // Register extension scheme as web safe scheme. - content::ChildProcessSecurityPolicy::GetInstance()-> - RegisterWebSafeScheme("chrome-extension"); -} - -AtomBrowserMainParts::~AtomBrowserMainParts() { - // Leak the JavascriptEnvironment on exit. - // This is to work around the bug that V8 would be waiting for background - // tasks to finish on exit, while somehow it waits forever in Electron, more - // about this can be found at https://github.com/electron/electron/issues/4767. - // On the other handle there is actually no need to gracefully shutdown V8 - // on exit in the main process, we already ensured all necessary resources get - // cleaned up, and it would make quitting faster. - ignore_result(js_env_.release()); -} - -// static -AtomBrowserMainParts* AtomBrowserMainParts::Get() { - DCHECK(self_); - return self_; -} - -bool AtomBrowserMainParts::SetExitCode(int code) { - if (!exit_code_) - return false; - - *exit_code_ = code; - return true; -} - -int AtomBrowserMainParts::GetExitCode() { - return exit_code_ != nullptr ? *exit_code_ : 0; -} - -base::Closure AtomBrowserMainParts::RegisterDestructionCallback( - const base::Closure& callback) { - auto iter = destructors_.insert(destructors_.end(), callback); - return base::Bind(&Erase>, &destructors_, iter); -} - -void AtomBrowserMainParts::PreEarlyInitialization() { - brightray::BrowserMainParts::PreEarlyInitialization(); -#if defined(OS_POSIX) - HandleSIGCHLD(); -#endif -} - -void AtomBrowserMainParts::PostEarlyInitialization() { - brightray::BrowserMainParts::PostEarlyInitialization(); - - // Temporary set the bridge_task_runner_ as current thread's task runner, - // so we can fool gin::PerIsolateData to use it as its task runner, instead - // of getting current message loop's task runner, which is null for now. - bridge_task_runner_ = new BridgeTaskRunner; - base::ThreadTaskRunnerHandle handle(bridge_task_runner_); - - // The ProxyResolverV8 has setup a complete V8 environment, in order to - // avoid conflicts we only initialize our V8 environment after that. - js_env_.reset(new JavascriptEnvironment); - - node_bindings_->Initialize(); - - // Support the "--debug" switch. - node_debugger_.reset(new NodeDebugger(js_env_->isolate())); - - // Create the global environment. - node::Environment* env = - node_bindings_->CreateEnvironment(js_env_->context()); - - // Make sure node can get correct environment when debugging. - if (node_debugger_->IsRunning()) - env->AssignToContext(v8::Debug::GetDebugContext()); - - // Add atom-shell extended APIs. - atom_bindings_->BindTo(js_env_->isolate(), env->process_object()); - - // Load everything. - node_bindings_->LoadEnvironment(env); - - // Wrap the uv loop with global env. - node_bindings_->set_uv_env(env); -} - -void AtomBrowserMainParts::PreMainMessageLoopRun() { - js_env_->OnMessageLoopCreated(); - - // Run user's main script before most things get initialized, so we can have - // a chance to setup everything. - node_bindings_->PrepareMessageLoop(); - node_bindings_->RunMessageLoop(); - -#if defined(USE_X11) - ui::TouchFactory::SetTouchDeviceListFromCommandLine(); -#endif - - // Start idle gc. - gc_timer_.Start( - FROM_HERE, base::TimeDelta::FromMinutes(1), - base::Bind(&v8::Isolate::LowMemoryNotification, - base::Unretained(js_env_->isolate()))); - - brightray::BrowserMainParts::PreMainMessageLoopRun(); - bridge_task_runner_->MessageLoopIsReady(); - bridge_task_runner_ = nullptr; - -#if defined(USE_X11) - libgtk2ui::GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess()); -#endif - -#if !defined(OS_MACOSX) - // The corresponding call in macOS is in AtomApplicationDelegate. - Browser::Get()->WillFinishLaunching(); - Browser::Get()->DidFinishLaunching(); -#endif -} - -bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) { - exit_code_ = result_code; - return brightray::BrowserMainParts::MainMessageLoopRun(result_code); -} - -void AtomBrowserMainParts::PostMainMessageLoopStart() { - brightray::BrowserMainParts::PostMainMessageLoopStart(); -#if defined(OS_POSIX) - HandleShutdownSignals(); -#endif -} - -void AtomBrowserMainParts::PostMainMessageLoopRun() { - brightray::BrowserMainParts::PostMainMessageLoopRun(); - - js_env_->OnMessageLoopDestroying(); - -#if defined(OS_MACOSX) - FreeAppDelegate(); -#endif - - // Make sure destruction callbacks are called before message loop is - // destroyed, otherwise some objects that need to be deleted on IO thread - // won't be freed. - // We don't use ranged for loop because iterators are getting invalided when - // the callback runs. - for (auto iter = destructors_.begin(); iter != destructors_.end();) { - base::Closure& callback = *iter; - ++iter; - callback.Run(); - } -} - -} // namespace atom diff --git a/atom/browser/atom_browser_main_parts.h b/atom/browser/atom_browser_main_parts.h deleted file mode 100644 index 0d8619f6865a5..0000000000000 --- a/atom/browser/atom_browser_main_parts.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_ -#define ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_ - -#include -#include - -#include "base/callback.h" -#include "base/timer/timer.h" -#include "brightray/browser/browser_main_parts.h" -#include "content/public/browser/browser_context.h" - -class BrowserProcess; - -namespace atom { - -class AtomBindings; -class Browser; -class JavascriptEnvironment; -class NodeBindings; -class NodeDebugger; -class BridgeTaskRunner; - -class AtomBrowserMainParts : public brightray::BrowserMainParts { - public: - AtomBrowserMainParts(); - virtual ~AtomBrowserMainParts(); - - static AtomBrowserMainParts* Get(); - - // Sets the exit code, will fail if the message loop is not ready. - bool SetExitCode(int code); - - // Gets the exit code - int GetExitCode(); - - // Register a callback that should be destroyed before JavaScript environment - // gets destroyed. - // Returns a closure that can be used to remove |callback| from the list. - base::Closure RegisterDestructionCallback(const base::Closure& callback); - - Browser* browser() { return browser_.get(); } - - protected: - // content::BrowserMainParts: - void PreEarlyInitialization() override; - void PostEarlyInitialization() override; - void PreMainMessageLoopRun() override; - bool MainMessageLoopRun(int* result_code) override; - void PostMainMessageLoopStart() override; - void PostMainMessageLoopRun() override; -#if defined(OS_MACOSX) - void PreMainMessageLoopStart() override; -#endif - - private: -#if defined(OS_POSIX) - // Set signal handlers. - void HandleSIGCHLD(); - void HandleShutdownSignals(); -#endif - -#if defined(OS_MACOSX) - void FreeAppDelegate(); -#endif - - // A fake BrowserProcess object that used to feed the source code from chrome. - std::unique_ptr fake_browser_process_; - - // The gin::PerIsolateData requires a task runner to create, so we feed it - // with a task runner that will post all work to main loop. - scoped_refptr bridge_task_runner_; - - // Pointer to exit code. - int* exit_code_; - - std::unique_ptr browser_; - std::unique_ptr js_env_; - std::unique_ptr node_bindings_; - std::unique_ptr atom_bindings_; - std::unique_ptr node_debugger_; - - base::Timer gc_timer_; - - // List of callbacks should be executed before destroying JS env. - std::list destructors_; - - static AtomBrowserMainParts* self_; - - DISALLOW_COPY_AND_ASSIGN(AtomBrowserMainParts); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_BROWSER_MAIN_PARTS_H_ diff --git a/atom/browser/atom_browser_main_parts_mac.mm b/atom/browser/atom_browser_main_parts_mac.mm deleted file mode 100644 index d6e83fd968b0d..0000000000000 --- a/atom/browser/atom_browser_main_parts_mac.mm +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_browser_main_parts.h" - -#include "atom/browser/mac/atom_application.h" -#include "atom/browser/mac/atom_application_delegate.h" -#include "base/mac/bundle_locations.h" -#include "base/mac/foundation_util.h" -#include "ui/base/l10n/l10n_util_mac.h" - -namespace atom { - -void AtomBrowserMainParts::PreMainMessageLoopStart() { - // Force the NSApplication subclass to be used. - [AtomApplication sharedApplication]; - - // Set our own application delegate. - AtomApplicationDelegate* delegate = [[AtomApplicationDelegate alloc] init]; - [NSApp setDelegate:(id)delegate]; - - brightray::BrowserMainParts::PreMainMessageLoopStart(); - - // Prevent Cocoa from turning command-line arguments into - // |-application:openFiles:|, since we already handle them directly. - [[NSUserDefaults standardUserDefaults] - setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"]; -} - -void AtomBrowserMainParts::FreeAppDelegate() { - [[NSApp delegate] release]; - [NSApp setDelegate:nil]; -} - -} // namespace atom diff --git a/atom/browser/atom_browser_main_parts_posix.cc b/atom/browser/atom_browser_main_parts_posix.cc deleted file mode 100644 index 8c96f91bfe68e..0000000000000 --- a/atom/browser/atom_browser_main_parts_posix.cc +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// Most code came from: chrome/browser/chrome_browser_main_posix.cc. - -#include "atom/browser/atom_browser_main_parts.h" - -#include -#include -#include -#include -#include -#include - -#include "atom/browser/browser.h" -#include "base/posix/eintr_wrapper.h" -#include "content/public/browser/browser_thread.h" - -using content::BrowserThread; - -namespace atom { - -namespace { - -// See comment in |PreEarlyInitialization()|, where sigaction is called. -void SIGCHLDHandler(int signal) { -} - -// The OSX fork() implementation can crash in the child process before -// fork() returns. In that case, the shutdown pipe will still be -// shared with the parent process. To prevent child crashes from -// causing parent shutdowns, |g_pipe_pid| is the pid for the process -// which registered |g_shutdown_pipe_write_fd|. -// See . -pid_t g_pipe_pid = -1; -int g_shutdown_pipe_write_fd = -1; -int g_shutdown_pipe_read_fd = -1; - -// Common code between SIG{HUP, INT, TERM}Handler. -void GracefulShutdownHandler(int signal) { - // Reinstall the default handler. We had one shot at graceful shutdown. - struct sigaction action; - memset(&action, 0, sizeof(action)); - action.sa_handler = SIG_DFL; - RAW_CHECK(sigaction(signal, &action, nullptr) == 0); - - RAW_CHECK(g_pipe_pid == getpid()); - RAW_CHECK(g_shutdown_pipe_write_fd != -1); - RAW_CHECK(g_shutdown_pipe_read_fd != -1); - size_t bytes_written = 0; - do { - int rv = HANDLE_EINTR( - write(g_shutdown_pipe_write_fd, - reinterpret_cast(&signal) + bytes_written, - sizeof(signal) - bytes_written)); - RAW_CHECK(rv >= 0); - bytes_written += rv; - } while (bytes_written < sizeof(signal)); -} - -// See comment in |PostMainMessageLoopStart()|, where sigaction is called. -void SIGHUPHandler(int signal) { - RAW_CHECK(signal == SIGHUP); - GracefulShutdownHandler(signal); -} - -// See comment in |PostMainMessageLoopStart()|, where sigaction is called. -void SIGINTHandler(int signal) { - RAW_CHECK(signal == SIGINT); - GracefulShutdownHandler(signal); -} - -// See comment in |PostMainMessageLoopStart()|, where sigaction is called. -void SIGTERMHandler(int signal) { - RAW_CHECK(signal == SIGTERM); - GracefulShutdownHandler(signal); -} - -class ShutdownDetector : public base::PlatformThread::Delegate { - public: - explicit ShutdownDetector(int shutdown_fd); - - void ThreadMain() override; - - private: - const int shutdown_fd_; - - DISALLOW_COPY_AND_ASSIGN(ShutdownDetector); -}; - -ShutdownDetector::ShutdownDetector(int shutdown_fd) - : shutdown_fd_(shutdown_fd) { - CHECK_NE(shutdown_fd_, -1); -} - -// These functions are used to help us diagnose crash dumps that happen -// during the shutdown process. -NOINLINE void ShutdownFDReadError() { - // Ensure function isn't optimized away. - asm(""); - sleep(UINT_MAX); -} - -NOINLINE void ShutdownFDClosedError() { - // Ensure function isn't optimized away. - asm(""); - sleep(UINT_MAX); -} - -NOINLINE void ExitPosted() { - // Ensure function isn't optimized away. - asm(""); - sleep(UINT_MAX); -} - -void ShutdownDetector::ThreadMain() { - base::PlatformThread::SetName("CrShutdownDetector"); - - int signal; - size_t bytes_read = 0; - ssize_t ret; - do { - ret = HANDLE_EINTR( - read(shutdown_fd_, - reinterpret_cast(&signal) + bytes_read, - sizeof(signal) - bytes_read)); - if (ret < 0) { - NOTREACHED() << "Unexpected error: " << strerror(errno); - ShutdownFDReadError(); - break; - } else if (ret == 0) { - NOTREACHED() << "Unexpected closure of shutdown pipe."; - ShutdownFDClosedError(); - break; - } - bytes_read += ret; - } while (bytes_read < sizeof(signal)); - VLOG(1) << "Handling shutdown for signal " << signal << "."; - base::Closure task = - base::Bind(&Browser::Quit, base::Unretained(Browser::Get())); - - if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task)) { - // Without a UI thread to post the exit task to, there aren't many - // options. Raise the signal again. The default handler will pick it up - // and cause an ungraceful exit. - RAW_LOG(WARNING, "No UI thread, exiting ungracefully."); - kill(getpid(), signal); - - // The signal may be handled on another thread. Give that a chance to - // happen. - sleep(3); - - // We really should be dead by now. For whatever reason, we're not. Exit - // immediately, with the exit status set to the signal number with bit 8 - // set. On the systems that we care about, this exit status is what is - // normally used to indicate an exit by this signal's default handler. - // This mechanism isn't a de jure standard, but even in the worst case, it - // should at least result in an immediate exit. - RAW_LOG(WARNING, "Still here, exiting really ungracefully."); - _exit(signal | (1 << 7)); - } - ExitPosted(); -} - -} // namespace - -void AtomBrowserMainParts::HandleSIGCHLD() { - // We need to accept SIGCHLD, even though our handler is a no-op because - // otherwise we cannot wait on children. (According to POSIX 2001.) - struct sigaction action; - memset(&action, 0, sizeof(action)); - action.sa_handler = SIGCHLDHandler; - CHECK_EQ(sigaction(SIGCHLD, &action, nullptr), 0); -} - -void AtomBrowserMainParts::HandleShutdownSignals() { - int pipefd[2]; - int ret = pipe(pipefd); - if (ret < 0) { - PLOG(DFATAL) << "Failed to create pipe"; - } else { - g_pipe_pid = getpid(); - g_shutdown_pipe_read_fd = pipefd[0]; - g_shutdown_pipe_write_fd = pipefd[1]; -#if !defined(ADDRESS_SANITIZER) && !defined(KEEP_SHADOW_STACKS) - const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 2; -#else - // ASan instrumentation and -finstrument-functions (used for keeping the - // shadow stacks) bloat the stack frames, so we need to increase the stack - // size to avoid hitting the guard page. - const size_t kShutdownDetectorThreadStackSize = PTHREAD_STACK_MIN * 4; -#endif - // TODO(viettrungluu,willchan): crbug.com/29675 - This currently leaks, so - // if you change this, you'll probably need to change the suppression. - if (!base::PlatformThread::CreateNonJoinable( - kShutdownDetectorThreadStackSize, - new ShutdownDetector(g_shutdown_pipe_read_fd))) { - LOG(DFATAL) << "Failed to create shutdown detector task."; - } - } - // Setup signal handlers for shutdown AFTER shutdown pipe is setup because - // it may be called right away after handler is set. - - // If adding to this list of signal handlers, note the new signal probably - // needs to be reset in child processes. See - // base/process_util_posix.cc:LaunchProcess. - - // We need to handle SIGTERM, because that is how many POSIX-based distros ask - // processes to quit gracefully at shutdown time. - struct sigaction action; - memset(&action, 0, sizeof(action)); - action.sa_handler = SIGTERMHandler; - CHECK_EQ(sigaction(SIGTERM, &action, nullptr), 0); - // Also handle SIGINT - when the user terminates the browser via Ctrl+C. If - // the browser process is being debugged, GDB will catch the SIGINT first. - action.sa_handler = SIGINTHandler; - CHECK_EQ(sigaction(SIGINT, &action, nullptr), 0); - // And SIGHUP, for when the terminal disappears. On shutdown, many Linux - // distros send SIGHUP, SIGTERM, and then SIGKILL. - action.sa_handler = SIGHUPHandler; - CHECK_EQ(sigaction(SIGHUP, &action, nullptr), 0); -} - -} // namespace atom diff --git a/atom/browser/atom_download_manager_delegate.cc b/atom/browser/atom_download_manager_delegate.cc deleted file mode 100644 index 63ca5f661f98c..0000000000000 --- a/atom/browser/atom_download_manager_delegate.cc +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_download_manager_delegate.h" - -#include - -#include "atom/browser/api/atom_api_download_item.h" -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/native_window.h" -#include "atom/browser/ui/file_dialog.h" -#include "base/bind.h" -#include "base/files/file_util.h" -#include "components/prefs/pref_service.h" -#include "chrome/common/pref_names.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/download_manager.h" -#include "net/base/filename_util.h" - -namespace atom { - -AtomDownloadManagerDelegate::AtomDownloadManagerDelegate( - content::DownloadManager* manager) - : download_manager_(manager), - weak_ptr_factory_(this) {} - -AtomDownloadManagerDelegate::~AtomDownloadManagerDelegate() { - if (download_manager_) { - DCHECK_EQ(static_cast(this), - download_manager_->GetDelegate()); - download_manager_->SetDelegate(nullptr); - download_manager_ = nullptr; - } -} - -void AtomDownloadManagerDelegate::CreateDownloadPath( - const GURL& url, - const std::string& content_disposition, - const std::string& suggested_filename, - const std::string& mime_type, - const base::FilePath& default_download_path, - const CreateDownloadPathCallback& callback) { - DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); - - auto generated_name = net::GenerateFileName(url, - content_disposition, - std::string(), - suggested_filename, - mime_type, - std::string()); - - if (!base::PathExists(default_download_path)) - base::CreateDirectory(default_download_path); - - base::FilePath path(default_download_path.Append(generated_name)); - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(callback, path)); -} - -void AtomDownloadManagerDelegate::OnDownloadPathGenerated( - uint32_t download_id, - const content::DownloadTargetCallback& callback, - const base::FilePath& default_path) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - auto item = download_manager_->GetDownload(download_id); - if (!item) - return; - - NativeWindow* window = nullptr; - content::WebContents* web_contents = item->GetWebContents(); - auto relay = web_contents ? NativeWindowRelay::FromWebContents(web_contents) - : nullptr; - if (relay) - window = relay->window.get(); - - base::FilePath path; - if (file_dialog::ShowSaveDialog(window, item->GetURL().spec(), - "", default_path, - file_dialog::Filters(), &path)) { - // Remember the last selected download directory. - AtomBrowserContext* browser_context = static_cast( - download_manager_->GetBrowserContext()); - browser_context->prefs()->SetFilePath(prefs::kDownloadDefaultDirectory, - path.DirName()); - - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::Locker locker(isolate); - v8::HandleScope handle_scope(isolate); - api::DownloadItem* download_item = api::DownloadItem::FromWrappedClass( - isolate, item); - if (download_item) - download_item->SetSavePath(path); - } - - // Running the DownloadTargetCallback with an empty FilePath signals that the - // download should be cancelled. - // If user cancels the file save dialog, run the callback with empty FilePath. - callback.Run(path, - content::DownloadItem::TARGET_DISPOSITION_PROMPT, - content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path); -} - -void AtomDownloadManagerDelegate::Shutdown() { - weak_ptr_factory_.InvalidateWeakPtrs(); - download_manager_ = nullptr; -} - -bool AtomDownloadManagerDelegate::DetermineDownloadTarget( - content::DownloadItem* download, - const content::DownloadTargetCallback& callback) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - if (!download->GetForcedFilePath().empty()) { - callback.Run(download->GetForcedFilePath(), - content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, - content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, - download->GetForcedFilePath()); - return true; - } - - // Try to get the save path from JS wrapper. - { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::Locker locker(isolate); - v8::HandleScope handle_scope(isolate); - api::DownloadItem* download_item = api::DownloadItem::FromWrappedClass( - isolate, download); - if (download_item) { - base::FilePath save_path = download_item->GetSavePath(); - if (!save_path.empty()) { - callback.Run(save_path, - content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, - content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, - save_path); - return true; - } - } - } - - AtomBrowserContext* browser_context = static_cast( - download_manager_->GetBrowserContext()); - base::FilePath default_download_path = browser_context->prefs()->GetFilePath( - prefs::kDownloadDefaultDirectory); - - CreateDownloadPathCallback download_path_callback = - base::Bind(&AtomDownloadManagerDelegate::OnDownloadPathGenerated, - weak_ptr_factory_.GetWeakPtr(), - download->GetId(), callback); - - content::BrowserThread::PostTask( - content::BrowserThread::FILE, FROM_HERE, - base::Bind(&AtomDownloadManagerDelegate::CreateDownloadPath, - weak_ptr_factory_.GetWeakPtr(), - download->GetURL(), - download->GetContentDisposition(), - download->GetSuggestedFilename(), - download->GetMimeType(), - default_download_path, - download_path_callback)); - return true; -} - -bool AtomDownloadManagerDelegate::ShouldOpenDownload( - content::DownloadItem* download, - const content::DownloadOpenDelayedCallback& callback) { - return true; -} - -void AtomDownloadManagerDelegate::GetNextId( - const content::DownloadIdCallback& callback) { - static uint32_t next_id = content::DownloadItem::kInvalidId + 1; - callback.Run(next_id++); -} - -} // namespace atom diff --git a/atom/browser/atom_download_manager_delegate.h b/atom/browser/atom_download_manager_delegate.h deleted file mode 100644 index 5ea3d50d5aee3..0000000000000 --- a/atom/browser/atom_download_manager_delegate.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_DOWNLOAD_MANAGER_DELEGATE_H_ -#define ATOM_BROWSER_ATOM_DOWNLOAD_MANAGER_DELEGATE_H_ - -#include - -#include "base/memory/weak_ptr.h" -#include "content/public/browser/download_manager_delegate.h" - -namespace content { -class DownloadManager; -} - -namespace atom { - -class AtomDownloadManagerDelegate : public content::DownloadManagerDelegate { - public: - using CreateDownloadPathCallback = - base::Callback; - - explicit AtomDownloadManagerDelegate(content::DownloadManager* manager); - virtual ~AtomDownloadManagerDelegate(); - - // Generate default file path to save the download. - void CreateDownloadPath(const GURL& url, - const std::string& suggested_filename, - const std::string& content_disposition, - const std::string& mime_type, - const base::FilePath& path, - const CreateDownloadPathCallback& callback); - void OnDownloadPathGenerated(uint32_t download_id, - const content::DownloadTargetCallback& callback, - const base::FilePath& default_path); - - // content::DownloadManagerDelegate: - void Shutdown() override; - bool DetermineDownloadTarget( - content::DownloadItem* download, - const content::DownloadTargetCallback& callback) override; - bool ShouldOpenDownload( - content::DownloadItem* download, - const content::DownloadOpenDelayedCallback& callback) override; - void GetNextId(const content::DownloadIdCallback& callback) override; - - private: - content::DownloadManager* download_manager_; - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(AtomDownloadManagerDelegate); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_DOWNLOAD_MANAGER_DELEGATE_H_ diff --git a/atom/browser/atom_javascript_dialog_manager.cc b/atom/browser/atom_javascript_dialog_manager.cc deleted file mode 100644 index eaf311ba1cdba..0000000000000 --- a/atom/browser/atom_javascript_dialog_manager.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_javascript_dialog_manager.h" - -#include - -#include "base/strings/utf_string_conversions.h" - -namespace atom { - -void AtomJavaScriptDialogManager::RunJavaScriptDialog( - content::WebContents* web_contents, - const GURL& origin_url, - content::JavaScriptMessageType javascript_message_type, - const base::string16& message_text, - const base::string16& default_prompt_text, - const DialogClosedCallback& callback, - bool* did_suppress_message) { - callback.Run(false, base::string16()); -} - -void AtomJavaScriptDialogManager::RunBeforeUnloadDialog( - content::WebContents* web_contents, - bool is_reload, - const DialogClosedCallback& callback) { - // FIXME(zcbenz): the |message_text| is removed, figure out what should we do. - callback.Run(false, base::ASCIIToUTF16("This should not be displayed")); -} - -} // namespace atom diff --git a/atom/browser/atom_javascript_dialog_manager.h b/atom/browser/atom_javascript_dialog_manager.h deleted file mode 100644 index 3844e41f9d2fd..0000000000000 --- a/atom/browser/atom_javascript_dialog_manager.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_JAVASCRIPT_DIALOG_MANAGER_H_ -#define ATOM_BROWSER_ATOM_JAVASCRIPT_DIALOG_MANAGER_H_ - -#include - -#include "content/public/browser/javascript_dialog_manager.h" - -namespace atom { - -class AtomJavaScriptDialogManager : public content::JavaScriptDialogManager { - public: - // content::JavaScriptDialogManager implementations. - void RunJavaScriptDialog( - content::WebContents* web_contents, - const GURL& origin_url, - content::JavaScriptMessageType javascript_message_type, - const base::string16& message_text, - const base::string16& default_prompt_text, - const DialogClosedCallback& callback, - bool* did_suppress_message) override; - void RunBeforeUnloadDialog( - content::WebContents* web_contents, - bool is_reload, - const DialogClosedCallback& callback) override; - void CancelActiveAndPendingDialogs( - content::WebContents* web_contents) override {} - void ResetDialogState(content::WebContents* web_contents) override {}; -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_JAVASCRIPT_DIALOG_MANAGER_H_ diff --git a/atom/browser/atom_permission_manager.cc b/atom/browser/atom_permission_manager.cc deleted file mode 100644 index 7fc5fa0d03784..0000000000000 --- a/atom/browser/atom_permission_manager.cc +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_permission_manager.h" - -#include - -#include "atom/browser/web_contents_preferences.h" -#include "content/public/browser/child_process_security_policy.h" -#include "content/public/browser/permission_type.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" - -namespace atom { - -namespace { - -bool WebContentsDestroyed(int process_id) { - auto contents = - WebContentsPreferences::GetWebContentsFromProcessID(process_id); - if (!contents) - return true; - return contents->IsBeingDestroyed(); -} - -} // namespace - -AtomPermissionManager::AtomPermissionManager() - : request_id_(0) { -} - -AtomPermissionManager::~AtomPermissionManager() { -} - -void AtomPermissionManager::SetPermissionRequestHandler( - const RequestHandler& handler) { - if (handler.is_null() && !pending_requests_.empty()) { - for (const auto& request : pending_requests_) { - if (!WebContentsDestroyed(request.second.render_process_id)) - request.second.callback.Run(blink::mojom::PermissionStatus::DENIED); - } - pending_requests_.clear(); - } - request_handler_ = handler; -} - -int AtomPermissionManager::RequestPermission( - content::PermissionType permission, - content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin, - const ResponseCallback& response_callback) { - int process_id = render_frame_host->GetProcess()->GetID(); - - if (permission == content::PermissionType::MIDI_SYSEX) { - content::ChildProcessSecurityPolicy::GetInstance()-> - GrantSendMidiSysExMessage(process_id); - } - - if (!request_handler_.is_null()) { - auto web_contents = - content::WebContents::FromRenderFrameHost(render_frame_host); - ++request_id_; - auto callback = base::Bind(&AtomPermissionManager::OnPermissionResponse, - base::Unretained(this), - request_id_, - requesting_origin, - response_callback); - pending_requests_[request_id_] = { process_id, callback }; - request_handler_.Run(web_contents, permission, callback); - return request_id_; - } - - response_callback.Run(blink::mojom::PermissionStatus::GRANTED); - return kNoPendingOperation; -} - -int AtomPermissionManager::RequestPermissions( - const std::vector& permissions, - content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin, - const base::Callback&)>& callback) { - // FIXME(zcbenz): Just ignore multiple permissions request for now. - std::vector permissionStatuses; - for (auto permission : permissions) { - if (permission == content::PermissionType::MIDI_SYSEX) { - content::ChildProcessSecurityPolicy::GetInstance()-> - GrantSendMidiSysExMessage(render_frame_host->GetProcess()->GetID()); - } - permissionStatuses.push_back(blink::mojom::PermissionStatus::GRANTED); - } - callback.Run(permissionStatuses); - return kNoPendingOperation; -} - -void AtomPermissionManager::OnPermissionResponse( - int request_id, - const GURL& origin, - const ResponseCallback& callback, - blink::mojom::PermissionStatus status) { - auto request = pending_requests_.find(request_id); - if (request != pending_requests_.end()) { - if (!WebContentsDestroyed(request->second.render_process_id)) - callback.Run(status); - pending_requests_.erase(request); - } -} - -void AtomPermissionManager::CancelPermissionRequest(int request_id) { - auto request = pending_requests_.find(request_id); - if (request != pending_requests_.end()) { - if (!WebContentsDestroyed(request->second.render_process_id)) - request->second.callback.Run(blink::mojom::PermissionStatus::DENIED); - pending_requests_.erase(request); - } -} - -void AtomPermissionManager::ResetPermission( - content::PermissionType permission, - const GURL& requesting_origin, - const GURL& embedding_origin) { -} - -blink::mojom::PermissionStatus AtomPermissionManager::GetPermissionStatus( - content::PermissionType permission, - const GURL& requesting_origin, - const GURL& embedding_origin) { - return blink::mojom::PermissionStatus::GRANTED; -} - -void AtomPermissionManager::RegisterPermissionUsage( - content::PermissionType permission, - const GURL& requesting_origin, - const GURL& embedding_origin) { -} - -int AtomPermissionManager::SubscribePermissionStatusChange( - content::PermissionType permission, - const GURL& requesting_origin, - const GURL& embedding_origin, - const ResponseCallback& callback) { - return -1; -} - -void AtomPermissionManager::UnsubscribePermissionStatusChange( - int subscription_id) { -} - -} // namespace atom diff --git a/atom/browser/atom_permission_manager.h b/atom/browser/atom_permission_manager.h deleted file mode 100644 index d0fcdc60768f1..0000000000000 --- a/atom/browser/atom_permission_manager.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_PERMISSION_MANAGER_H_ -#define ATOM_BROWSER_ATOM_PERMISSION_MANAGER_H_ - -#include -#include - -#include "base/callback.h" -#include "content/public/browser/permission_manager.h" - -namespace content { -class WebContents; -} - -namespace atom { - -class AtomPermissionManager : public content::PermissionManager { - public: - AtomPermissionManager(); - ~AtomPermissionManager() override; - - using ResponseCallback = - base::Callback; - using RequestHandler = - base::Callback; - - // Handler to dispatch permission requests in JS. - void SetPermissionRequestHandler(const RequestHandler& handler); - - // content::PermissionManager: - int RequestPermission( - content::PermissionType permission, - content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin, - const ResponseCallback& callback) override; - int RequestPermissions( - const std::vector& permissions, - content::RenderFrameHost* render_frame_host, - const GURL& requesting_origin, - const base::Callback&)>& callback) override; - - protected: - void OnPermissionResponse(int request_id, - const GURL& url, - const ResponseCallback& callback, - blink::mojom::PermissionStatus status); - - // content::PermissionManager: - void CancelPermissionRequest(int request_id) override; - void ResetPermission(content::PermissionType permission, - const GURL& requesting_origin, - const GURL& embedding_origin) override; - blink::mojom::PermissionStatus GetPermissionStatus( - content::PermissionType permission, - const GURL& requesting_origin, - const GURL& embedding_origin) override; - void RegisterPermissionUsage(content::PermissionType permission, - const GURL& requesting_origin, - const GURL& embedding_origin) override; - int SubscribePermissionStatusChange( - content::PermissionType permission, - const GURL& requesting_origin, - const GURL& embedding_origin, - const base::Callback& callback) - override; - void UnsubscribePermissionStatusChange(int subscription_id) override; - - private: - struct RequestInfo { - int render_process_id; - ResponseCallback callback; - }; - - RequestHandler request_handler_; - - std::map pending_requests_; - - int request_id_; - - DISALLOW_COPY_AND_ASSIGN(AtomPermissionManager); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_PERMISSION_MANAGER_H_ diff --git a/atom/browser/atom_quota_permission_context.cc b/atom/browser/atom_quota_permission_context.cc deleted file mode 100644 index 8775f950ca9a0..0000000000000 --- a/atom/browser/atom_quota_permission_context.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_quota_permission_context.h" - -#include "storage/common/quota/quota_types.h" - -namespace atom { - -AtomQuotaPermissionContext::AtomQuotaPermissionContext() { -} - -AtomQuotaPermissionContext::~AtomQuotaPermissionContext() { -} - -void AtomQuotaPermissionContext::RequestQuotaPermission( - const content::StorageQuotaParams& params, - int render_process_id, - const PermissionCallback& callback) { - callback.Run(response::QUOTA_PERMISSION_RESPONSE_ALLOW); -} - -} // namespace atom diff --git a/atom/browser/atom_quota_permission_context.h b/atom/browser/atom_quota_permission_context.h deleted file mode 100644 index 1246ea7bad589..0000000000000 --- a/atom/browser/atom_quota_permission_context.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_QUOTA_PERMISSION_CONTEXT_H_ -#define ATOM_BROWSER_ATOM_QUOTA_PERMISSION_CONTEXT_H_ - -#include "content/public/browser/quota_permission_context.h" - -namespace atom { - -class AtomQuotaPermissionContext : public content::QuotaPermissionContext { - public: - typedef content::QuotaPermissionContext::QuotaPermissionResponse response; - - AtomQuotaPermissionContext(); - virtual ~AtomQuotaPermissionContext(); - - // content::QuotaPermissionContext: - void RequestQuotaPermission( - const content::StorageQuotaParams& params, - int render_process_id, - const PermissionCallback& callback) override; - - private: - DISALLOW_COPY_AND_ASSIGN(AtomQuotaPermissionContext); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_QUOTA_PERMISSION_CONTEXT_H_ diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.cc b/atom/browser/atom_resource_dispatcher_host_delegate.cc deleted file mode 100644 index c64a21d26dd84..0000000000000 --- a/atom/browser/atom_resource_dispatcher_host_delegate.cc +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_resource_dispatcher_host_delegate.h" - -#include "atom/browser/login_handler.h" -#include "atom/browser/web_contents_permission_helper.h" -#include "atom/common/platform_util.h" -#include "base/strings/utf_string_conversions.h" -#include "content/public/browser/browser_thread.h" -#include "net/base/escape.h" -#include "url/gurl.h" - -using content::BrowserThread; - -namespace atom { - -namespace { - -void OnOpenExternal(const GURL& escaped_url, - bool allowed) { - if (allowed) - platform_util::OpenExternal( -#if defined(OS_WIN) - base::UTF8ToUTF16(escaped_url.spec()), -#else - escaped_url, -#endif - true); -} - -void HandleExternalProtocolInUI( - const GURL& url, - const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, - bool has_user_gesture) { - content::WebContents* web_contents = web_contents_getter.Run(); - if (!web_contents) - return; - - auto permission_helper = - WebContentsPermissionHelper::FromWebContents(web_contents); - if (!permission_helper) - return; - - GURL escaped_url(net::EscapeExternalHandlerValue(url.spec())); - auto callback = base::Bind(&OnOpenExternal, escaped_url); - permission_helper->RequestOpenExternalPermission(callback, has_user_gesture); -} - -} // namespace - -AtomResourceDispatcherHostDelegate::AtomResourceDispatcherHostDelegate() { -} - -bool AtomResourceDispatcherHostDelegate::HandleExternalProtocol( - const GURL& url, - int child_id, - const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, - bool is_main_frame, - ui::PageTransition transition, - bool has_user_gesture) { - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&HandleExternalProtocolInUI, - url, - web_contents_getter, - has_user_gesture)); - return true; -} - -content::ResourceDispatcherHostLoginDelegate* -AtomResourceDispatcherHostDelegate::CreateLoginDelegate( - net::AuthChallengeInfo* auth_info, - net::URLRequest* request) { - return new LoginHandler(auth_info, request); -} - -} // namespace atom diff --git a/atom/browser/atom_resource_dispatcher_host_delegate.h b/atom/browser/atom_resource_dispatcher_host_delegate.h deleted file mode 100644 index 408b83c92d905..0000000000000 --- a/atom/browser/atom_resource_dispatcher_host_delegate.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_ -#define ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_ - -#include "content/public/browser/resource_dispatcher_host_delegate.h" - -namespace atom { - -class AtomResourceDispatcherHostDelegate - : public content::ResourceDispatcherHostDelegate { - public: - AtomResourceDispatcherHostDelegate(); - - // content::ResourceDispatcherHostDelegate: - bool HandleExternalProtocol( - const GURL& url, - int child_id, - const content::ResourceRequestInfo::WebContentsGetter&, - bool is_main_frame, - ui::PageTransition transition, - bool has_user_gesture) override; - content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( - net::AuthChallengeInfo* auth_info, - net::URLRequest* request) override; -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_RESOURCE_DISPATCHER_HOST_DELEGATE_H_ diff --git a/atom/browser/atom_security_state_model_client.cc b/atom/browser/atom_security_state_model_client.cc deleted file mode 100644 index 77a91bdec9b37..0000000000000 --- a/atom/browser/atom_security_state_model_client.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_security_state_model_client.h" - -#include "content/public/browser/cert_store.h" -#include "content/public/browser/navigation_entry.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/origin_util.h" -#include "content/public/common/ssl_status.h" -#include "net/cert/x509_certificate.h" - -DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::AtomSecurityStateModelClient); - -using security_state::SecurityStateModel; - -namespace atom { - -namespace { - -SecurityStateModel::SecurityLevel GetSecurityLevelForSecurityStyle( - content::SecurityStyle style) { - switch (style) { - case content::SECURITY_STYLE_UNKNOWN: - return SecurityStateModel::NONE; - case content::SECURITY_STYLE_UNAUTHENTICATED: - return SecurityStateModel::NONE; - case content::SECURITY_STYLE_AUTHENTICATION_BROKEN: - return SecurityStateModel::SECURITY_ERROR; - case content::SECURITY_STYLE_WARNING: - return SecurityStateModel::SECURITY_WARNING; - case content::SECURITY_STYLE_AUTHENTICATED: - return SecurityStateModel::SECURE; - } - return SecurityStateModel::NONE; -} - -} // namespace - -AtomSecurityStateModelClient::AtomSecurityStateModelClient( - content::WebContents* web_contents) - : web_contents_(web_contents), - security_state_model_(new SecurityStateModel()) { - security_state_model_->SetClient(this); -} - -AtomSecurityStateModelClient::~AtomSecurityStateModelClient() { -} - -const SecurityStateModel::SecurityInfo& -AtomSecurityStateModelClient::GetSecurityInfo() const { - return security_state_model_->GetSecurityInfo(); -} - -bool AtomSecurityStateModelClient::RetrieveCert( - scoped_refptr* cert) { - content::NavigationEntry* entry = - web_contents_->GetController().GetVisibleEntry(); - if (!entry) - return false; - return content::CertStore::GetInstance()->RetrieveCert( - entry->GetSSL().cert_id, cert); -} - -bool AtomSecurityStateModelClient::UsedPolicyInstalledCertificate() { - return false; -} - -bool AtomSecurityStateModelClient::IsOriginSecure(const GURL& url) { - return content::IsOriginSecure(url); -} - -void AtomSecurityStateModelClient::GetVisibleSecurityState( - SecurityStateModel::VisibleSecurityState* state) { - content::NavigationEntry* entry = - web_contents_->GetController().GetVisibleEntry(); - if (!entry || - entry->GetSSL().security_style == content::SECURITY_STYLE_UNKNOWN) { - *state = SecurityStateModel::VisibleSecurityState(); - return; - } - - state->initialized = true; - state->url = entry->GetURL(); - const content::SSLStatus& ssl = entry->GetSSL(); - state->initial_security_level = - GetSecurityLevelForSecurityStyle(ssl.security_style); - state->cert_id = ssl.cert_id; - state->cert_status = ssl.cert_status; - state->connection_status = ssl.connection_status; - state->security_bits = ssl.security_bits; - state->sct_verify_statuses.clear(); - state->sct_verify_statuses.insert(state->sct_verify_statuses.end(), - ssl.num_unknown_scts, - net::ct::SCT_STATUS_LOG_UNKNOWN); - state->sct_verify_statuses.insert(state->sct_verify_statuses.end(), - ssl.num_invalid_scts, - net::ct::SCT_STATUS_INVALID); - state->sct_verify_statuses.insert(state->sct_verify_statuses.end(), - ssl.num_valid_scts, net::ct::SCT_STATUS_OK); - state->displayed_mixed_content = - (ssl.content_status & content::SSLStatus::DISPLAYED_INSECURE_CONTENT) - ? true - : false; - state->ran_mixed_content = - (ssl.content_status & content::SSLStatus::RAN_INSECURE_CONTENT) ? true - : false; -} - -} // namespace atom diff --git a/atom/browser/atom_security_state_model_client.h b/atom/browser/atom_security_state_model_client.h deleted file mode 100644 index 0dd3aa66c1250..0000000000000 --- a/atom/browser/atom_security_state_model_client.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_ -#define ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_ - -#include "components/security_state/security_state_model.h" -#include "components/security_state/security_state_model_client.h" -#include "content/public/browser/web_contents_user_data.h" - -namespace atom { - -class AtomSecurityStateModelClient - : public security_state::SecurityStateModelClient, - public content::WebContentsUserData { - public: - ~AtomSecurityStateModelClient() override; - - const security_state::SecurityStateModel::SecurityInfo& - GetSecurityInfo() const; - - // security_state::SecurityStateModelClient: - void GetVisibleSecurityState( - security_state::SecurityStateModel::VisibleSecurityState* state) override; - bool RetrieveCert(scoped_refptr* cert) override; - bool UsedPolicyInstalledCertificate() override; - bool IsOriginSecure(const GURL& url) override; - - private: - explicit AtomSecurityStateModelClient(content::WebContents* web_contents); - friend class content::WebContentsUserData; - - content::WebContents* web_contents_; - std::unique_ptr security_state_model_; - - DISALLOW_COPY_AND_ASSIGN(AtomSecurityStateModelClient); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_ diff --git a/atom/browser/atom_speech_recognition_manager_delegate.cc b/atom/browser/atom_speech_recognition_manager_delegate.cc deleted file mode 100644 index d2e7135c9af22..0000000000000 --- a/atom/browser/atom_speech_recognition_manager_delegate.cc +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/atom_speech_recognition_manager_delegate.h" - -#include - -#include "base/callback.h" - -namespace atom { - -AtomSpeechRecognitionManagerDelegate::AtomSpeechRecognitionManagerDelegate() { -} - -AtomSpeechRecognitionManagerDelegate::~AtomSpeechRecognitionManagerDelegate() { -} - -void AtomSpeechRecognitionManagerDelegate::OnRecognitionStart(int session_id) { -} - -void AtomSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) { -} - -void AtomSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete( - int session_id) { -} - -void AtomSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) { -} - -void AtomSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) { -} - -void AtomSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) { -} - -void AtomSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) { -} - -void AtomSpeechRecognitionManagerDelegate::OnRecognitionResults( - int session_id, const content::SpeechRecognitionResults& result) { -} - -void AtomSpeechRecognitionManagerDelegate::OnRecognitionError( - int session_id, const content::SpeechRecognitionError& error) { -} - -void AtomSpeechRecognitionManagerDelegate::OnAudioLevelsChange( - int session_id, float volume, float noise_volume) { -} - -void AtomSpeechRecognitionManagerDelegate::CheckRecognitionIsAllowed( - int session_id, - base::Callback callback) { - callback.Run(true, true); -} - -content::SpeechRecognitionEventListener* -AtomSpeechRecognitionManagerDelegate::GetEventListener() { - return this; -} - -bool AtomSpeechRecognitionManagerDelegate::FilterProfanities( - int render_process_id) { - return false; -} - -} // namespace atom diff --git a/atom/browser/atom_speech_recognition_manager_delegate.h b/atom/browser/atom_speech_recognition_manager_delegate.h deleted file mode 100644 index a6b2f059f7a0b..0000000000000 --- a/atom/browser/atom_speech_recognition_manager_delegate.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_ATOM_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_ -#define ATOM_BROWSER_ATOM_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_ - -#include - -#include "base/macros.h" -#include "content/public/browser/speech_recognition_event_listener.h" -#include "content/public/browser/speech_recognition_manager_delegate.h" - -namespace atom { - -class AtomSpeechRecognitionManagerDelegate - : public content::SpeechRecognitionManagerDelegate, - public content::SpeechRecognitionEventListener { - public: - AtomSpeechRecognitionManagerDelegate(); - virtual ~AtomSpeechRecognitionManagerDelegate(); - - // content::SpeechRecognitionEventListener: - void OnRecognitionStart(int session_id) override; - void OnAudioStart(int session_id) override; - void OnEnvironmentEstimationComplete(int session_id) override; - void OnSoundStart(int session_id) override; - void OnSoundEnd(int session_id) override; - void OnAudioEnd(int session_id) override; - void OnRecognitionEnd(int session_id) override; - void OnRecognitionResults( - int session_id, const content::SpeechRecognitionResults& result) override; - void OnRecognitionError( - int session_id, const content::SpeechRecognitionError& error) override; - void OnAudioLevelsChange(int session_id, float volume, - float noise_volume) override; - - // content::SpeechRecognitionManagerDelegate: - void CheckRecognitionIsAllowed( - int session_id, - base::Callback callback) override; - content::SpeechRecognitionEventListener* GetEventListener() override; - bool FilterProfanities(int render_process_id) override; - - private: - DISALLOW_COPY_AND_ASSIGN(AtomSpeechRecognitionManagerDelegate); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_ATOM_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_ diff --git a/atom/browser/auto_updater.cc b/atom/browser/auto_updater.cc deleted file mode 100644 index 8ada3ff6ab3dc..0000000000000 --- a/atom/browser/auto_updater.cc +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/auto_updater.h" - -namespace auto_updater { - -Delegate* AutoUpdater::delegate_ = nullptr; - -Delegate* AutoUpdater::GetDelegate() { - return delegate_; -} - -void AutoUpdater::SetDelegate(Delegate* delegate) { - delegate_ = delegate; -} - -#if !defined(OS_MACOSX) || defined(MAS_BUILD) -std::string AutoUpdater::GetFeedURL() { - return ""; -} - -void AutoUpdater::SetFeedURL(const std::string& url, - const HeaderMap& requestHeaders) { -} - -void AutoUpdater::CheckForUpdates() { -} - -void AutoUpdater::QuitAndInstall() { -} -#endif - -} // namespace auto_updater diff --git a/atom/browser/auto_updater.h b/atom/browser/auto_updater.h deleted file mode 100644 index aa4ca19cf21f5..0000000000000 --- a/atom/browser/auto_updater.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_AUTO_UPDATER_H_ -#define ATOM_BROWSER_AUTO_UPDATER_H_ - -#include -#include - -#include "base/macros.h" -#include "build/build_config.h" - -namespace base { -class Time; -} - -namespace auto_updater { - -class Delegate { - public: - // An error happened. - virtual void OnError(const std::string& error) {} - - // Checking to see if there is an update - virtual void OnCheckingForUpdate() {} - - // There is an update available and it is being downloaded - virtual void OnUpdateAvailable() {} - - // There is no available update. - virtual void OnUpdateNotAvailable() {} - - // There is a new update which has been downloaded. - virtual void OnUpdateDownloaded(const std::string& release_notes, - const std::string& release_name, - const base::Time& release_date, - const std::string& update_url) {} - - protected: - virtual ~Delegate() {} -}; - -class AutoUpdater { - public: - typedef std::map HeaderMap; - - // Gets/Sets the delegate. - static Delegate* GetDelegate(); - static void SetDelegate(Delegate* delegate); - - static std::string GetFeedURL(); - static void SetFeedURL(const std::string& url, - const HeaderMap& requestHeaders); - static void CheckForUpdates(); - static void QuitAndInstall(); - - private: - static Delegate* delegate_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(AutoUpdater); -}; - -} // namespace auto_updater - -#endif // ATOM_BROWSER_AUTO_UPDATER_H_ diff --git a/atom/browser/auto_updater_mac.mm b/atom/browser/auto_updater_mac.mm deleted file mode 100644 index 1987f33621d8a..0000000000000 --- a/atom/browser/auto_updater_mac.mm +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/auto_updater.h" - -#import -#import -#import -#import - -#include "base/bind.h" -#include "base/time/time.h" -#include "base/strings/sys_string_conversions.h" - -namespace auto_updater { - -namespace { - -// The gloal SQRLUpdater object. -SQRLUpdater* g_updater = nil; - -} // namespace - -namespace { - -bool g_update_available = false; -std::string update_url_ = ""; - -} - -std::string AutoUpdater::GetFeedURL() { - return update_url_; -} - -// static -void AutoUpdater::SetFeedURL(const std::string& feed, - const HeaderMap& requestHeaders) { - Delegate* delegate = GetDelegate(); - if (!delegate) - return; - - update_url_ = feed; - - NSURL* url = [NSURL URLWithString:base::SysUTF8ToNSString(feed)]; - NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url]; - - for (const auto& it : requestHeaders) { - [urlRequest setValue:base::SysUTF8ToNSString(it.second) - forHTTPHeaderField:base::SysUTF8ToNSString(it.first)]; - } - - if (g_updater) - [g_updater release]; - - // Initialize the SQRLUpdater. - @try { - g_updater = [[SQRLUpdater alloc] initWithUpdateRequest:urlRequest]; - } @catch (NSException* error) { - delegate->OnError(base::SysNSStringToUTF8(error.reason)); - return; - } - - [[g_updater rac_valuesForKeyPath:@"state" observer:g_updater] - subscribeNext:^(NSNumber *stateNumber) { - int state = [stateNumber integerValue]; - // Dispatching the event on main thread. - dispatch_async(dispatch_get_main_queue(), ^{ - if (state == SQRLUpdaterStateCheckingForUpdate) - delegate->OnCheckingForUpdate(); - else if (state == SQRLUpdaterStateDownloadingUpdate) - delegate->OnUpdateAvailable(); - }); - }]; -} - -// static -void AutoUpdater::CheckForUpdates() { - Delegate* delegate = GetDelegate(); - if (!delegate) - return; - - [[[[g_updater.checkForUpdatesCommand - execute:nil] - // Send a `nil` after everything... - concat:[RACSignal return:nil]] - // But only take the first value. If an update is sent, we'll get that. - // Otherwise, we'll get our inserted `nil` value. - take:1] - subscribeNext:^(SQRLDownloadedUpdate *downloadedUpdate) { - if (downloadedUpdate) { - g_update_available = true; - SQRLUpdate* update = downloadedUpdate.update; - // There is a new update that has been downloaded. - delegate->OnUpdateDownloaded( - base::SysNSStringToUTF8(update.releaseNotes), - base::SysNSStringToUTF8(update.releaseName), - base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970), - base::SysNSStringToUTF8(update.updateURL.absoluteString)); - } else { - g_update_available = false; - // When the completed event is sent with no update, then we know there - // is no update available. - delegate->OnUpdateNotAvailable(); - } - } error:^(NSError *error) { - NSString* failureString = error.localizedFailureReason ? - [NSString stringWithFormat:@"%@: %@", - error.localizedDescription, - error.localizedFailureReason] : - [NSString stringWithString:error.localizedDescription]; - delegate->OnError(base::SysNSStringToUTF8(failureString)); - }]; -} - -void AutoUpdater::QuitAndInstall() { - Delegate* delegate = AutoUpdater::GetDelegate(); - if (g_update_available) { - [[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) { - if (delegate) - delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription)); - }]; - } else { - if (delegate) - delegate->OnError("No update available, can't quit and install"); - } -} - -} // namespace auto_updater diff --git a/atom/browser/bridge_task_runner.cc b/atom/browser/bridge_task_runner.cc deleted file mode 100644 index 36c8d17359e8e..0000000000000 --- a/atom/browser/bridge_task_runner.cc +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/bridge_task_runner.h" - -#include "base/message_loop/message_loop.h" - -namespace atom { - -void BridgeTaskRunner::MessageLoopIsReady() { - auto message_loop = base::MessageLoop::current(); - CHECK(message_loop); - for (const TaskPair& task : tasks_) { - message_loop->task_runner()->PostDelayedTask( - base::get<0>(task), base::get<1>(task), base::get<2>(task)); - } - for (const TaskPair& task : non_nestable_tasks_) { - message_loop->task_runner()->PostNonNestableDelayedTask( - base::get<0>(task), base::get<1>(task), base::get<2>(task)); - } -} - -bool BridgeTaskRunner::PostDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - auto message_loop = base::MessageLoop::current(); - if (!message_loop) { - tasks_.push_back(base::MakeTuple(from_here, task, delay)); - return true; - } - - return message_loop->task_runner()->PostDelayedTask(from_here, task, delay); -} - -bool BridgeTaskRunner::RunsTasksOnCurrentThread() const { - auto message_loop = base::MessageLoop::current(); - if (!message_loop) - return true; - - return message_loop->task_runner()->RunsTasksOnCurrentThread(); -} - -bool BridgeTaskRunner::PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) { - auto message_loop = base::MessageLoop::current(); - if (!message_loop) { - non_nestable_tasks_.push_back(base::MakeTuple(from_here, task, delay)); - return true; - } - - return message_loop->task_runner()->PostNonNestableDelayedTask( - from_here, task, delay); -} - -} // namespace atom diff --git a/atom/browser/bridge_task_runner.h b/atom/browser/bridge_task_runner.h deleted file mode 100644 index b69b33b29516a..0000000000000 --- a/atom/browser/bridge_task_runner.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_ -#define ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_ - -#include - -#include "base/single_thread_task_runner.h" -#include "base/tuple.h" - -namespace atom { - -// Post all tasks to the current message loop's task runner if available, -// otherwise delay the work until message loop is ready. -class BridgeTaskRunner : public base::SingleThreadTaskRunner { - public: - BridgeTaskRunner() {} - ~BridgeTaskRunner() override {} - - // Called when message loop is ready. - void MessageLoopIsReady(); - - // base::SingleThreadTaskRunner: - bool PostDelayedTask(const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - bool RunsTasksOnCurrentThread() const override; - bool PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const base::Closure& task, - base::TimeDelta delay) override; - - private: - using TaskPair = base::Tuple< - tracked_objects::Location, base::Closure, base::TimeDelta>; - std::vector tasks_; - std::vector non_nestable_tasks_; - - DISALLOW_COPY_AND_ASSIGN(BridgeTaskRunner); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_BRIDGE_TASK_RUNNER_H_ diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc deleted file mode 100644 index dd958d0dc7d22..0000000000000 --- a/atom/browser/browser.cc +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/browser.h" - -#include - -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/browser/native_window.h" -#include "atom/browser/window_list.h" -#include "base/files/file_util.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "brightray/browser/brightray_paths.h" - -namespace atom { - -Browser::Browser() - : is_quiting_(false), - is_exiting_(false), - is_ready_(false), - is_shutdown_(false) { - WindowList::AddObserver(this); -} - -Browser::~Browser() { - WindowList::RemoveObserver(this); -} - -// static -Browser* Browser::Get() { - return AtomBrowserMainParts::Get()->browser(); -} - -void Browser::Quit() { - if (is_quiting_) - return; - - is_quiting_ = HandleBeforeQuit(); - if (!is_quiting_) - return; - - atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->size() == 0) - NotifyAndShutdown(); - - window_list->CloseAllWindows(); -} - -void Browser::Exit(int code) { - if (!AtomBrowserMainParts::Get()->SetExitCode(code)) { - // Message loop is not ready, quit directly. - exit(code); - } else { - // Prepare to quit when all windows have been closed. - is_quiting_ = true; - - // Remember this caller so that we don't emit unrelated events. - is_exiting_ = true; - - // Must destroy windows before quitting, otherwise bad things can happen. - atom::WindowList* window_list = atom::WindowList::GetInstance(); - if (window_list->size() == 0) { - Shutdown(); - } else { - // Unlike Quit(), we do not ask to close window, but destroy the window - // without asking. - for (NativeWindow* window : *window_list) - window->CloseContents(nullptr); // e.g. Destroy() - } - } -} - -void Browser::Shutdown() { - if (is_shutdown_) - return; - - is_shutdown_ = true; - is_quiting_ = true; - - FOR_EACH_OBSERVER(BrowserObserver, observers_, OnQuit()); - - if (base::MessageLoop::current()) { - base::MessageLoop::current()->PostTask( - FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); - } else { - // There is no message loop available so we are in early stage. - exit(0); - } -} - -std::string Browser::GetVersion() const { - if (version_override_.empty()) { - std::string version = GetExecutableFileVersion(); - if (!version.empty()) - return version; - } - - return version_override_; -} - -void Browser::SetVersion(const std::string& version) { - version_override_ = version; -} - -std::string Browser::GetName() const { - if (name_override_.empty()) { - std::string name = GetExecutableFileProductName(); - if (!name.empty()) - return name; - } - - return name_override_; -} - -void Browser::SetName(const std::string& name) { - name_override_ = name; -} - -int Browser::GetBadgeCount() { - return badge_count_; -} - -bool Browser::OpenFile(const std::string& file_path) { - bool prevent_default = false; - FOR_EACH_OBSERVER(BrowserObserver, - observers_, - OnOpenFile(&prevent_default, file_path)); - - return prevent_default; -} - -void Browser::OpenURL(const std::string& url) { - FOR_EACH_OBSERVER(BrowserObserver, observers_, OnOpenURL(url)); -} - -void Browser::Activate(bool has_visible_windows) { - FOR_EACH_OBSERVER(BrowserObserver, - observers_, - OnActivate(has_visible_windows)); -} - -void Browser::WillFinishLaunching() { - FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillFinishLaunching()); -} - -void Browser::DidFinishLaunching() { - // Make sure the userData directory is created. - base::FilePath user_data; - if (PathService::Get(brightray::DIR_USER_DATA, &user_data)) - base::CreateDirectoryAndGetError(user_data, nullptr); - - is_ready_ = true; - FOR_EACH_OBSERVER(BrowserObserver, observers_, OnFinishLaunching()); -} - -void Browser::OnAccessibilitySupportChanged() { - FOR_EACH_OBSERVER(BrowserObserver, - observers_, - OnAccessibilitySupportChanged()); -} - -void Browser::RequestLogin( - LoginHandler* login_handler, - std::unique_ptr request_details) { - FOR_EACH_OBSERVER(BrowserObserver, - observers_, - OnLogin(login_handler, *(request_details.get()))); -} - -void Browser::NotifyAndShutdown() { - if (is_shutdown_) - return; - - bool prevent_default = false; - FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWillQuit(&prevent_default)); - - if (prevent_default) { - is_quiting_ = false; - return; - } - - Shutdown(); -} - -bool Browser::HandleBeforeQuit() { - bool prevent_default = false; - FOR_EACH_OBSERVER(BrowserObserver, - observers_, - OnBeforeQuit(&prevent_default)); - - return !prevent_default; -} - -void Browser::OnWindowCloseCancelled(NativeWindow* window) { - if (is_quiting_) - // Once a beforeunload handler has prevented the closing, we think the quit - // is cancelled too. - is_quiting_ = false; -} - -void Browser::OnWindowAllClosed() { - if (is_exiting_) - Shutdown(); - else if (is_quiting_) - NotifyAndShutdown(); - else - FOR_EACH_OBSERVER(BrowserObserver, observers_, OnWindowAllClosed()); -} - -} // namespace atom diff --git a/atom/browser/browser.h b/atom/browser/browser.h deleted file mode 100644 index 96fad18fc7f07..0000000000000 --- a/atom/browser/browser.h +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_BROWSER_H_ -#define ATOM_BROWSER_BROWSER_H_ - -#include -#include - -#include "base/macros.h" -#include "base/compiler_specific.h" -#include "base/observer_list.h" -#include "base/strings/string16.h" -#include "atom/browser/browser_observer.h" -#include "atom/browser/window_list_observer.h" -#include "native_mate/arguments.h" - -#if defined(OS_WIN) -#include "base/files/file_path.h" -#endif - -namespace base { -class DictionaryValue; -class FilePath; -} - -namespace gfx { -class Image; -} - -namespace atom { - -class AtomMenuModel; -class LoginHandler; - -// This class is used for control application-wide operations. -class Browser : public WindowListObserver { - public: - Browser(); - ~Browser(); - - static Browser* Get(); - - // Try to close all windows and quit the application. - void Quit(); - - // Exit the application immediately and set exit code. - void Exit(int code); - - // Cleanup everything and shutdown the application gracefully. - void Shutdown(); - - // Focus the application. - void Focus(); - - // Returns the version of the executable (or bundle). - std::string GetVersion() const; - - // Overrides the application version. - void SetVersion(const std::string& version); - - // Returns the application's name, default is just Atom-Shell. - std::string GetName() const; - - // Overrides the application name. - void SetName(const std::string& name); - - // Add the |path| to recent documents list. - void AddRecentDocument(const base::FilePath& path); - - // Clear the recent documents list. - void ClearRecentDocuments(); - - // Set the application user model ID. - void SetAppUserModelID(const base::string16& name); - - // Remove the default protocol handler registry key - bool RemoveAsDefaultProtocolClient(const std::string& protocol); - - // Set as default handler for a protocol. - bool SetAsDefaultProtocolClient(const std::string& protocol); - - // Query the current state of default handler for a protocol. - bool IsDefaultProtocolClient(const std::string& protocol); - - // Set/Get the badge count. - bool SetBadgeCount(int count); - int GetBadgeCount(); - - // Set/Get the login item settings of the app - struct LoginItemSettings { - bool open_at_login = false; - bool open_as_hidden = false; - bool restore_state = false; - bool opened_at_login = false; - bool opened_as_hidden = false; - }; - void SetLoginItemSettings(LoginItemSettings settings); - LoginItemSettings GetLoginItemSettings(); - -#if defined(OS_MACOSX) - // Hide the application. - void Hide(); - - // Show the application. - void Show(); - - // Creates an activity and sets it as the one currently in use. - void SetUserActivity(const std::string& type, - const base::DictionaryValue& user_info, - mate::Arguments* args); - - // Returns the type name of the current user activity. - std::string GetCurrentActivityType(); - - // Resumes an activity via hand-off. - bool ContinueUserActivity(const std::string& type, - const base::DictionaryValue& user_info); - - // Bounce the dock icon. - enum BounceType { - BOUNCE_CRITICAL = 0, - BOUNCE_INFORMATIONAL = 10, - }; - int DockBounce(BounceType type); - void DockCancelBounce(int request_id); - - // Bounce the Downloads stack. - void DockDownloadFinished(const std::string& filePath); - - // Set/Get dock's badge text. - void DockSetBadgeText(const std::string& label); - std::string DockGetBadgeText(); - - // Hide/Show dock. - void DockHide(); - void DockShow(); - bool DockIsVisible(); - - // Set docks' menu. - void DockSetMenu(AtomMenuModel* model); - - // Set docks' icon. - void DockSetIcon(const gfx::Image& image); -#endif // defined(OS_MACOSX) - -#if defined(OS_WIN) - struct UserTask { - base::FilePath program; - base::string16 arguments; - base::string16 title; - base::string16 description; - base::FilePath icon_path; - int icon_index; - }; - - // Add a custom task to jump list. - void SetUserTasks(const std::vector& tasks); - - // Returns the application user model ID, if there isn't one, then create - // one from app's name. - // The returned string managed by Browser, and should not be modified. - PCWSTR GetAppUserModelID(); -#endif // defined(OS_WIN) - -#if defined(OS_LINUX) - // Whether Unity launcher is running. - bool IsUnityRunning(); -#endif // defined(OS_LINUX) - - // Tell the application to open a file. - bool OpenFile(const std::string& file_path); - - // Tell the application to open a url. - void OpenURL(const std::string& url); - - // Tell the application that application is activated with visible/invisible - // windows. - void Activate(bool has_visible_windows); - - // Tell the application the loading has been done. - void WillFinishLaunching(); - void DidFinishLaunching(); - - void OnAccessibilitySupportChanged(); - - // Request basic auth login. - void RequestLogin(LoginHandler* login_handler, - std::unique_ptr request_details); - - void AddObserver(BrowserObserver* obs) { - observers_.AddObserver(obs); - } - - void RemoveObserver(BrowserObserver* obs) { - observers_.RemoveObserver(obs); - } - - bool is_shutting_down() const { return is_shutdown_; } - bool is_quiting() const { return is_quiting_; } - bool is_ready() const { return is_ready_; } - - protected: - // Returns the version of application bundle or executable file. - std::string GetExecutableFileVersion() const; - - // Returns the name of application bundle or executable file. - std::string GetExecutableFileProductName() const; - - // Send the will-quit message and then shutdown the application. - void NotifyAndShutdown(); - - // Send the before-quit message and start closing windows. - bool HandleBeforeQuit(); - - bool is_quiting_; - - private: - // WindowListObserver implementations: - void OnWindowCloseCancelled(NativeWindow* window) override; - void OnWindowAllClosed() override; - - // Observers of the browser. - base::ObserverList observers_; - - // Whether `app.exit()` has been called - bool is_exiting_; - - // Whether "ready" event has been emitted. - bool is_ready_; - - // The browser is being shutdown. - bool is_shutdown_; - - std::string version_override_; - std::string name_override_; - - int badge_count_ = 0; - -#if defined(OS_WIN) - base::string16 app_user_model_id_; -#endif - - DISALLOW_COPY_AND_ASSIGN(Browser); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_BROWSER_H_ diff --git a/atom/browser/browser_linux.cc b/atom/browser/browser_linux.cc deleted file mode 100644 index 6aff6027266fa..0000000000000 --- a/atom/browser/browser_linux.cc +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/browser.h" - -#include - -#include "atom/browser/native_window.h" -#include "atom/browser/window_list.h" -#include "atom/common/atom_version.h" -#include "brightray/common/application_info.h" -#include "chrome/browser/ui/libgtk2ui/unity_service.h" - -namespace atom { - -void Browser::Focus() { - // Focus on the first visible window. - WindowList* list = WindowList::GetInstance(); - for (WindowList::iterator iter = list->begin(); iter != list->end(); ++iter) { - NativeWindow* window = *iter; - if (window->IsVisible()) { - window->Focus(true); - break; - } - } -} - -void Browser::AddRecentDocument(const base::FilePath& path) { -} - -void Browser::ClearRecentDocuments() { -} - -void Browser::SetAppUserModelID(const base::string16& name) { -} - -bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol) { - return false; -} - -bool Browser::SetAsDefaultProtocolClient(const std::string& protocol) { - return false; -} - -bool Browser::IsDefaultProtocolClient(const std::string& protocol) { - return false; -} - -bool Browser::SetBadgeCount(int count) { - if (IsUnityRunning()) { - unity::SetDownloadCount(count); - badge_count_ = count; - return true; - } else { - return false; - } -} - -void Browser::SetLoginItemSettings(LoginItemSettings settings) { -} - -Browser::LoginItemSettings Browser::GetLoginItemSettings() { - return LoginItemSettings(); -} - -std::string Browser::GetExecutableFileVersion() const { - return brightray::GetApplicationVersion(); -} - -std::string Browser::GetExecutableFileProductName() const { - return brightray::GetApplicationName(); -} - -bool Browser::IsUnityRunning() { - return unity::IsRunning(); -} - -} // namespace atom diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm deleted file mode 100644 index 2cfb4ca2cdf6a..0000000000000 --- a/atom/browser/browser_mac.mm +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/browser.h" - -#include "atom/browser/mac/atom_application.h" -#include "atom/browser/mac/atom_application_delegate.h" -#include "atom/browser/mac/dict_util.h" -#include "atom/browser/native_window.h" -#include "atom/browser/window_list.h" -#include "base/mac/bundle_locations.h" -#include "base/mac/foundation_util.h" -#include "base/mac/mac_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/sys_string_conversions.h" -#include "brightray/common/application_info.h" -#include "net/base/mac/url_conversions.h" -#include "url/gurl.h" - -namespace atom { - -void Browser::Focus() { - [[AtomApplication sharedApplication] activateIgnoringOtherApps:YES]; -} - -void Browser::Hide() { - [[AtomApplication sharedApplication] hide:nil]; -} - -void Browser::Show() { - [[AtomApplication sharedApplication] unhide:nil]; -} - -void Browser::AddRecentDocument(const base::FilePath& path) { - NSString* path_string = base::mac::FilePathToNSString(path); - if (!path_string) - return; - NSURL* u = [NSURL fileURLWithPath:path_string]; - if (!u) - return; - [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:u]; -} - -void Browser::ClearRecentDocuments() { - [[NSDocumentController sharedDocumentController] clearRecentDocuments:nil]; -} - -bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol) { - NSString* identifier = [base::mac::MainBundle() bundleIdentifier]; - if (!identifier) - return false; - - if (!Browser::IsDefaultProtocolClient(protocol)) - return false; - - NSString* protocol_ns = [NSString stringWithUTF8String:protocol.c_str()]; - CFStringRef protocol_cf = base::mac::NSToCFCast(protocol_ns); - CFArrayRef bundleList = LSCopyAllHandlersForURLScheme(protocol_cf); - if (!bundleList) { - return false; - } - // On macOS, we can't query the default, but the handlers list seems to put - // Apple's defaults first, so we'll use the first option that isn't our bundle - CFStringRef other = nil; - for (CFIndex i = 0; i < CFArrayGetCount(bundleList); i++) { - other = (CFStringRef)CFArrayGetValueAtIndex(bundleList, i); - if (![identifier isEqualToString: (__bridge NSString *)other]) { - break; - } - } - - OSStatus return_code = LSSetDefaultHandlerForURLScheme(protocol_cf, other); - return return_code == noErr; -} - -bool Browser::SetAsDefaultProtocolClient(const std::string& protocol) { - if (protocol.empty()) - return false; - - NSString* identifier = [base::mac::MainBundle() bundleIdentifier]; - if (!identifier) - return false; - - NSString* protocol_ns = [NSString stringWithUTF8String:protocol.c_str()]; - OSStatus return_code = - LSSetDefaultHandlerForURLScheme(base::mac::NSToCFCast(protocol_ns), - base::mac::NSToCFCast(identifier)); - return return_code == noErr; -} - -bool Browser::IsDefaultProtocolClient(const std::string& protocol) { - if (protocol.empty()) - return false; - - NSString* identifier = [base::mac::MainBundle() bundleIdentifier]; - if (!identifier) - return false; - - NSString* protocol_ns = [NSString stringWithUTF8String:protocol.c_str()]; - - CFStringRef bundle = - LSCopyDefaultHandlerForURLScheme(base::mac::NSToCFCast(protocol_ns)); - NSString* bundleId = static_cast( - base::mac::CFTypeRefToNSObjectAutorelease(bundle)); - if (!bundleId) - return false; - - // Ensure the comparison is case-insensitive - // as LS does not persist the case of the bundle id. - NSComparisonResult result = - [bundleId caseInsensitiveCompare:identifier]; - return result == NSOrderedSame; -} - -void Browser::SetAppUserModelID(const base::string16& name) { -} - -bool Browser::SetBadgeCount(int count) { - DockSetBadgeText(count != 0 ? base::IntToString(count) : ""); - badge_count_ = count; - return true; -} - -void Browser::SetUserActivity(const std::string& type, - const base::DictionaryValue& user_info, - mate::Arguments* args) { - std::string url_string; - args->GetNext(&url_string); - - [[AtomApplication sharedApplication] - setCurrentActivity:base::SysUTF8ToNSString(type) - withUserInfo:DictionaryValueToNSDictionary(user_info) - withWebpageURL:net::NSURLWithGURL(GURL(url_string))]; -} - -std::string Browser::GetCurrentActivityType() { - NSUserActivity* userActivity = - [[AtomApplication sharedApplication] getCurrentActivity]; - return base::SysNSStringToUTF8(userActivity.activityType); -} - -bool Browser::ContinueUserActivity(const std::string& type, - const base::DictionaryValue& user_info) { - bool prevent_default = false; - FOR_EACH_OBSERVER(BrowserObserver, - observers_, - OnContinueUserActivity(&prevent_default, type, user_info)); - return prevent_default; -} - -Browser::LoginItemSettings Browser::GetLoginItemSettings() { - LoginItemSettings settings; - settings.open_at_login = base::mac::CheckLoginItemStatus( - &settings.open_as_hidden); - settings.restore_state = base::mac::WasLaunchedAsLoginItemRestoreState(); - settings.opened_at_login = base::mac::WasLaunchedAsLoginOrResumeItem(); - settings.opened_as_hidden = base::mac::WasLaunchedAsHiddenLoginItem(); - return settings; -} - -void Browser::SetLoginItemSettings(LoginItemSettings settings) { - if (settings.open_at_login) - base::mac::AddToLoginItems(settings.open_as_hidden); - else - base::mac::RemoveFromLoginItems(); -} - -std::string Browser::GetExecutableFileVersion() const { - return brightray::GetApplicationVersion(); -} - -std::string Browser::GetExecutableFileProductName() const { - return brightray::GetApplicationName(); -} - -int Browser::DockBounce(BounceType type) { - return [[AtomApplication sharedApplication] - requestUserAttention:(NSRequestUserAttentionType)type]; -} - -void Browser::DockCancelBounce(int request_id) { - [[AtomApplication sharedApplication] cancelUserAttentionRequest:request_id]; -} - -void Browser::DockSetBadgeText(const std::string& label) { - NSDockTile *tile = [[AtomApplication sharedApplication] dockTile]; - [tile setBadgeLabel:base::SysUTF8ToNSString(label)]; -} - -void Browser::DockDownloadFinished(const std::string& filePath) { - [[NSDistributedNotificationCenter defaultCenter] - postNotificationName: @"com.apple.DownloadFileFinished" - object: base::SysUTF8ToNSString(filePath)]; -} - -std::string Browser::DockGetBadgeText() { - NSDockTile *tile = [[AtomApplication sharedApplication] dockTile]; - return base::SysNSStringToUTF8([tile badgeLabel]); -} - -void Browser::DockHide() { - WindowList* list = WindowList::GetInstance(); - for (WindowList::iterator it = list->begin(); it != list->end(); ++it) - [(*it)->GetNativeWindow() setCanHide:NO]; - - ProcessSerialNumber psn = { 0, kCurrentProcess }; - TransformProcessType(&psn, kProcessTransformToUIElementApplication); -} - -bool Browser::DockIsVisible() { - // Because DockShow has a slight delay this may not be true immediately - // after that call. - return ([[NSRunningApplication currentApplication] activationPolicy] == NSApplicationActivationPolicyRegular); -} - -void Browser::DockShow() { - BOOL active = [[NSRunningApplication currentApplication] isActive]; - ProcessSerialNumber psn = { 0, kCurrentProcess }; - if (active) { - // Workaround buggy behavior of TransformProcessType. - // http://stackoverflow.com/questions/7596643/ - NSArray* runningApps = [NSRunningApplication - runningApplicationsWithBundleIdentifier:@"com.apple.dock"]; - for (NSRunningApplication* app in runningApps) { - [app activateWithOptions:NSApplicationActivateIgnoringOtherApps]; - break; - } - dispatch_time_t one_ms = dispatch_time(DISPATCH_TIME_NOW, USEC_PER_SEC); - dispatch_after(one_ms, dispatch_get_main_queue(), ^{ - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - dispatch_time_t one_ms = dispatch_time(DISPATCH_TIME_NOW, USEC_PER_SEC); - dispatch_after(one_ms, dispatch_get_main_queue(), ^{ - [[NSRunningApplication currentApplication] - activateWithOptions:NSApplicationActivateIgnoringOtherApps]; - }); - }); - } else { - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - } -} - -void Browser::DockSetMenu(AtomMenuModel* model) { - AtomApplicationDelegate* delegate = (AtomApplicationDelegate*)[NSApp delegate]; - [delegate setApplicationDockMenu:model]; -} - -void Browser::DockSetIcon(const gfx::Image& image) { - [[AtomApplication sharedApplication] - setApplicationIconImage:image.AsNSImage()]; -} - -} // namespace atom diff --git a/atom/browser/browser_observer.h b/atom/browser/browser_observer.h deleted file mode 100644 index 54617e5e09fad..0000000000000 --- a/atom/browser/browser_observer.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_BROWSER_OBSERVER_H_ -#define ATOM_BROWSER_BROWSER_OBSERVER_H_ - -#include - -#include "build/build_config.h" - -namespace base { -class DictionaryValue; -} - -namespace atom { - -class LoginHandler; - -class BrowserObserver { - public: - // The browser is about to close all windows. - virtual void OnBeforeQuit(bool* prevent_default) {} - - // The browser has closed all windows and will quit. - virtual void OnWillQuit(bool* prevent_default) {} - - // The browser has closed all windows. If the browser is quiting, then this - // method will not be called, instead it will call OnWillQuit. - virtual void OnWindowAllClosed() {} - - // The browser is quitting. - virtual void OnQuit() {} - - // The browser has opened a file by double clicking in Finder or dragging the - // file to the Dock icon. (macOS only) - virtual void OnOpenFile(bool* prevent_default, - const std::string& file_path) {} - - // Browser is used to open a url. - virtual void OnOpenURL(const std::string& url) {} - - // The browser is activated with visible/invisible windows (usually by - // clicking on the dock icon). - virtual void OnActivate(bool has_visible_windows) {} - - // The browser has finished loading. - virtual void OnWillFinishLaunching() {} - virtual void OnFinishLaunching() {} - - // The browser requests HTTP login. - virtual void OnLogin(LoginHandler* login_handler, - const base::DictionaryValue& request_details) {} - - // The browser's accessibility suppport has changed. - virtual void OnAccessibilitySupportChanged() {} - -#if defined(OS_MACOSX) - // The browser wants to resume a user activity via handoff. (macOS only) - virtual void OnContinueUserActivity( - bool* prevent_default, - const std::string& type, - const base::DictionaryValue& user_info) {} -#endif - - protected: - virtual ~BrowserObserver() {} -}; - -} // namespace atom - -#endif // ATOM_BROWSER_BROWSER_OBSERVER_H_ diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc deleted file mode 100644 index 059b28909425f..0000000000000 --- a/atom/browser/browser_win.cc +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/browser.h" - -#include -#include -#include -#include -#include - -#include "base/base_paths.h" -#include "base/file_version_info.h" -#include "base/files/file_path.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/win_util.h" -#include "base/win/registry.h" -#include "base/win/windows_version.h" -#include "atom/common/atom_version.h" - -namespace atom { - -namespace { - -const wchar_t kAppUserModelIDFormat[] = L"electron.app.$1"; - -BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) { - DWORD target_process_id = *reinterpret_cast(param); - DWORD process_id = 0; - - GetWindowThreadProcessId(hwnd, &process_id); - if (process_id == target_process_id) { - SetFocus(hwnd); - return FALSE; - } - - return TRUE; -} - -} // namespace - -void Browser::Focus() { - // On Windows we just focus on the first window found for this process. - DWORD pid = GetCurrentProcessId(); - EnumWindows(&WindowsEnumerationHandler, reinterpret_cast(&pid)); -} - -void Browser::AddRecentDocument(const base::FilePath& path) { - if (base::win::GetVersion() < base::win::VERSION_WIN7) - return; - - CComPtr item; - HRESULT hr = SHCreateItemFromParsingName( - path.value().c_str(), NULL, IID_PPV_ARGS(&item)); - if (SUCCEEDED(hr)) { - SHARDAPPIDINFO info; - info.psi = item; - info.pszAppID = GetAppUserModelID(); - SHAddToRecentDocs(SHARD_APPIDINFO, &info); - } -} - -void Browser::ClearRecentDocuments() { - CComPtr destinations; - if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations, - NULL, CLSCTX_INPROC_SERVER))) - return; - if (FAILED(destinations->SetAppID(GetAppUserModelID()))) - return; - destinations->RemoveAllDestinations(); -} - -void Browser::SetAppUserModelID(const base::string16& name) { - app_user_model_id_ = name; - SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str()); -} - -void Browser::SetUserTasks(const std::vector& tasks) { - CComPtr destinations; - if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList))) - return; - if (FAILED(destinations->SetAppID(GetAppUserModelID()))) - return; - - // Start a transaction that updates the JumpList of this application. - UINT max_slots; - CComPtr removed; - if (FAILED(destinations->BeginList(&max_slots, IID_PPV_ARGS(&removed)))) - return; - - CComPtr collection; - if (FAILED(collection.CoCreateInstance(CLSID_EnumerableObjectCollection))) - return; - - for (auto& task : tasks) { - CComPtr link; - if (FAILED(link.CoCreateInstance(CLSID_ShellLink)) || - FAILED(link->SetPath(task.program.value().c_str())) || - FAILED(link->SetArguments(task.arguments.c_str())) || - FAILED(link->SetDescription(task.description.c_str()))) - return; - - if (!task.icon_path.empty() && - FAILED(link->SetIconLocation(task.icon_path.value().c_str(), - task.icon_index))) - return; - - CComQIPtr property_store = link; - if (!base::win::SetStringValueForPropertyStore(property_store, PKEY_Title, - task.title.c_str())) - return; - - if (FAILED(collection->AddObject(link))) - return; - } - - // When the list is empty "AddUserTasks" could fail, so we don't check return - // value for it. - CComQIPtr task_array = collection; - destinations->AddUserTasks(task_array); - destinations->CommitList(); -} - -bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol) { - if (protocol.empty()) - return false; - - base::FilePath path; - if (!PathService::Get(base::FILE_EXE, &path)) { - LOG(ERROR) << "Error getting app exe path"; - return false; - } - - // Main Registry Key - HKEY root = HKEY_CURRENT_USER; - std::string keyPathStr = "Software\\Classes\\" + protocol; - std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end()); - - // Command Key - std::string cmdPathStr = keyPathStr + "\\shell\\open\\command"; - std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end()); - - base::win::RegKey key; - base::win::RegKey commandKey; - if (FAILED(key.Open(root, keyPath.c_str(), KEY_ALL_ACCESS))) - // Key doesn't even exist, we can confirm that it is not set - return true; - - if (FAILED(commandKey.Open(root, cmdPath.c_str(), KEY_ALL_ACCESS))) - // Key doesn't even exist, we can confirm that it is not set - return true; - - std::wstring keyVal; - if (FAILED(commandKey.ReadValue(L"", &keyVal))) - // Default value not set, we can confirm that it is not set - return true; - - std::wstring exePath(path.value()); - std::wstring exe = L"\"" + exePath + L"\" \"%1\""; - if (keyVal == exe) { - // Let's kill the key - if (FAILED(key.DeleteKey(L"shell"))) - return false; - - return true; - } else { - return true; - } -} - -bool Browser::SetAsDefaultProtocolClient(const std::string& protocol) { - // HKEY_CLASSES_ROOT - // $PROTOCOL - // (Default) = "URL:$NAME" - // URL Protocol = "" - // shell - // open - // command - // (Default) = "$COMMAND" "%1" - // - // However, the "HKEY_CLASSES_ROOT" key can only be written by the - // Administrator user. So, we instead write to "HKEY_CURRENT_USER\ - // Software\Classes", which is inherited by "HKEY_CLASSES_ROOT" - // anyway, and can be written by unprivileged users. - - if (protocol.empty()) - return false; - - base::FilePath path; - if (!PathService::Get(base::FILE_EXE, &path)) { - LOG(ERROR) << "Error getting app exe path"; - return false; - } - - // Main Registry Key - HKEY root = HKEY_CURRENT_USER; - std::string keyPathStr = "Software\\Classes\\" + protocol; - std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end()); - std::string urlDeclStr = "URL:" + protocol; - std::wstring urlDecl = std::wstring(urlDeclStr.begin(), urlDeclStr.end()); - - // Command Key - std::string cmdPathStr = keyPathStr + "\\shell\\open\\command"; - std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end()); - - // Executable Path - std::wstring exePath(path.value()); - std::wstring exe = L"\"" + exePath + L"\" \"%1\""; - - // Write information to registry - base::win::RegKey key(root, keyPath.c_str(), KEY_ALL_ACCESS); - if (FAILED(key.WriteValue(L"URL Protocol", L"")) || - FAILED(key.WriteValue(L"", urlDecl.c_str()))) - return false; - - base::win::RegKey commandKey(root, cmdPath.c_str(), KEY_ALL_ACCESS); - if (FAILED(commandKey.WriteValue(L"", exe.c_str()))) - return false; - - return true; -} - -bool Browser::IsDefaultProtocolClient(const std::string& protocol) { - if (protocol.empty()) - return false; - - base::FilePath path; - if (!PathService::Get(base::FILE_EXE, &path)) { - LOG(ERROR) << "Error getting app exe path"; - return false; - } - - // Main Registry Key - HKEY root = HKEY_CURRENT_USER; - std::string keyPathStr = "Software\\Classes\\" + protocol; - std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end()); - - // Command Key - std::string cmdPathStr = keyPathStr + "\\shell\\open\\command"; - std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end()); - - base::win::RegKey key; - base::win::RegKey commandKey; - if (FAILED(key.Open(root, keyPath.c_str(), KEY_ALL_ACCESS))) - // Key doesn't exist, we can confirm that it is not set - return false; - - if (FAILED(commandKey.Open(root, cmdPath.c_str(), KEY_ALL_ACCESS))) - // Key doesn't exist, we can confirm that it is not set - return false; - - std::wstring keyVal; - if (FAILED(commandKey.ReadValue(L"", &keyVal))) - // Default value not set, we can confirm that it is not set - return false; - - std::wstring exePath(path.value()); - std::wstring exe = L"\"" + exePath + L"\" \"%1\""; - if (keyVal == exe) { - // Default value is the same as current file path - return true; - } else { - return false; - } -} - -bool Browser::SetBadgeCount(int count) { - return false; -} - -void Browser::SetLoginItemSettings(LoginItemSettings settings) { - std::wstring keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; - base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS); - - if (settings.open_at_login) { - base::FilePath path; - if (PathService::Get(base::FILE_EXE, &path)) { - std::wstring exePath(path.value()); - key.WriteValue(GetAppUserModelID(), exePath.c_str()); - } - } else { - key.DeleteValue(GetAppUserModelID()); - } -} - -Browser::LoginItemSettings Browser::GetLoginItemSettings() { - LoginItemSettings settings; - std::wstring keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; - base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS); - std::wstring keyVal; - - if (!FAILED(key.ReadValue(GetAppUserModelID(), &keyVal))) { - base::FilePath path; - if (PathService::Get(base::FILE_EXE, &path)) { - std::wstring exePath(path.value()); - settings.open_at_login = keyVal == exePath; - } - } - - return settings; -} - - -PCWSTR Browser::GetAppUserModelID() { - if (app_user_model_id_.empty()) { - SetAppUserModelID(base::ReplaceStringPlaceholders( - kAppUserModelIDFormat, base::UTF8ToUTF16(GetName()), nullptr)); - } - - return app_user_model_id_.c_str(); -} - -std::string Browser::GetExecutableFileVersion() const { - base::FilePath path; - if (PathService::Get(base::FILE_EXE, &path)) { - std::unique_ptr version_info( - FileVersionInfo::CreateFileVersionInfo(path)); - return base::UTF16ToUTF8(version_info->product_version()); - } - - return ATOM_VERSION_STRING; -} - -std::string Browser::GetExecutableFileProductName() const { - base::FilePath path; - if (PathService::Get(base::FILE_EXE, &path)) { - std::unique_ptr version_info( - FileVersionInfo::CreateFileVersionInfo(path)); - return base::UTF16ToUTF8(version_info->product_name()); - } - - return ATOM_PRODUCT_NAME; -} - -} // namespace atom diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc deleted file mode 100644 index f2f0ee8aec534..0000000000000 --- a/atom/browser/common_web_contents_delegate.cc +++ /dev/null @@ -1,643 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/common_web_contents_delegate.h" - -#include -#include -#include - -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/atom_javascript_dialog_manager.h" -#include "atom/browser/atom_security_state_model_client.h" -#include "atom/browser/native_window.h" -#include "atom/browser/ui/file_dialog.h" -#include "atom/browser/web_dialog_helper.h" -#include "atom/common/atom_constants.h" -#include "base/files/file_util.h" -#include "components/prefs/pref_service.h" -#include "components/prefs/scoped_user_pref_update.h" -#include "chrome/browser/printing/print_preview_message_handler.h" -#include "chrome/browser/printing/print_view_manager_basic.h" -#include "chrome/browser/ui/browser_dialogs.h" -#include "chrome/common/pref_names.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/child_process_security_policy.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host.h" -#include "content/public/browser/security_style_explanation.h" -#include "content/public/browser/security_style_explanations.h" -#include "storage/browser/fileapi/isolated_context.h" - -using content::BrowserThread; -using security_state::SecurityStateModel; - -namespace atom { - -namespace { - -const char kRootName[] = ""; - -struct FileSystem { - FileSystem() { - } - FileSystem(const std::string& file_system_name, - const std::string& root_url, - const std::string& file_system_path) - : file_system_name(file_system_name), - root_url(root_url), - file_system_path(file_system_path) { - } - - std::string file_system_name; - std::string root_url; - std::string file_system_path; -}; - -std::string RegisterFileSystem(content::WebContents* web_contents, - const base::FilePath& path) { - auto isolated_context = storage::IsolatedContext::GetInstance(); - std::string root_name(kRootName); - std::string file_system_id = isolated_context->RegisterFileSystemForPath( - storage::kFileSystemTypeNativeLocal, - std::string(), - path, - &root_name); - - content::ChildProcessSecurityPolicy* policy = - content::ChildProcessSecurityPolicy::GetInstance(); - content::RenderViewHost* render_view_host = web_contents->GetRenderViewHost(); - int renderer_id = render_view_host->GetProcess()->GetID(); - policy->GrantReadFileSystem(renderer_id, file_system_id); - policy->GrantWriteFileSystem(renderer_id, file_system_id); - policy->GrantCreateFileForFileSystem(renderer_id, file_system_id); - policy->GrantDeleteFromFileSystem(renderer_id, file_system_id); - - if (!policy->CanReadFile(renderer_id, path)) - policy->GrantReadFile(renderer_id, path); - - return file_system_id; -} - -FileSystem CreateFileSystemStruct( - content::WebContents* web_contents, - const std::string& file_system_id, - const std::string& file_system_path) { - const GURL origin = web_contents->GetURL().GetOrigin(); - std::string file_system_name = - storage::GetIsolatedFileSystemName(origin, file_system_id); - std::string root_url = storage::GetIsolatedFileSystemRootURIString( - origin, file_system_id, kRootName); - return FileSystem(file_system_name, root_url, file_system_path); -} - -base::DictionaryValue* CreateFileSystemValue(const FileSystem& file_system) { - auto* file_system_value = new base::DictionaryValue(); - file_system_value->SetString("fileSystemName", file_system.file_system_name); - file_system_value->SetString("rootURL", file_system.root_url); - file_system_value->SetString("fileSystemPath", file_system.file_system_path); - return file_system_value; -} - -void WriteToFile(const base::FilePath& path, - const std::string& content) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); - DCHECK(!path.empty()); - - base::WriteFile(path, content.data(), content.size()); -} - -void AppendToFile(const base::FilePath& path, - const std::string& content) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); - DCHECK(!path.empty()); - - base::AppendToFile(path, content.data(), content.size()); -} - -PrefService* GetPrefService(content::WebContents* web_contents) { - auto context = web_contents->GetBrowserContext(); - return static_cast(context)->prefs(); -} - -std::set GetAddedFileSystemPaths( - content::WebContents* web_contents) { - auto pref_service = GetPrefService(web_contents); - const base::DictionaryValue* file_system_paths_value = - pref_service->GetDictionary(prefs::kDevToolsFileSystemPaths); - std::set result; - if (file_system_paths_value) { - base::DictionaryValue::Iterator it(*file_system_paths_value); - for (; !it.IsAtEnd(); it.Advance()) { - result.insert(it.key()); - } - } - return result; -} - -bool IsDevToolsFileSystemAdded( - content::WebContents* web_contents, - const std::string& file_system_path) { - auto file_system_paths = GetAddedFileSystemPaths(web_contents); - return file_system_paths.find(file_system_path) != file_system_paths.end(); -} - -content::SecurityStyle SecurityLevelToSecurityStyle( - SecurityStateModel::SecurityLevel security_level) { - switch (security_level) { - case SecurityStateModel::NONE: - return content::SECURITY_STYLE_UNAUTHENTICATED; - case SecurityStateModel::SECURITY_WARNING: - case SecurityStateModel::SECURITY_POLICY_WARNING: - return content::SECURITY_STYLE_WARNING; - case SecurityStateModel::EV_SECURE: - case SecurityStateModel::SECURE: - return content::SECURITY_STYLE_AUTHENTICATED; - case SecurityStateModel::SECURITY_ERROR: - return content::SECURITY_STYLE_AUTHENTICATION_BROKEN; - } - - return content::SECURITY_STYLE_UNKNOWN; -} - -} // namespace - -CommonWebContentsDelegate::CommonWebContentsDelegate() - : html_fullscreen_(false), - native_fullscreen_(false), - devtools_file_system_indexer_(new DevToolsFileSystemIndexer) { -} - -CommonWebContentsDelegate::~CommonWebContentsDelegate() { -} - -void CommonWebContentsDelegate::InitWithWebContents( - content::WebContents* web_contents, - AtomBrowserContext* browser_context) { - browser_context_ = browser_context; - web_contents->SetDelegate(this); - - printing::PrintViewManagerBasic::CreateForWebContents(web_contents); - printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents); - - // Create InspectableWebContents. - web_contents_.reset(brightray::InspectableWebContents::Create(web_contents)); - web_contents_->SetDelegate(this); -} - -void CommonWebContentsDelegate::SetOwnerWindow(NativeWindow* owner_window) { - SetOwnerWindow(GetWebContents(), owner_window); -} - -void CommonWebContentsDelegate::SetOwnerWindow( - content::WebContents* web_contents, NativeWindow* owner_window) { - owner_window_ = owner_window->GetWeakPtr(); - NativeWindowRelay* relay = new NativeWindowRelay(owner_window_); - web_contents->SetUserData(relay->key, relay); -} - -void CommonWebContentsDelegate::DestroyWebContents() { - web_contents_.reset(); -} - -content::WebContents* CommonWebContentsDelegate::GetWebContents() const { - if (!web_contents_) - return nullptr; - return web_contents_->GetWebContents(); -} - -content::WebContents* -CommonWebContentsDelegate::GetDevToolsWebContents() const { - if (!web_contents_) - return nullptr; - return web_contents_->GetDevToolsWebContents(); -} - -content::WebContents* CommonWebContentsDelegate::OpenURLFromTab( - content::WebContents* source, - const content::OpenURLParams& params) { - content::NavigationController::LoadURLParams load_url_params(params.url); - load_url_params.referrer = params.referrer; - load_url_params.transition_type = params.transition; - load_url_params.extra_headers = params.extra_headers; - load_url_params.should_replace_current_entry = - params.should_replace_current_entry; - load_url_params.is_renderer_initiated = params.is_renderer_initiated; - load_url_params.should_clear_history_list = true; - - source->GetController().LoadURLWithParams(load_url_params); - return source; -} - -bool CommonWebContentsDelegate::CanOverscrollContent() const { - return false; -} - -content::JavaScriptDialogManager* -CommonWebContentsDelegate::GetJavaScriptDialogManager( - content::WebContents* source) { - if (!dialog_manager_) - dialog_manager_.reset(new AtomJavaScriptDialogManager); - - return dialog_manager_.get(); -} - -content::ColorChooser* CommonWebContentsDelegate::OpenColorChooser( - content::WebContents* web_contents, - SkColor color, - const std::vector& suggestions) { - return chrome::ShowColorChooser(web_contents, color); -} - -void CommonWebContentsDelegate::RunFileChooser( - content::WebContents* guest, - const content::FileChooserParams& params) { - if (!web_dialog_helper_) - web_dialog_helper_.reset(new WebDialogHelper(owner_window())); - web_dialog_helper_->RunFileChooser(guest, params); -} - -void CommonWebContentsDelegate::EnumerateDirectory(content::WebContents* guest, - int request_id, - const base::FilePath& path) { - if (!web_dialog_helper_) - web_dialog_helper_.reset(new WebDialogHelper(owner_window())); - web_dialog_helper_->EnumerateDirectory(guest, request_id, path); -} - -void CommonWebContentsDelegate::EnterFullscreenModeForTab( - content::WebContents* source, const GURL& origin) { - if (!owner_window_) - return; - SetHtmlApiFullscreen(true); - owner_window_->NotifyWindowEnterHtmlFullScreen(); - source->GetRenderViewHost()->GetWidget()->WasResized(); -} - -void CommonWebContentsDelegate::ExitFullscreenModeForTab( - content::WebContents* source) { - if (!owner_window_) - return; - SetHtmlApiFullscreen(false); - owner_window_->NotifyWindowLeaveHtmlFullScreen(); - source->GetRenderViewHost()->GetWidget()->WasResized(); -} - -bool CommonWebContentsDelegate::IsFullscreenForTabOrPending( - const content::WebContents* source) const { - return html_fullscreen_; -} - -content::SecurityStyle CommonWebContentsDelegate::GetSecurityStyle( - content::WebContents* web_contents, - content::SecurityStyleExplanations* explanations) { - auto model_client = - AtomSecurityStateModelClient::FromWebContents(web_contents); - - const SecurityStateModel::SecurityInfo& security_info = - model_client->GetSecurityInfo(); - - const content::SecurityStyle security_style = - SecurityLevelToSecurityStyle(security_info.security_level); - - explanations->ran_insecure_content_style = - SecurityLevelToSecurityStyle( - SecurityStateModel::kRanInsecureContentLevel); - explanations->displayed_insecure_content_style = - SecurityLevelToSecurityStyle( - SecurityStateModel::kDisplayedInsecureContentLevel); - - explanations->scheme_is_cryptographic = security_info.scheme_is_cryptographic; - if (!security_info.scheme_is_cryptographic) - return security_style; - - if (security_info.sha1_deprecation_status == - SecurityStateModel::DEPRECATED_SHA1_MAJOR) { - explanations->broken_explanations.push_back( - content::SecurityStyleExplanation( - kSHA1Certificate, - kSHA1MajorDescription, - security_info.cert_id)); - } else if (security_info.sha1_deprecation_status == - SecurityStateModel::DEPRECATED_SHA1_MINOR) { - explanations->unauthenticated_explanations.push_back( - content::SecurityStyleExplanation( - kSHA1Certificate, - kSHA1MinorDescription, - security_info.cert_id)); - } - - explanations->ran_insecure_content = - security_info.mixed_content_status == - SecurityStateModel::RAN_MIXED_CONTENT || - security_info.mixed_content_status == - SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT; - explanations->displayed_insecure_content = - security_info.mixed_content_status == - SecurityStateModel::DISPLAYED_MIXED_CONTENT || - security_info.mixed_content_status == - SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT; - - if (net::IsCertStatusError(security_info.cert_status)) { - std::string error_string = net::ErrorToString( - net::MapCertStatusToNetError(security_info.cert_status)); - - content::SecurityStyleExplanation explanation( - kCertificateError, - "There are issues with the site's certificate chain " + error_string, - security_info.cert_id); - - if (net::IsCertStatusMinorError(security_info.cert_status)) - explanations->unauthenticated_explanations.push_back(explanation); - else - explanations->broken_explanations.push_back(explanation); - } else { - if (security_info.sha1_deprecation_status == - SecurityStateModel::NO_DEPRECATED_SHA1) { - explanations->secure_explanations.push_back( - content::SecurityStyleExplanation( - kValidCertificate, - kValidCertificateDescription, - security_info.cert_id)); - } - } - - if (security_info.is_secure_protocol_and_ciphersuite) { - explanations->secure_explanations.push_back( - content::SecurityStyleExplanation( - kSecureProtocol, - kSecureProtocolDescription)); - } - - return security_style; -} - -void CommonWebContentsDelegate::DevToolsSaveToFile( - const std::string& url, const std::string& content, bool save_as) { - base::FilePath path; - auto it = saved_files_.find(url); - if (it != saved_files_.end() && !save_as) { - path = it->second; - } else { - file_dialog::Filters filters; - base::FilePath default_path(base::FilePath::FromUTF8Unsafe(url)); - if (!file_dialog::ShowSaveDialog(owner_window(), url, "", default_path, - filters, &path)) { - base::StringValue url_value(url); - web_contents_->CallClientFunction( - "DevToolsAPI.canceledSaveURL", &url_value, nullptr, nullptr); - return; - } - } - - saved_files_[url] = path; - BrowserThread::PostTaskAndReply( - BrowserThread::FILE, FROM_HERE, - base::Bind(&WriteToFile, path, content), - base::Bind(&CommonWebContentsDelegate::OnDevToolsSaveToFile, - base::Unretained(this), url)); -} - -void CommonWebContentsDelegate::DevToolsAppendToFile( - const std::string& url, const std::string& content) { - auto it = saved_files_.find(url); - if (it == saved_files_.end()) - return; - - BrowserThread::PostTaskAndReply( - BrowserThread::FILE, FROM_HERE, - base::Bind(&AppendToFile, it->second, content), - base::Bind(&CommonWebContentsDelegate::OnDevToolsAppendToFile, - base::Unretained(this), url)); -} - -void CommonWebContentsDelegate::DevToolsRequestFileSystems() { - auto file_system_paths = GetAddedFileSystemPaths(GetDevToolsWebContents()); - if (file_system_paths.empty()) { - base::ListValue empty_file_system_value; - web_contents_->CallClientFunction("DevToolsAPI.fileSystemsLoaded", - &empty_file_system_value, - nullptr, nullptr); - return; - } - - std::vector file_systems; - for (auto file_system_path : file_system_paths) { - base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path); - std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(), - path); - FileSystem file_system = CreateFileSystemStruct(GetDevToolsWebContents(), - file_system_id, - file_system_path); - file_systems.push_back(file_system); - } - - base::ListValue file_system_value; - for (const auto& file_system : file_systems) - file_system_value.Append(CreateFileSystemValue(file_system)); - web_contents_->CallClientFunction("DevToolsAPI.fileSystemsLoaded", - &file_system_value, nullptr, nullptr); -} - -void CommonWebContentsDelegate::DevToolsAddFileSystem( - const base::FilePath& file_system_path) { - base::FilePath path = file_system_path; - if (path.empty()) { - file_dialog::Filters filters; - base::FilePath default_path; - std::vector paths; - int flag = file_dialog::FILE_DIALOG_OPEN_DIRECTORY; - if (!file_dialog::ShowOpenDialog(owner_window(), "", "", default_path, - filters, flag, &paths)) - return; - - path = paths[0]; - } - - std::string file_system_id = RegisterFileSystem(GetDevToolsWebContents(), - path); - if (IsDevToolsFileSystemAdded(GetDevToolsWebContents(), path.AsUTF8Unsafe())) - return; - - FileSystem file_system = CreateFileSystemStruct(GetDevToolsWebContents(), - file_system_id, - path.AsUTF8Unsafe()); - std::unique_ptr file_system_value( - CreateFileSystemValue(file_system)); - - auto pref_service = GetPrefService(GetDevToolsWebContents()); - DictionaryPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths); - update.Get()->SetWithoutPathExpansion( - path.AsUTF8Unsafe(), base::Value::CreateNullValue()); - - web_contents_->CallClientFunction("DevToolsAPI.fileSystemAdded", - file_system_value.get(), - nullptr, nullptr); -} - -void CommonWebContentsDelegate::DevToolsRemoveFileSystem( - const base::FilePath& file_system_path) { - if (!web_contents_) - return; - - std::string path = file_system_path.AsUTF8Unsafe(); - storage::IsolatedContext::GetInstance()-> - RevokeFileSystemByPath(file_system_path); - - auto pref_service = GetPrefService(GetDevToolsWebContents()); - DictionaryPrefUpdate update(pref_service, prefs::kDevToolsFileSystemPaths); - update.Get()->RemoveWithoutPathExpansion(path, nullptr); - - base::StringValue file_system_path_value(path); - web_contents_->CallClientFunction("DevToolsAPI.fileSystemRemoved", - &file_system_path_value, - nullptr, nullptr); -} - -void CommonWebContentsDelegate::DevToolsIndexPath( - int request_id, - const std::string& file_system_path) { - if (!IsDevToolsFileSystemAdded(GetDevToolsWebContents(), file_system_path)) { - OnDevToolsIndexingDone(request_id, file_system_path); - return; - } - if (devtools_indexing_jobs_.count(request_id) != 0) - return; - devtools_indexing_jobs_[request_id] = - scoped_refptr( - devtools_file_system_indexer_->IndexPath( - file_system_path, - base::Bind( - &CommonWebContentsDelegate::OnDevToolsIndexingWorkCalculated, - base::Unretained(this), - request_id, - file_system_path), - base::Bind(&CommonWebContentsDelegate::OnDevToolsIndexingWorked, - base::Unretained(this), - request_id, - file_system_path), - base::Bind(&CommonWebContentsDelegate::OnDevToolsIndexingDone, - base::Unretained(this), - request_id, - file_system_path))); -} - -void CommonWebContentsDelegate::DevToolsStopIndexing(int request_id) { - auto it = devtools_indexing_jobs_.find(request_id); - if (it == devtools_indexing_jobs_.end()) - return; - it->second->Stop(); - devtools_indexing_jobs_.erase(it); -} - -void CommonWebContentsDelegate::DevToolsSearchInPath( - int request_id, - const std::string& file_system_path, - const std::string& query) { - if (!IsDevToolsFileSystemAdded(GetDevToolsWebContents(), file_system_path)) { - OnDevToolsSearchCompleted(request_id, - file_system_path, - std::vector()); - return; - } - devtools_file_system_indexer_->SearchInPath( - file_system_path, - query, - base::Bind(&CommonWebContentsDelegate::OnDevToolsSearchCompleted, - base::Unretained(this), - request_id, - file_system_path)); -} - -void CommonWebContentsDelegate::OnDevToolsSaveToFile( - const std::string& url) { - // Notify DevTools. - base::StringValue url_value(url); - web_contents_->CallClientFunction( - "DevToolsAPI.savedURL", &url_value, nullptr, nullptr); -} - -void CommonWebContentsDelegate::OnDevToolsAppendToFile( - const std::string& url) { - // Notify DevTools. - base::StringValue url_value(url); - web_contents_->CallClientFunction( - "DevToolsAPI.appendedToURL", &url_value, nullptr, nullptr); -} - -void CommonWebContentsDelegate::OnDevToolsIndexingWorkCalculated( - int request_id, - const std::string& file_system_path, - int total_work) { - base::FundamentalValue request_id_value(request_id); - base::StringValue file_system_path_value(file_system_path); - base::FundamentalValue total_work_value(total_work); - web_contents_->CallClientFunction("DevToolsAPI.indexingTotalWorkCalculated", - &request_id_value, - &file_system_path_value, - &total_work_value); -} - -void CommonWebContentsDelegate::OnDevToolsIndexingWorked( - int request_id, - const std::string& file_system_path, - int worked) { - base::FundamentalValue request_id_value(request_id); - base::StringValue file_system_path_value(file_system_path); - base::FundamentalValue worked_value(worked); - web_contents_->CallClientFunction("DevToolsAPI.indexingWorked", - &request_id_value, - &file_system_path_value, - &worked_value); -} - -void CommonWebContentsDelegate::OnDevToolsIndexingDone( - int request_id, - const std::string& file_system_path) { - devtools_indexing_jobs_.erase(request_id); - base::FundamentalValue request_id_value(request_id); - base::StringValue file_system_path_value(file_system_path); - web_contents_->CallClientFunction("DevToolsAPI.indexingDone", - &request_id_value, - &file_system_path_value, - nullptr); -} - -void CommonWebContentsDelegate::OnDevToolsSearchCompleted( - int request_id, - const std::string& file_system_path, - const std::vector& file_paths) { - base::ListValue file_paths_value; - for (const auto& file_path : file_paths) { - file_paths_value.AppendString(file_path); - } - base::FundamentalValue request_id_value(request_id); - base::StringValue file_system_path_value(file_system_path); - web_contents_->CallClientFunction("DevToolsAPI.searchCompleted", - &request_id_value, - &file_system_path_value, - &file_paths_value); -} - -void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) { - // Window is already in fullscreen mode, save the state. - if (enter_fullscreen && owner_window_->IsFullscreen()) { - native_fullscreen_ = true; - html_fullscreen_ = true; - return; - } - - // Exit html fullscreen state but not window's fullscreen mode. - if (!enter_fullscreen && native_fullscreen_) { - html_fullscreen_ = false; - return; - } - - owner_window_->SetFullScreen(enter_fullscreen); - html_fullscreen_ = enter_fullscreen; - native_fullscreen_ = false; -} - -} // namespace atom diff --git a/atom/browser/common_web_contents_delegate.h b/atom/browser/common_web_contents_delegate.h deleted file mode 100644 index 1746d63b20824..0000000000000 --- a/atom/browser/common_web_contents_delegate.h +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_COMMON_WEB_CONTENTS_DELEGATE_H_ -#define ATOM_BROWSER_COMMON_WEB_CONTENTS_DELEGATE_H_ - -#include -#include -#include - -#include "brightray/browser/inspectable_web_contents_impl.h" -#include "brightray/browser/inspectable_web_contents_delegate.h" -#include "brightray/browser/inspectable_web_contents_view_delegate.h" -#include "brightray/browser/devtools_file_system_indexer.h" -#include "content/public/browser/web_contents_delegate.h" - -using brightray::DevToolsFileSystemIndexer; - -namespace atom { - -class AtomBrowserContext; -class AtomJavaScriptDialogManager; -class NativeWindow; -class WebDialogHelper; - -class CommonWebContentsDelegate - : public content::WebContentsDelegate, - public brightray::InspectableWebContentsDelegate, - public brightray::InspectableWebContentsViewDelegate { - public: - CommonWebContentsDelegate(); - virtual ~CommonWebContentsDelegate(); - - // Creates a InspectableWebContents object and takes onwership of - // |web_contents|. - void InitWithWebContents(content::WebContents* web_contents, - AtomBrowserContext* browser_context); - - // Set the window as owner window. - void SetOwnerWindow(NativeWindow* owner_window); - void SetOwnerWindow(content::WebContents* web_contents, - NativeWindow* owner_window); - - // Destroy the managed InspectableWebContents object. - void DestroyWebContents(); - - // Returns the WebContents managed by this delegate. - content::WebContents* GetWebContents() const; - - // Returns the WebContents of devtools. - content::WebContents* GetDevToolsWebContents() const; - - brightray::InspectableWebContents* managed_web_contents() const { - return web_contents_.get(); - } - - NativeWindow* owner_window() const { return owner_window_.get(); } - - bool is_html_fullscreen() const { return html_fullscreen_; } - - protected: - // content::WebContentsDelegate: - content::WebContents* OpenURLFromTab( - content::WebContents* source, - const content::OpenURLParams& params) override; - bool CanOverscrollContent() const override; - content::JavaScriptDialogManager* GetJavaScriptDialogManager( - content::WebContents* source) override; - content::ColorChooser* OpenColorChooser( - content::WebContents* web_contents, - SkColor color, - const std::vector& suggestions) override; - void RunFileChooser(content::WebContents* web_contents, - const content::FileChooserParams& params) override; - void EnumerateDirectory(content::WebContents* web_contents, - int request_id, - const base::FilePath& path) override; - void EnterFullscreenModeForTab(content::WebContents* source, - const GURL& origin) override; - void ExitFullscreenModeForTab(content::WebContents* source) override; - bool IsFullscreenForTabOrPending( - const content::WebContents* source) const override; - content::SecurityStyle GetSecurityStyle( - content::WebContents* web_contents, - content::SecurityStyleExplanations* explanations) override; - void HandleKeyboardEvent( - content::WebContents* source, - const content::NativeWebKeyboardEvent& event) override; - - // brightray::InspectableWebContentsDelegate: - void DevToolsSaveToFile(const std::string& url, - const std::string& content, - bool save_as) override; - void DevToolsAppendToFile(const std::string& url, - const std::string& content) override; - void DevToolsRequestFileSystems() override; - void DevToolsAddFileSystem(const base::FilePath& path) override; - void DevToolsRemoveFileSystem( - const base::FilePath& file_system_path) override; - void DevToolsIndexPath(int request_id, - const std::string& file_system_path) override; - void DevToolsStopIndexing(int request_id) override; - void DevToolsSearchInPath(int request_id, - const std::string& file_system_path, - const std::string& query) override; - - // brightray::InspectableWebContentsViewDelegate: -#if defined(TOOLKIT_VIEWS) - gfx::ImageSkia GetDevToolsWindowIcon() override; -#endif -#if defined(USE_X11) - void GetDevToolsWindowWMClass( - std::string* name, std::string* class_name) override; -#endif - - private: - // Callback for when DevToolsSaveToFile has completed. - void OnDevToolsSaveToFile(const std::string& url); - - // Callback for when DevToolsAppendToFile has completed. - void OnDevToolsAppendToFile(const std::string& url); - - // - void OnDevToolsIndexingWorkCalculated(int request_id, - const std::string& file_system_path, - int total_work); - void OnDevToolsIndexingWorked(int request_id, - const std::string& file_system_path, - int worked); - void OnDevToolsIndexingDone(int request_id, - const std::string& file_system_path); - void OnDevToolsSearchCompleted(int request_id, - const std::string& file_system_path, - const std::vector& file_paths); - - // Set fullscreen mode triggered by html api. - void SetHtmlApiFullscreen(bool enter_fullscreen); - - // The window that this WebContents belongs to. - base::WeakPtr owner_window_; - - // Whether window is fullscreened by HTML5 api. - bool html_fullscreen_; - - // Whether window is fullscreened by window api. - bool native_fullscreen_; - - std::unique_ptr web_dialog_helper_; - std::unique_ptr dialog_manager_; - scoped_refptr devtools_file_system_indexer_; - - // Make sure BrowserContext is alwasys destroyed after WebContents. - scoped_refptr browser_context_; - - // The stored InspectableWebContents object. - // Notice that web_contents_ must be placed after dialog_manager_, so we can - // make sure web_contents_ is destroyed before dialog_manager_, otherwise a - // crash would happen. - std::unique_ptr web_contents_; - - // Maps url to file path, used by the file requests sent from devtools. - typedef std::map PathsMap; - PathsMap saved_files_; - - // Map id to index job, used for file system indexing requests from devtools. - typedef std::map< - int, - scoped_refptr> - DevToolsIndexingJobsMap; - DevToolsIndexingJobsMap devtools_indexing_jobs_; - - DISALLOW_COPY_AND_ASSIGN(CommonWebContentsDelegate); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_COMMON_WEB_CONTENTS_DELEGATE_H_ diff --git a/atom/browser/common_web_contents_delegate_mac.mm b/atom/browser/common_web_contents_delegate_mac.mm deleted file mode 100644 index c766061379390..0000000000000 --- a/atom/browser/common_web_contents_delegate_mac.mm +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/common_web_contents_delegate.h" - -#import - -#include "brightray/browser/mac/event_dispatching_window.h" -#include "content/public/browser/native_web_keyboard_event.h" -#include "ui/events/keycodes/keyboard_codes.h" - -@interface NSWindow (EventDispatchingWindow) -- (void)redispatchKeyEvent:(NSEvent*)event; -@end - -namespace atom { - -void CommonWebContentsDelegate::HandleKeyboardEvent( - content::WebContents* source, - const content::NativeWebKeyboardEvent& event) { - if (event.skip_in_browser || - event.type == content::NativeWebKeyboardEvent::Char) - return; - - // Escape exits tabbed fullscreen mode. - if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen()) - ExitFullscreenModeForTab(source); - - // Send the event to the menu before sending it to the window - if (event.os_event.type == NSKeyDown && - [[NSApp mainMenu] performKeyEquivalent:event.os_event]) - return; - - if (event.os_event.window && - [event.os_event.window isKindOfClass:[EventDispatchingWindow class]]) - [event.os_event.window redispatchKeyEvent:event.os_event]; -} - -} // namespace atom diff --git a/atom/browser/common_web_contents_delegate_views.cc b/atom/browser/common_web_contents_delegate_views.cc deleted file mode 100644 index d70884c45c2ac..0000000000000 --- a/atom/browser/common_web_contents_delegate_views.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/common_web_contents_delegate.h" - -#include "atom/browser/native_window_views.h" -#include "base/strings/string_util.h" -#include "content/public/browser/native_web_keyboard_event.h" -#include "ui/events/keycodes/keyboard_codes.h" - -#if defined(USE_X11) -#include "atom/browser/browser.h" -#endif - -namespace atom { - -void CommonWebContentsDelegate::HandleKeyboardEvent( - content::WebContents* source, - const content::NativeWebKeyboardEvent& event) { - // Escape exits tabbed fullscreen mode. - if (event.windowsKeyCode == ui::VKEY_ESCAPE && is_html_fullscreen()) - ExitFullscreenModeForTab(source); - - // Let the NativeWindow handle other parts. - if (owner_window()) - owner_window()->HandleKeyboardEvent(source, event); -} - -gfx::ImageSkia CommonWebContentsDelegate::GetDevToolsWindowIcon() { - if (!owner_window()) - return gfx::ImageSkia(); - return static_cast(static_cast( - owner_window()))->GetWindowAppIcon(); -} - -#if defined(USE_X11) -void CommonWebContentsDelegate::GetDevToolsWindowWMClass( - std::string* name, std::string* class_name) { - *class_name = Browser::Get()->GetName(); - *name = base::ToLowerASCII(*class_name); -} -#endif - -} // namespace atom diff --git a/atom/browser/javascript_environment.cc b/atom/browser/javascript_environment.cc deleted file mode 100644 index 0f87a2ca32fdc..0000000000000 --- a/atom/browser/javascript_environment.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/javascript_environment.h" - -#include - -#include "base/command_line.h" -#include "base/message_loop/message_loop.h" -#include "content/public/common/content_switches.h" -#include "gin/array_buffer.h" -#include "gin/v8_initializer.h" - -namespace atom { - -JavascriptEnvironment::JavascriptEnvironment() - : initialized_(Initialize()), - isolate_(isolate_holder_.isolate()), - isolate_scope_(isolate_), - locker_(isolate_), - handle_scope_(isolate_), - context_(isolate_, v8::Context::New(isolate_)), - context_scope_(v8::Local::New(isolate_, context_)) { -} - -void JavascriptEnvironment::OnMessageLoopCreated() { - isolate_holder_.AddRunMicrotasksObserver(); -} - -void JavascriptEnvironment::OnMessageLoopDestroying() { - isolate_holder_.RemoveRunMicrotasksObserver(); -} - -bool JavascriptEnvironment::Initialize() { - auto cmd = base::CommandLine::ForCurrentProcess(); - if (cmd->HasSwitch("debug-brk")) { - // Need to be called before v8::Initialize(). - const char expose_debug_as[] = "--expose_debug_as=v8debug"; - v8::V8::SetFlagsFromString(expose_debug_as, sizeof(expose_debug_as) - 1); - } - - // --js-flags. - std::string js_flags = cmd->GetSwitchValueASCII(switches::kJavaScriptFlags); - if (!js_flags.empty()) - v8::V8::SetFlagsFromString(js_flags.c_str(), js_flags.size()); - - gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode, - gin::IsolateHolder::kStableV8Extras, - gin::ArrayBufferAllocator::SharedInstance()); - return true; -} - -} // namespace atom diff --git a/atom/browser/javascript_environment.h b/atom/browser/javascript_environment.h deleted file mode 100644 index 1f4d2f4534782..0000000000000 --- a/atom/browser/javascript_environment.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_ -#define ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_ - -#include "base/macros.h" -#include "gin/public/isolate_holder.h" - -namespace atom { - -class JavascriptEnvironment { - public: - JavascriptEnvironment(); - - void OnMessageLoopCreated(); - void OnMessageLoopDestroying(); - - v8::Isolate* isolate() const { return isolate_; } - v8::Local context() const { - return v8::Local::New(isolate_, context_); - } - - private: - bool Initialize(); - - bool initialized_; - gin::IsolateHolder isolate_holder_; - v8::Isolate* isolate_; - v8::Isolate::Scope isolate_scope_; - v8::Locker locker_; - v8::HandleScope handle_scope_; - v8::UniquePersistent context_; - v8::Context::Scope context_scope_; - - DISALLOW_COPY_AND_ASSIGN(JavascriptEnvironment); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_JAVASCRIPT_ENVIRONMENT_H_ diff --git a/atom/browser/lib/bluetooth_chooser.cc b/atom/browser/lib/bluetooth_chooser.cc deleted file mode 100644 index 2ed21bd333fdf..0000000000000 --- a/atom/browser/lib/bluetooth_chooser.cc +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/lib/bluetooth_chooser.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "native_mate/dictionary.h" - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8( - v8::Isolate* isolate, const atom::BluetoothChooser::DeviceInfo& val) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("deviceName", val.device_name); - dict.Set("deviceId", val.device_id); - return mate::ConvertToV8(isolate, dict); - } -}; - -} // namespace mate - -namespace atom { - -namespace { - -const int kMaxScanRetries = 5; - -void OnDeviceChosen( - const content::BluetoothChooser::EventHandler& handler, - const std::string& device_id) { - if (device_id.empty()) { - handler.Run(content::BluetoothChooser::Event::CANCELLED, device_id); - } else { - handler.Run(content::BluetoothChooser::Event::SELECTED, device_id); - } -} - -} // namespace - -BluetoothChooser::BluetoothChooser( - api::WebContents* contents, - const EventHandler& event_handler) - : api_web_contents_(contents), - event_handler_(event_handler), - num_retries_(0) { -} - -BluetoothChooser::~BluetoothChooser() { -} - -void BluetoothChooser::SetAdapterPresence(AdapterPresence presence) { - switch (presence) { - case AdapterPresence::ABSENT: - case AdapterPresence::POWERED_OFF: - event_handler_.Run(Event::CANCELLED, ""); - break; - case AdapterPresence::POWERED_ON: - break; - } -} - -void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) { - switch (state) { - case DiscoveryState::FAILED_TO_START: - event_handler_.Run(Event::CANCELLED, ""); - break; - case DiscoveryState::IDLE: - if (device_list_.empty()) { - auto event = ++num_retries_ > kMaxScanRetries ? Event::CANCELLED - : Event::RESCAN; - event_handler_.Run(event, ""); - } else { - bool prevent_default = - api_web_contents_->Emit("select-bluetooth-device", - device_list_, - base::Bind(&OnDeviceChosen, - event_handler_)); - if (!prevent_default) { - auto device_id = device_list_[0].device_id; - event_handler_.Run(Event::SELECTED, device_id); - } - } - break; - case DiscoveryState::DISCOVERING: - break; - } -} - -void BluetoothChooser::AddDevice(const std::string& device_id, - const base::string16& device_name) { - DeviceInfo info = {device_id, device_name}; - device_list_.push_back(info); -} - -void BluetoothChooser::RemoveDevice(const std::string& device_id) { - for (auto it = device_list_.begin(); it != device_list_.end(); ++it) { - if (it->device_id == device_id) { - device_list_.erase(it); - return; - } - } -} - -} // namespace atom diff --git a/atom/browser/lib/bluetooth_chooser.h b/atom/browser/lib/bluetooth_chooser.h deleted file mode 100644 index 615dfcb8c6630..0000000000000 --- a/atom/browser/lib/bluetooth_chooser.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_LIB_BLUETOOTH_CHOOSER_H_ -#define ATOM_BROWSER_LIB_BLUETOOTH_CHOOSER_H_ - -#include -#include - -#include "atom/browser/api/atom_api_web_contents.h" -#include "content/public/browser/bluetooth_chooser.h" - -namespace atom { - -class BluetoothChooser : public content::BluetoothChooser { - public: - struct DeviceInfo { - std::string device_id; - base::string16 device_name; - }; - - explicit BluetoothChooser(api::WebContents* contents, - const EventHandler& handler); - ~BluetoothChooser() override; - - // content::BluetoothChooser: - void SetAdapterPresence(AdapterPresence presence) override; - void ShowDiscoveryState(DiscoveryState state) override; - void AddDevice(const std::string& device_id, - const base::string16& device_name) override; - void RemoveDevice(const std::string& device_id) override; - - private: - std::vector device_list_; - api::WebContents* api_web_contents_; - EventHandler event_handler_; - int num_retries_; - - DISALLOW_COPY_AND_ASSIGN(BluetoothChooser); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_LIB_BLUETOOTH_CHOOSER_H_ diff --git a/atom/browser/login_handler.cc b/atom/browser/login_handler.cc deleted file mode 100644 index 827154b0d0b43..0000000000000 --- a/atom/browser/login_handler.cc +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/login_handler.h" - -#include "atom/browser/browser.h" -#include "atom/common/native_mate_converters/net_converter.h" -#include "base/values.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/resource_dispatcher_host.h" -#include "content/public/browser/resource_request_info.h" -#include "content/public/browser/web_contents.h" -#include "net/base/auth.h" -#include "net/url_request/url_request.h" - -using content::BrowserThread; - -namespace atom { - -namespace { - -// Helper to remove the ref from an net::URLRequest to the LoginHandler. -// Should only be called from the IO thread, since it accesses an -// net::URLRequest. -void ResetLoginHandlerForRequest(net::URLRequest* request) { - content::ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request); -} - -} // namespace - -LoginHandler::LoginHandler(net::AuthChallengeInfo* auth_info, - net::URLRequest* request) - : handled_auth_(false), - auth_info_(auth_info), - request_(request), - render_process_host_id_(0), - render_frame_id_(0) { - content::ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderFrame( - &render_process_host_id_, &render_frame_id_); - - // Fill request details on IO thread. - std::unique_ptr request_details( - new base::DictionaryValue); - FillRequestDetails(request_details.get(), request_); - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&Browser::RequestLogin, - base::Unretained(Browser::Get()), - base::RetainedRef(make_scoped_refptr(this)), - base::Passed(&request_details))); -} - -LoginHandler::~LoginHandler() { -} - -content::WebContents* LoginHandler::GetWebContents() const { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( - render_process_host_id_, render_frame_id_); - return content::WebContents::FromRenderFrameHost(rfh); -} - -void LoginHandler::Login(const base::string16& username, - const base::string16& password) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (TestAndSetAuthHandled()) - return; - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&LoginHandler::DoLogin, this, username, password)); -} - -void LoginHandler::CancelAuth() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (TestAndSetAuthHandled()) - return; - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&LoginHandler::DoCancelAuth, this)); -} - -void LoginHandler::OnRequestCancelled() { - TestAndSetAuthHandled(); - request_ = nullptr; -} - -// Marks authentication as handled and returns the previous handled state. -bool LoginHandler::TestAndSetAuthHandled() { - base::AutoLock lock(handled_auth_lock_); - bool was_handled = handled_auth_; - handled_auth_ = true; - return was_handled; -} - -void LoginHandler::DoCancelAuth() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - if (request_) { - request_->CancelAuth(); - // Verify that CancelAuth doesn't destroy the request via our delegate. - DCHECK(request_ != nullptr); - ResetLoginHandlerForRequest(request_); - } -} - -void LoginHandler::DoLogin(const base::string16& username, - const base::string16& password) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - if (request_) { - request_->SetAuth(net::AuthCredentials(username, password)); - ResetLoginHandlerForRequest(request_); - } -} - -} // namespace atom diff --git a/atom/browser/login_handler.h b/atom/browser/login_handler.h deleted file mode 100644 index ba1371336cc1b..0000000000000 --- a/atom/browser/login_handler.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_LOGIN_HANDLER_H_ -#define ATOM_BROWSER_LOGIN_HANDLER_H_ - -#include "base/strings/string16.h" -#include "base/synchronization/lock.h" -#include "content/public/browser/resource_dispatcher_host_login_delegate.h" - -namespace content { -class WebContents; -} - -namespace net { -class AuthChallengeInfo; -class URLRequest; -} - -namespace atom { - -// Handles the HTTP basic auth, must be created on IO thread. -class LoginHandler : public content::ResourceDispatcherHostLoginDelegate { - public: - LoginHandler(net::AuthChallengeInfo* auth_info, net::URLRequest* request); - - // Returns the WebContents associated with the request, must be called on UI - // thread. - content::WebContents* GetWebContents() const; - - // The auth is cancelled, must be called on UI thread. - void CancelAuth(); - - // Login with |username| and |password|, must be called on UI thread. - void Login(const base::string16& username, const base::string16& password); - - const net::AuthChallengeInfo* auth_info() const { return auth_info_.get(); } - - protected: - ~LoginHandler() override; - - // content::ResourceDispatcherHostLoginDelegate: - void OnRequestCancelled() override; - - private: - // Must be called on IO thread. - void DoCancelAuth(); - void DoLogin(const base::string16& username, const base::string16& password); - - // Marks authentication as handled and returns the previous handled - // state. - bool TestAndSetAuthHandled(); - - // True if we've handled auth (Login or CancelAuth has been called). - bool handled_auth_; - mutable base::Lock handled_auth_lock_; - - // Who/where/what asked for the authentication. - scoped_refptr auth_info_; - - // The request that wants login data. - // This should only be accessed on the IO loop. - net::URLRequest* request_; - - // Cached from the net::URLRequest, in case it goes NULL on us. - int render_process_host_id_; - int render_frame_id_; - - DISALLOW_COPY_AND_ASSIGN(LoginHandler); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_LOGIN_HANDLER_H_ diff --git a/atom/browser/mac/atom_application.h b/atom/browser/mac/atom_application.h deleted file mode 100644 index 73baf9e7d9802..0000000000000 --- a/atom/browser/mac/atom_application.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#import "base/mac/scoped_sending_event.h" -#import "base/mac/scoped_nsobject.h" - -@interface AtomApplication : NSApplication { - @private - BOOL handlingSendEvent_; - base::scoped_nsobject currentActivity_; -} - -+ (AtomApplication*)sharedApplication; - -// CrAppProtocol: -- (BOOL)isHandlingSendEvent; - -// CrAppControlProtocol: -- (void)setHandlingSendEvent:(BOOL)handlingSendEvent; - -- (NSUserActivity*)getCurrentActivity; -- (void)setCurrentActivity:(NSString*)type - withUserInfo:(NSDictionary*)userInfo - withWebpageURL:(NSURL*)webpageURL; - -@end diff --git a/atom/browser/mac/atom_application.mm b/atom/browser/mac/atom_application.mm deleted file mode 100644 index 159852a59a831..0000000000000 --- a/atom/browser/mac/atom_application.mm +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#import "atom/browser/mac/atom_application.h" - -#include "atom/browser/browser.h" -#include "base/auto_reset.h" -#include "base/strings/sys_string_conversions.h" -#include "content/public/browser/browser_accessibility_state.h" - -@implementation AtomApplication - -+ (AtomApplication*)sharedApplication { - return (AtomApplication*)[super sharedApplication]; -} - -- (BOOL)isHandlingSendEvent { - return handlingSendEvent_; -} - -- (void)sendEvent:(NSEvent*)event { - base::AutoReset scoper(&handlingSendEvent_, YES); - [super sendEvent:event]; -} - -- (void)setHandlingSendEvent:(BOOL)handlingSendEvent { - handlingSendEvent_ = handlingSendEvent; -} - -- (void)setCurrentActivity:(NSString*)type - withUserInfo:(NSDictionary*)userInfo - withWebpageURL:(NSURL*)webpageURL { - currentActivity_ = base::scoped_nsobject( - [[NSUserActivity alloc] initWithActivityType:type]); - [currentActivity_ setUserInfo:userInfo]; - [currentActivity_ setWebpageURL:webpageURL]; - [currentActivity_ becomeCurrent]; -} - -- (NSUserActivity*)getCurrentActivity { - return currentActivity_.get(); -} - -- (void)awakeFromNib { - [[NSAppleEventManager sharedAppleEventManager] - setEventHandler:self - andSelector:@selector(handleURLEvent:withReplyEvent:) - forEventClass:kInternetEventClass - andEventID:kAEGetURL]; -} - -- (void)handleURLEvent:(NSAppleEventDescriptor*)event - withReplyEvent:(NSAppleEventDescriptor*)replyEvent { - NSString* url = [ - [event paramDescriptorForKeyword:keyDirectObject] stringValue]; - atom::Browser::Get()->OpenURL(base::SysNSStringToUTF8(url)); -} - -- (bool)voiceOverEnabled { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - [defaults addSuiteNamed:@"com.apple.universalaccess"]; - [defaults synchronize]; - - return [defaults boolForKey:@"voiceOverOnOffKey"]; -} - -- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { - // Undocumented attribute that VoiceOver happens to set while running. - // Chromium uses this too, even though it's not exactly right. - if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) { - bool enableAccessibility = ([self voiceOverEnabled] && [value boolValue]); - [self updateAccessibilityEnabled:enableAccessibility]; - } - return [super accessibilitySetValue:value forAttribute:attribute]; -} - -- (void)updateAccessibilityEnabled:(BOOL)enabled { - auto ax_state = content::BrowserAccessibilityState::GetInstance(); - - if (enabled) { - ax_state->OnScreenReaderDetected(); - } else { - ax_state->DisableAccessibility(); - } - - atom::Browser::Get()->OnAccessibilitySupportChanged(); -} - -@end diff --git a/atom/browser/mac/atom_application_delegate.h b/atom/browser/mac/atom_application_delegate.h deleted file mode 100644 index 777475213ecf3..0000000000000 --- a/atom/browser/mac/atom_application_delegate.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#import - -#import "atom/browser/ui/cocoa/atom_menu_controller.h" - -@interface AtomApplicationDelegate : NSObject { - @private - base::scoped_nsobject menu_controller_; -} - -// Sets the menu that will be returned in "applicationDockMenu:". -- (void)setApplicationDockMenu:(atom::AtomMenuModel*)model; - -@end diff --git a/atom/browser/mac/atom_application_delegate.mm b/atom/browser/mac/atom_application_delegate.mm deleted file mode 100644 index e77bd125201ba..0000000000000 --- a/atom/browser/mac/atom_application_delegate.mm +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#import "atom/browser/mac/atom_application_delegate.h" - -#import "atom/browser/mac/atom_application.h" -#include "atom/browser/browser.h" -#include "atom/browser/mac/dict_util.h" -#include "base/strings/sys_string_conversions.h" -#include "base/values.h" - -@implementation AtomApplicationDelegate - -- (void)setApplicationDockMenu:(atom::AtomMenuModel*)model { - menu_controller_.reset([[AtomMenuController alloc] initWithModel:model - useDefaultAccelerator:NO]); -} - -- (void)applicationWillFinishLaunching:(NSNotification*)notify { - // Don't add the "Enter Full Screen" menu item automatically. - [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"]; - - atom::Browser::Get()->WillFinishLaunching(); -} - -- (void)applicationDidFinishLaunching:(NSNotification*)notify { - atom::Browser::Get()->DidFinishLaunching(); -} - -- (NSMenu*)applicationDockMenu:(NSApplication*)sender { - if (menu_controller_) - return [menu_controller_ menu]; - else - return nil; -} - -- (BOOL)application:(NSApplication*)sender - openFile:(NSString*)filename { - std::string filename_str(base::SysNSStringToUTF8(filename)); - return atom::Browser::Get()->OpenFile(filename_str) ? YES : NO; -} - -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender { - atom::Browser* browser = atom::Browser::Get(); - if (browser->is_quiting()) { - return NSTerminateNow; - } else { - // System started termination. - atom::Browser::Get()->Quit(); - return NSTerminateCancel; - } -} - -- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApplication - hasVisibleWindows:(BOOL)flag { - atom::Browser* browser = atom::Browser::Get(); - browser->Activate(static_cast(flag)); - return flag; -} - -- (BOOL)application:(NSApplication*)sender -continueUserActivity:(NSUserActivity*)userActivity - restorationHandler:(void (^)(NSArray*restorableObjects))restorationHandler { - std::string activity_type(base::SysNSStringToUTF8(userActivity.activityType)); - std::unique_ptr user_info = - atom::NSDictionaryToDictionaryValue(userActivity.userInfo); - if (!user_info) - return NO; - - atom::Browser* browser = atom::Browser::Get(); - return browser->ContinueUserActivity(activity_type, *user_info) ? YES : NO; -} - -@end diff --git a/atom/browser/mac/dict_util.h b/atom/browser/mac/dict_util.h deleted file mode 100644 index 74a2b7234c045..0000000000000 --- a/atom/browser/mac/dict_util.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_MAC_DICT_UTIL_H_ -#define ATOM_BROWSER_MAC_DICT_UTIL_H_ - -#include - -#import - -namespace base { -class ListValue; -class DictionaryValue; -} - -namespace atom { - -NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value); - -std::unique_ptr NSDictionaryToDictionaryValue( - NSDictionary* dict); - -std::unique_ptr NSArrayToListValue(NSArray* arr); - -} // namespace atom - -#endif // ATOM_BROWSER_MAC_DICT_UTIL_H_ diff --git a/atom/browser/mac/dict_util.mm b/atom/browser/mac/dict_util.mm deleted file mode 100644 index 8692f001f6a89..0000000000000 --- a/atom/browser/mac/dict_util.mm +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/mac/dict_util.h" - -#include "base/json/json_writer.h" -#include "base/strings/sys_string_conversions.h" -#include "base/values.h" - -namespace atom { - -std::unique_ptr NSArrayToListValue(NSArray* arr) { - if (!arr) - return nullptr; - - std::unique_ptr result(new base::ListValue); - for (id value in arr) { - if ([value isKindOfClass:[NSString class]]) { - result->AppendString(base::SysNSStringToUTF8(value)); - } else if ([value isKindOfClass:[NSNumber class]]) { - const char* objc_type = [value objCType]; - if (strcmp(objc_type, @encode(BOOL)) == 0 || - strcmp(objc_type, @encode(char)) == 0) - result->AppendBoolean([value boolValue]); - else if (strcmp(objc_type, @encode(double)) == 0 || - strcmp(objc_type, @encode(float)) == 0) - result->AppendDouble([value doubleValue]); - else - result->AppendInteger([value intValue]); - } else if ([value isKindOfClass:[NSArray class]]) { - std::unique_ptr sub_arr = NSArrayToListValue(value); - if (sub_arr) - result->Append(std::move(sub_arr)); - else - result->Append(base::Value::CreateNullValue()); - } else if ([value isKindOfClass:[NSDictionary class]]) { - std::unique_ptr sub_dict = - NSDictionaryToDictionaryValue(value); - if (sub_dict) - result->Append(std::move(sub_dict)); - else - result->Append(base::Value::CreateNullValue()); - } else { - result->AppendString(base::SysNSStringToUTF8([value description])); - } - } - - return result; -} - -NSDictionary* DictionaryValueToNSDictionary(const base::DictionaryValue& value) { - std::string json; - if (!base::JSONWriter::Write(value, &json)) - return nil; - NSData* jsonData = [NSData dataWithBytes:json.c_str() length:json.length()]; - id obj = [NSJSONSerialization JSONObjectWithData:jsonData - options:0 - error:nil]; - if (![obj isKindOfClass:[NSDictionary class]]) - return nil; - return obj; -} - -std::unique_ptr NSDictionaryToDictionaryValue( - NSDictionary* dict) { - if (!dict) - return nullptr; - - std::unique_ptr result(new base::DictionaryValue); - for (id key in dict) { - std::string str_key = base::SysNSStringToUTF8( - [key isKindOfClass:[NSString class]] ? key : [key description]); - - id value = [dict objectForKey:key]; - if ([value isKindOfClass:[NSString class]]) { - result->SetStringWithoutPathExpansion( - str_key, base::SysNSStringToUTF8(value)); - } else if ([value isKindOfClass:[NSNumber class]]) { - const char* objc_type = [value objCType]; - if (strcmp(objc_type, @encode(BOOL)) == 0 || - strcmp(objc_type, @encode(char)) == 0) - result->SetBooleanWithoutPathExpansion(str_key, [value boolValue]); - else if (strcmp(objc_type, @encode(double)) == 0 || - strcmp(objc_type, @encode(float)) == 0) - result->SetDoubleWithoutPathExpansion(str_key, [value doubleValue]); - else - result->SetIntegerWithoutPathExpansion(str_key, [value intValue]); - } else if ([value isKindOfClass:[NSArray class]]) { - std::unique_ptr sub_arr = NSArrayToListValue(value); - if (sub_arr) - result->SetWithoutPathExpansion(str_key, std::move(sub_arr)); - else - result->SetWithoutPathExpansion(str_key, - base::Value::CreateNullValue()); - } else if ([value isKindOfClass:[NSDictionary class]]) { - std::unique_ptr sub_dict = - NSDictionaryToDictionaryValue(value); - if (sub_dict) - result->SetWithoutPathExpansion(str_key, std::move(sub_dict)); - else - result->SetWithoutPathExpansion(str_key, - base::Value::CreateNullValue()); - } else { - result->SetStringWithoutPathExpansion( - str_key, - base::SysNSStringToUTF8([value description])); - } - } - - return result; -} - -} // namespace atom diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc deleted file mode 100644 index 9008b6b2240d1..0000000000000 --- a/atom/browser/native_window.cc +++ /dev/null @@ -1,634 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/native_window.h" - -#include -#include -#include - -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/atom_browser_main_parts.h" -#include "atom/browser/browser.h" -#include "atom/browser/unresponsive_suppressor.h" -#include "atom/browser/window_list.h" -#include "atom/common/api/api_messages.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/options_switches.h" -#include "base/files/file_util.h" -#include "base/json/json_writer.h" -#include "components/prefs/pref_service.h" -#include "base/message_loop/message_loop.h" -#include "base/strings/utf_string_conversions.h" -#include "brightray/browser/inspectable_web_contents.h" -#include "brightray/browser/inspectable_web_contents_view.h" -#include "content/browser/renderer_host/render_widget_host_impl.h" -#include "content/public/browser/navigation_entry.h" -#include "content/public/browser/plugin_service.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host.h" -#include "content/public/browser/render_widget_host_view.h" -#include "content/public/common/content_switches.h" -#include "ipc/ipc_message_macros.h" -#include "native_mate/dictionary.h" -#include "ui/gfx/codec/png_codec.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/geometry/size_conversions.h" -#include "ui/gl/gpu_switching_manager.h" - -#if defined(OS_LINUX) || defined(OS_WIN) -#include "content/public/common/renderer_preferences.h" -#include "ui/gfx/font_render_params.h" -#endif - -DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay); - -namespace atom { - -NativeWindow::NativeWindow( - brightray::InspectableWebContents* inspectable_web_contents, - const mate::Dictionary& options, - NativeWindow* parent) - : content::WebContentsObserver(inspectable_web_contents->GetWebContents()), - has_frame_(true), - transparent_(false), - enable_larger_than_screen_(false), - is_closed_(false), - sheet_offset_x_(0.0), - sheet_offset_y_(0.0), - aspect_ratio_(0.0), - parent_(parent), - is_modal_(false), - inspectable_web_contents_(inspectable_web_contents), - weak_factory_(this) { - options.Get(options::kFrame, &has_frame_); - options.Get(options::kTransparent, &transparent_); - options.Get(options::kEnableLargerThanScreen, &enable_larger_than_screen_); - - if (parent) - options.Get("modal", &is_modal_); - -#if defined(OS_LINUX) || defined(OS_WIN) - auto* prefs = web_contents()->GetMutableRendererPrefs(); - - // Update font settings. - CR_DEFINE_STATIC_LOCAL(const gfx::FontRenderParams, params, - (gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr))); - prefs->should_antialias_text = params.antialiasing; - prefs->use_subpixel_positioning = params.subpixel_positioning; - prefs->hinting = params.hinting; - prefs->use_autohinter = params.autohinter; - prefs->use_bitmaps = params.use_bitmaps; - prefs->subpixel_rendering = params.subpixel_rendering; -#endif - - // Tell the content module to initialize renderer widget with transparent - // mode. - ui::GpuSwitchingManager::SetTransparent(transparent_); - - WindowList::AddWindow(this); -} - -NativeWindow::~NativeWindow() { - // It's possible that the windows gets destroyed before it's closed, in that - // case we need to ensure the OnWindowClosed message is still notified. - NotifyWindowClosed(); -} - -// static -NativeWindow* NativeWindow::FromWebContents( - content::WebContents* web_contents) { - WindowList& window_list = *WindowList::GetInstance(); - for (NativeWindow* window : window_list) { - if (window->web_contents() == web_contents) - return window; - } - return nullptr; -} - -void NativeWindow::InitFromOptions(const mate::Dictionary& options) { - // Setup window from options. - int x = -1, y = -1; - bool center; - if (options.Get(options::kX, &x) && options.Get(options::kY, &y)) { - SetPosition(gfx::Point(x, y)); - } else if (options.Get(options::kCenter, ¢er) && center) { - Center(); - } - // On Linux and Window we may already have maximum size defined. - extensions::SizeConstraints size_constraints(GetContentSizeConstraints()); - int min_height = 0, min_width = 0; - if (options.Get(options::kMinHeight, &min_height) | - options.Get(options::kMinWidth, &min_width)) { - size_constraints.set_minimum_size(gfx::Size(min_width, min_height)); - } - int max_height = INT_MAX, max_width = INT_MAX; - if (options.Get(options::kMaxHeight, &max_height) | - options.Get(options::kMaxWidth, &max_width)) { - size_constraints.set_maximum_size(gfx::Size(max_width, max_height)); - } - bool use_content_size = false; - options.Get(options::kUseContentSize, &use_content_size); - if (use_content_size) { - SetContentSizeConstraints(size_constraints); - } else { - SetSizeConstraints(size_constraints); - } -#if defined(USE_X11) - bool resizable; - if (options.Get(options::kResizable, &resizable)) { - SetResizable(resizable); - } -#endif -#if defined(OS_WIN) || defined(USE_X11) - bool closable; - if (options.Get(options::kClosable, &closable)) { - SetClosable(closable); - } -#endif - bool movable; - if (options.Get(options::kMovable, &movable)) { - SetMovable(movable); - } - bool has_shadow; - if (options.Get(options::kHasShadow, &has_shadow)) { - SetHasShadow(has_shadow); - } - bool top; - if (options.Get(options::kAlwaysOnTop, &top) && top) { - SetAlwaysOnTop(true); - } - bool fullscreenable = true; - bool fullscreen = false; - if (options.Get(options::kFullscreen, &fullscreen) && !fullscreen) { - // Disable fullscreen button if 'fullscreen' is specified to false. - #if defined(OS_MACOSX) - fullscreenable = false; - #endif - } - // Overriden by 'fullscreenable'. - options.Get(options::kFullScreenable, &fullscreenable); - SetFullScreenable(fullscreenable); - if (fullscreen) { - SetFullScreen(true); - } - bool skip; - if (options.Get(options::kSkipTaskbar, &skip)) { - SetSkipTaskbar(skip); - } - bool kiosk; - if (options.Get(options::kKiosk, &kiosk) && kiosk) { - SetKiosk(kiosk); - } - std::string color; - if (options.Get(options::kBackgroundColor, &color)) { - SetBackgroundColor(color); - } else if (!transparent()) { - // For normal window, use white as default background. - SetBackgroundColor("#FFFF"); - } - std::string title(Browser::Get()->GetName()); - options.Get(options::kTitle, &title); - SetTitle(title); - - // Then show it. - bool show = true; - options.Get(options::kShow, &show); - if (show) - Show(); -} - -void NativeWindow::SetSize(const gfx::Size& size, bool animate) { - SetBounds(gfx::Rect(GetPosition(), size), animate); -} - -gfx::Size NativeWindow::GetSize() { - return GetBounds().size(); -} - -void NativeWindow::SetPosition(const gfx::Point& position, bool animate) { - SetBounds(gfx::Rect(position, GetSize()), animate); -} - -gfx::Point NativeWindow::GetPosition() { - return GetBounds().origin(); -} - -void NativeWindow::SetContentSize(const gfx::Size& size, bool animate) { - SetSize(ContentBoundsToWindowBounds(gfx::Rect(size)).size(), animate); -} - -gfx::Size NativeWindow::GetContentSize() { - return GetContentBounds().size(); -} - -void NativeWindow::SetContentBounds(const gfx::Rect& bounds, bool animate) { - SetBounds(ContentBoundsToWindowBounds(bounds), animate); -} - -gfx::Rect NativeWindow::GetContentBounds() { - return WindowBoundsToContentBounds(GetBounds()); -} - -void NativeWindow::SetSizeConstraints( - const extensions::SizeConstraints& window_constraints) { - extensions::SizeConstraints content_constraints(GetContentSizeConstraints()); - if (window_constraints.HasMaximumSize()) { - gfx::Rect max_bounds = WindowBoundsToContentBounds( - gfx::Rect(window_constraints.GetMaximumSize())); - content_constraints.set_maximum_size(max_bounds.size()); - } - if (window_constraints.HasMinimumSize()) { - gfx::Rect min_bounds = WindowBoundsToContentBounds( - gfx::Rect(window_constraints.GetMinimumSize())); - content_constraints.set_minimum_size(min_bounds.size()); - } - SetContentSizeConstraints(content_constraints); -} - -extensions::SizeConstraints NativeWindow::GetSizeConstraints() { - extensions::SizeConstraints content_constraints = GetContentSizeConstraints(); - extensions::SizeConstraints window_constraints; - if (content_constraints.HasMaximumSize()) { - gfx::Rect max_bounds = ContentBoundsToWindowBounds( - gfx::Rect(content_constraints.GetMaximumSize())); - window_constraints.set_maximum_size(max_bounds.size()); - } - if (content_constraints.HasMinimumSize()) { - gfx::Rect min_bounds = ContentBoundsToWindowBounds( - gfx::Rect(content_constraints.GetMinimumSize())); - window_constraints.set_minimum_size(min_bounds.size()); - } - return window_constraints; -} - -void NativeWindow::SetContentSizeConstraints( - const extensions::SizeConstraints& size_constraints) { - size_constraints_ = size_constraints; -} - -extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() { - return size_constraints_; -} - -void NativeWindow::SetMinimumSize(const gfx::Size& size) { - extensions::SizeConstraints size_constraints; - size_constraints.set_minimum_size(size); - SetSizeConstraints(size_constraints); -} - -gfx::Size NativeWindow::GetMinimumSize() { - return GetSizeConstraints().GetMinimumSize(); -} - -void NativeWindow::SetMaximumSize(const gfx::Size& size) { - extensions::SizeConstraints size_constraints; - size_constraints.set_maximum_size(size); - SetSizeConstraints(size_constraints); -} - -gfx::Size NativeWindow::GetMaximumSize() { - return GetSizeConstraints().GetMaximumSize(); -} - -void NativeWindow::SetSheetOffset(const double offsetX, const double offsetY) { - sheet_offset_x_ = offsetX; - sheet_offset_y_ = offsetY; -} - -double NativeWindow::GetSheetOffsetX() { - return sheet_offset_x_; -} - -double NativeWindow::GetSheetOffsetY() { - return sheet_offset_y_; -} - -void NativeWindow::SetRepresentedFilename(const std::string& filename) { -} - -std::string NativeWindow::GetRepresentedFilename() { - return ""; -} - -void NativeWindow::SetDocumentEdited(bool edited) { -} - -bool NativeWindow::IsDocumentEdited() { - return false; -} - -void NativeWindow::SetFocusable(bool focusable) { -} - -void NativeWindow::SetMenu(AtomMenuModel* menu) { -} - -void NativeWindow::SetParentWindow(NativeWindow* parent) { - parent_ = parent; -} - -void NativeWindow::FocusOnWebView() { - web_contents()->GetRenderViewHost()->GetWidget()->Focus(); -} - -void NativeWindow::BlurWebView() { - web_contents()->GetRenderViewHost()->GetWidget()->Blur(); -} - -bool NativeWindow::IsWebViewFocused() { - auto host_view = web_contents()->GetRenderViewHost()->GetWidget()->GetView(); - return host_view && host_view->HasFocus(); -} - -void NativeWindow::SetAutoHideMenuBar(bool auto_hide) { -} - -bool NativeWindow::IsMenuBarAutoHide() { - return false; -} - -void NativeWindow::SetMenuBarVisibility(bool visible) { -} - -bool NativeWindow::IsMenuBarVisible() { - return true; -} - -double NativeWindow::GetAspectRatio() { - return aspect_ratio_; -} - -gfx::Size NativeWindow::GetAspectRatioExtraSize() { - return aspect_ratio_extraSize_; -} - -void NativeWindow::SetAspectRatio(double aspect_ratio, - const gfx::Size& extra_size) { - aspect_ratio_ = aspect_ratio; - aspect_ratio_extraSize_ = extra_size; -} - -void NativeWindow::RequestToClosePage() { - bool prevent_default = false; - FOR_EACH_OBSERVER(NativeWindowObserver, - observers_, - WillCloseWindow(&prevent_default)); - if (prevent_default) { - WindowList::WindowCloseCancelled(this); - return; - } - - // Assume the window is not responding if it doesn't cancel the close and is - // not closed in 5s, in this way we can quickly show the unresponsive - // dialog when the window is busy executing some script withouth waiting for - // the unresponsive timeout. - if (window_unresposive_closure_.IsCancelled()) - ScheduleUnresponsiveEvent(5000); - - if (web_contents()->NeedToFireBeforeUnload()) - web_contents()->DispatchBeforeUnload(); - else - web_contents()->Close(); -} - -void NativeWindow::CloseContents(content::WebContents* source) { - if (!inspectable_web_contents_) - return; - - inspectable_web_contents_->GetView()->SetDelegate(nullptr); - inspectable_web_contents_ = nullptr; - Observe(nullptr); - - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - WillDestoryNativeObject()); - - // When the web contents is gone, close the window immediately, but the - // memory will not be freed until you call delete. - // In this way, it would be safe to manage windows via smart pointers. If you - // want to free memory when the window is closed, you can do deleting by - // overriding the OnWindowClosed method in the observer. - CloseImmediately(); - - // Do not sent "unresponsive" event after window is closed. - window_unresposive_closure_.Cancel(); -} - -void NativeWindow::RendererUnresponsive(content::WebContents* source) { - // Schedule the unresponsive shortly later, since we may receive the - // responsive event soon. This could happen after the whole application had - // blocked for a while. - // Also notice that when closing this event would be ignored because we have - // explicitly started a close timeout counter. This is on purpose because we - // don't want the unresponsive event to be sent too early when user is closing - // the window. - ScheduleUnresponsiveEvent(50); -} - -void NativeWindow::RendererResponsive(content::WebContents* source) { - window_unresposive_closure_.Cancel(); - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnRendererResponsive()); -} - -void NativeWindow::NotifyWindowClosed() { - if (is_closed_) - return; - - WindowList::RemoveWindow(this); - - is_closed_ = true; - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowClosed()); -} - -void NativeWindow::NotifyWindowBlur() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowBlur()); -} - -void NativeWindow::NotifyWindowFocus() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowFocus()); -} - -void NativeWindow::NotifyWindowShow() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowShow()); -} - -void NativeWindow::NotifyWindowHide() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowHide()); -} - -void NativeWindow::NotifyWindowMaximize() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowMaximize()); -} - -void NativeWindow::NotifyWindowUnmaximize() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowUnmaximize()); -} - -void NativeWindow::NotifyWindowMinimize() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowMinimize()); -} - -void NativeWindow::NotifyWindowRestore() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowRestore()); -} - -void NativeWindow::NotifyWindowResize() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowResize()); -} - -void NativeWindow::NotifyWindowMove() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowMove()); -} - -void NativeWindow::NotifyWindowMoved() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowMoved()); -} - -void NativeWindow::NotifyWindowEnterFullScreen() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - OnWindowEnterFullScreen()); -} - -void NativeWindow::NotifyWindowScrollTouchBegin() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - OnWindowScrollTouchBegin()); -} - -void NativeWindow::NotifyWindowScrollTouchEnd() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - OnWindowScrollTouchEnd()); -} - -void NativeWindow::NotifyWindowSwipe(const std::string& direction) { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - OnWindowSwipe(direction)); -} - -void NativeWindow::NotifyWindowLeaveFullScreen() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - OnWindowLeaveFullScreen()); -} - -void NativeWindow::NotifyWindowEnterHtmlFullScreen() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - OnWindowEnterHtmlFullScreen()); -} - -void NativeWindow::NotifyWindowLeaveHtmlFullScreen() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - OnWindowLeaveHtmlFullScreen()); -} - -void NativeWindow::NotifyWindowExecuteWindowsCommand( - const std::string& command) { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - OnExecuteWindowsCommand(command)); -} - -#if defined(OS_WIN) -void NativeWindow::NotifyWindowMessage( - UINT message, WPARAM w_param, LPARAM l_param) { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, - OnWindowMessage(message, w_param, l_param)); -} -#endif - -std::unique_ptr NativeWindow::DraggableRegionsToSkRegion( - const std::vector& regions) { - std::unique_ptr sk_region(new SkRegion); - for (const DraggableRegion& region : regions) { - sk_region->op( - region.bounds.x(), - region.bounds.y(), - region.bounds.right(), - region.bounds.bottom(), - region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op); - } - return sk_region; -} - -void NativeWindow::RenderViewCreated( - content::RenderViewHost* render_view_host) { - if (!transparent_) - return; - - content::RenderWidgetHostImpl* impl = content::RenderWidgetHostImpl::FromID( - render_view_host->GetProcess()->GetID(), - render_view_host->GetRoutingID()); - if (impl) - impl->SetBackgroundOpaque(false); -} - -void NativeWindow::BeforeUnloadDialogCancelled() { - WindowList::WindowCloseCancelled(this); - - // Cancel unresponsive event when window close is cancelled. - window_unresposive_closure_.Cancel(); -} - -void NativeWindow::DidFirstVisuallyNonEmptyPaint() { - if (IsVisible()) - return; - - // When there is a non-empty first paint, resize the RenderWidget to force - // Chromium to draw. - const auto view = web_contents()->GetRenderWidgetHostView(); - view->Show(); - view->SetSize(GetContentSize()); - - // Emit the ReadyToShow event in next tick in case of pending drawing work. - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&NativeWindow::NotifyReadyToShow, GetWeakPtr())); -} - -bool NativeWindow::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(NativeWindow, message) - IPC_MESSAGE_HANDLER(AtomViewHostMsg_UpdateDraggableRegions, - UpdateDraggableRegions) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - return handled; -} - -void NativeWindow::UpdateDraggableRegions( - const std::vector& regions) { - // Draggable region is not supported for non-frameless window. - if (has_frame_) - return; - draggable_region_ = DraggableRegionsToSkRegion(regions); -} - -void NativeWindow::ScheduleUnresponsiveEvent(int ms) { - if (!window_unresposive_closure_.IsCancelled()) - return; - - window_unresposive_closure_.Reset( - base::Bind(&NativeWindow::NotifyWindowUnresponsive, - weak_factory_.GetWeakPtr())); - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - window_unresposive_closure_.callback(), - base::TimeDelta::FromMilliseconds(ms)); -} - -void NativeWindow::NotifyWindowUnresponsive() { - window_unresposive_closure_.Cancel(); - - if (!is_closed_ && !IsUnresponsiveEventSuppressed() && IsEnabled()) - FOR_EACH_OBSERVER(NativeWindowObserver, - observers_, - OnRendererUnresponsive()); -} - -void NativeWindow::NotifyReadyToShow() { - FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnReadyToShow()); -} - -} // namespace atom diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h deleted file mode 100644 index 352297223f2e2..0000000000000 --- a/atom/browser/native_window.h +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NATIVE_WINDOW_H_ -#define ATOM_BROWSER_NATIVE_WINDOW_H_ - -#include -#include -#include -#include - -#include "atom/browser/native_window_observer.h" -#include "atom/browser/ui/accelerator_util.h" -#include "atom/browser/ui/atom_menu_model.h" -#include "base/cancelable_callback.h" -#include "base/memory/weak_ptr.h" -#include "base/observer_list.h" -#include "base/supports_user_data.h" -#include "content/public/browser/readback_types.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_user_data.h" -#include "extensions/browser/app_window/size_constraints.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/image/image_skia.h" - -class SkRegion; - -namespace brightray { -class InspectableWebContents; -} - -namespace content { -struct NativeWebKeyboardEvent; -} - -namespace gfx { -class Point; -class Rect; -class Size; -} - -namespace mate { -class Dictionary; -} - -namespace atom { - -struct DraggableRegion; - -class NativeWindow : public base::SupportsUserData, - public content::WebContentsObserver { - public: - ~NativeWindow() override; - - // Create window with existing WebContents, the caller is responsible for - // managing the window's live. - static NativeWindow* Create( - brightray::InspectableWebContents* inspectable_web_contents, - const mate::Dictionary& options, - NativeWindow* parent = nullptr); - - // Find a window from its WebContents - static NativeWindow* FromWebContents(content::WebContents* web_contents); - - void InitFromOptions(const mate::Dictionary& options); - - virtual void Close() = 0; - virtual void CloseImmediately() = 0; - virtual bool IsClosed() const { return is_closed_; } - virtual void Focus(bool focus) = 0; - virtual bool IsFocused() = 0; - virtual void Show() = 0; - virtual void ShowInactive() = 0; - virtual void Hide() = 0; - virtual bool IsVisible() = 0; - virtual bool IsEnabled() = 0; - virtual void Maximize() = 0; - virtual void Unmaximize() = 0; - virtual bool IsMaximized() = 0; - virtual void Minimize() = 0; - virtual void Restore() = 0; - virtual bool IsMinimized() = 0; - virtual void SetFullScreen(bool fullscreen) = 0; - virtual bool IsFullscreen() const = 0; - virtual void SetBounds(const gfx::Rect& bounds, bool animate = false) = 0; - virtual gfx::Rect GetBounds() = 0; - virtual void SetSize(const gfx::Size& size, bool animate = false); - virtual gfx::Size GetSize(); - virtual void SetPosition(const gfx::Point& position, bool animate = false); - virtual gfx::Point GetPosition(); - virtual void SetContentSize(const gfx::Size& size, bool animate = false); - virtual gfx::Size GetContentSize(); - virtual void SetContentBounds(const gfx::Rect& bounds, bool animate = false); - virtual gfx::Rect GetContentBounds(); - virtual void SetSizeConstraints( - const extensions::SizeConstraints& size_constraints); - virtual extensions::SizeConstraints GetSizeConstraints(); - virtual void SetContentSizeConstraints( - const extensions::SizeConstraints& size_constraints); - virtual extensions::SizeConstraints GetContentSizeConstraints(); - virtual void SetMinimumSize(const gfx::Size& size); - virtual gfx::Size GetMinimumSize(); - virtual void SetMaximumSize(const gfx::Size& size); - virtual gfx::Size GetMaximumSize(); - virtual void SetSheetOffset(const double offsetX, const double offsetY); - virtual double GetSheetOffsetX(); - virtual double GetSheetOffsetY(); - virtual void SetResizable(bool resizable) = 0; - virtual bool IsResizable() = 0; - virtual void SetMovable(bool movable) = 0; - virtual bool IsMovable() = 0; - virtual void SetMinimizable(bool minimizable) = 0; - virtual bool IsMinimizable() = 0; - virtual void SetMaximizable(bool maximizable) = 0; - virtual bool IsMaximizable() = 0; - virtual void SetFullScreenable(bool fullscreenable) = 0; - virtual bool IsFullScreenable() = 0; - virtual void SetClosable(bool closable) = 0; - virtual bool IsClosable() = 0; - virtual void SetAlwaysOnTop(bool top) = 0; - virtual bool IsAlwaysOnTop() = 0; - virtual void Center() = 0; - virtual void SetTitle(const std::string& title) = 0; - virtual std::string GetTitle() = 0; - virtual void FlashFrame(bool flash) = 0; - virtual void SetSkipTaskbar(bool skip) = 0; - virtual void SetKiosk(bool kiosk) = 0; - virtual bool IsKiosk() = 0; - virtual void SetBackgroundColor(const std::string& color_name) = 0; - virtual void SetHasShadow(bool has_shadow) = 0; - virtual bool HasShadow() = 0; - virtual void SetRepresentedFilename(const std::string& filename); - virtual std::string GetRepresentedFilename(); - virtual void SetDocumentEdited(bool edited); - virtual bool IsDocumentEdited(); - virtual void SetIgnoreMouseEvents(bool ignore) = 0; - virtual void SetContentProtection(bool enable) = 0; - virtual void SetFocusable(bool focusable); - virtual void SetMenu(AtomMenuModel* menu); - virtual void SetParentWindow(NativeWindow* parent); - virtual gfx::NativeWindow GetNativeWindow() = 0; - virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0; - - // Taskbar/Dock APIs. - virtual void SetProgressBar(double progress) = 0; - virtual void SetOverlayIcon(const gfx::Image& overlay, - const std::string& description) = 0; - - // Workspace APIs. - virtual void SetVisibleOnAllWorkspaces(bool visible) = 0; - virtual bool IsVisibleOnAllWorkspaces() = 0; - - // Webview APIs. - virtual void FocusOnWebView(); - virtual void BlurWebView(); - virtual bool IsWebViewFocused(); - - // Toggle the menu bar. - virtual void SetAutoHideMenuBar(bool auto_hide); - virtual bool IsMenuBarAutoHide(); - virtual void SetMenuBarVisibility(bool visible); - virtual bool IsMenuBarVisible(); - - // Set the aspect ratio when resizing window. - double GetAspectRatio(); - gfx::Size GetAspectRatioExtraSize(); - virtual void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size); - - base::WeakPtr GetWeakPtr() { - return weak_factory_.GetWeakPtr(); - } - - // Requests the WebContents to close, can be cancelled by the page. - virtual void RequestToClosePage(); - - // Methods called by the WebContents. - virtual void CloseContents(content::WebContents* source); - virtual void RendererUnresponsive(content::WebContents* source); - virtual void RendererResponsive(content::WebContents* source); - virtual void HandleKeyboardEvent( - content::WebContents*, - const content::NativeWebKeyboardEvent& event) {} - - // Public API used by platform-dependent delegates and observers to send UI - // related notifications. - void NotifyWindowClosed(); - void NotifyWindowBlur(); - void NotifyWindowFocus(); - void NotifyWindowShow(); - void NotifyWindowHide(); - void NotifyWindowMaximize(); - void NotifyWindowUnmaximize(); - void NotifyWindowMinimize(); - void NotifyWindowRestore(); - void NotifyWindowMove(); - void NotifyWindowResize(); - void NotifyWindowMoved(); - void NotifyWindowScrollTouchBegin(); - void NotifyWindowScrollTouchEnd(); - void NotifyWindowSwipe(const std::string& direction); - void NotifyWindowEnterFullScreen(); - void NotifyWindowLeaveFullScreen(); - void NotifyWindowEnterHtmlFullScreen(); - void NotifyWindowLeaveHtmlFullScreen(); - void NotifyWindowExecuteWindowsCommand(const std::string& command); - - #if defined(OS_WIN) - void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param); - #endif - - void AddObserver(NativeWindowObserver* obs) { - observers_.AddObserver(obs); - } - void RemoveObserver(NativeWindowObserver* obs) { - observers_.RemoveObserver(obs); - } - - brightray::InspectableWebContents* inspectable_web_contents() const { - return inspectable_web_contents_; - } - - bool has_frame() const { return has_frame_; } - void set_has_frame(bool has_frame) { has_frame_ = has_frame; } - - bool transparent() const { return transparent_; } - SkRegion* draggable_region() const { return draggable_region_.get(); } - bool enable_larger_than_screen() const { return enable_larger_than_screen_; } - - NativeWindow* parent() const { return parent_; } - bool is_modal() const { return is_modal_; } - - protected: - NativeWindow(brightray::InspectableWebContents* inspectable_web_contents, - const mate::Dictionary& options, - NativeWindow* parent); - - // Convert draggable regions in raw format to SkRegion format. Caller is - // responsible for deleting the returned SkRegion instance. - std::unique_ptr DraggableRegionsToSkRegion( - const std::vector& regions); - - // Converts between content bounds and window bounds. - virtual gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) = 0; - virtual gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) = 0; - - // Called when the window needs to update its draggable region. - virtual void UpdateDraggableRegions( - const std::vector& regions); - - // content::WebContentsObserver: - void RenderViewCreated(content::RenderViewHost* render_view_host) override; - void BeforeUnloadDialogCancelled() override; - void DidFirstVisuallyNonEmptyPaint() override; - bool OnMessageReceived(const IPC::Message& message) override; - - private: - // Schedule a notification unresponsive event. - void ScheduleUnresponsiveEvent(int ms); - - // Dispatch unresponsive event to observers. - void NotifyWindowUnresponsive(); - - // Dispatch ReadyToShow event to observers. - void NotifyReadyToShow(); - - // Whether window has standard frame. - bool has_frame_; - - // Whether window is transparent. - bool transparent_; - - // For custom drag, the whole window is non-draggable and the draggable region - // has to been explicitly provided. - std::unique_ptr draggable_region_; // used in custom drag. - - // Minimum and maximum size, stored as content size. - extensions::SizeConstraints size_constraints_; - - // Whether window can be resized larger than screen. - bool enable_larger_than_screen_; - - // The windows has been closed. - bool is_closed_; - - // Closure that would be called when window is unresponsive when closing, - // it should be cancelled when we can prove that the window is responsive. - base::CancelableClosure window_unresposive_closure_; - - // Used to display sheets at the appropriate horizontal and vertical offsets - // on macOS. - double sheet_offset_x_; - double sheet_offset_y_; - - // Used to maintain the aspect ratio of a view which is inside of the - // content view. - double aspect_ratio_; - gfx::Size aspect_ratio_extraSize_; - - // The parent window, it is guaranteed to be valid during this window's life. - NativeWindow* parent_; - - // Is this a modal window. - bool is_modal_; - - // The page this window is viewing. - brightray::InspectableWebContents* inspectable_web_contents_; - - // Observers of this window. - base::ObserverList observers_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(NativeWindow); -}; - -// This class provides a hook to get a NativeWindow from a WebContents. -class NativeWindowRelay : - public content::WebContentsUserData { - public: - explicit NativeWindowRelay(base::WeakPtr window) - : key(UserDataKey()), window(window) {} - - void* key; - base::WeakPtr window; - - private: - friend class content::WebContentsUserData; -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NATIVE_WINDOW_H_ diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h deleted file mode 100644 index ab5645cc080b8..0000000000000 --- a/atom/browser/native_window_mac.h +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NATIVE_WINDOW_MAC_H_ -#define ATOM_BROWSER_NATIVE_WINDOW_MAC_H_ - -#import - -#include -#include - -#include "base/mac/scoped_nsobject.h" -#include "atom/browser/native_window.h" - -@class AtomNSWindow; -@class AtomNSWindowDelegate; -@class FullSizeContentView; - -namespace atom { - -class NativeWindowMac : public NativeWindow { - public: - NativeWindowMac(brightray::InspectableWebContents* inspectable_web_contents, - const mate::Dictionary& options, - NativeWindow* parent); - ~NativeWindowMac() override; - - // NativeWindow: - void Close() override; - void CloseImmediately() override; - void Focus(bool focus) override; - bool IsFocused() override; - void Show() override; - void ShowInactive() override; - void Hide() override; - bool IsVisible() override; - bool IsEnabled() override; - void Maximize() override; - void Unmaximize() override; - bool IsMaximized() override; - void Minimize() override; - void Restore() override; - bool IsMinimized() override; - void SetFullScreen(bool fullscreen) override; - bool IsFullscreen() const override; - void SetBounds(const gfx::Rect& bounds, bool animate = false) override; - gfx::Rect GetBounds() override; - void SetContentSizeConstraints( - const extensions::SizeConstraints& size_constraints) override; - void SetResizable(bool resizable) override; - bool IsResizable() override; - void SetMovable(bool movable) override; - void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size) - override; - bool IsMovable() override; - void SetMinimizable(bool minimizable) override; - bool IsMinimizable() override; - void SetMaximizable(bool maximizable) override; - bool IsMaximizable() override; - void SetFullScreenable(bool fullscreenable) override; - bool IsFullScreenable() override; - void SetClosable(bool closable) override; - bool IsClosable() override; - void SetAlwaysOnTop(bool top) override; - bool IsAlwaysOnTop() override; - void Center() override; - void SetTitle(const std::string& title) override; - std::string GetTitle() override; - void FlashFrame(bool flash) override; - void SetSkipTaskbar(bool skip) override; - void SetKiosk(bool kiosk) override; - bool IsKiosk() override; - void SetBackgroundColor(const std::string& color_name) override; - void SetHasShadow(bool has_shadow) override; - bool HasShadow() override; - void SetRepresentedFilename(const std::string& filename) override; - std::string GetRepresentedFilename() override; - void SetDocumentEdited(bool edited) override; - bool IsDocumentEdited() override; - void SetIgnoreMouseEvents(bool ignore) override; - void SetContentProtection(bool enable) override; - void SetParentWindow(NativeWindow* parent) override; - gfx::NativeWindow GetNativeWindow() override; - gfx::AcceleratedWidget GetAcceleratedWidget() override; - void SetProgressBar(double progress) override; - void SetOverlayIcon(const gfx::Image& overlay, - const std::string& description) override; - - void SetVisibleOnAllWorkspaces(bool visible) override; - bool IsVisibleOnAllWorkspaces() override; - - // Refresh the DraggableRegion views. - void UpdateDraggableRegionViews() { - UpdateDraggableRegionViews(draggable_regions_); - } - - // Set the attribute of NSWindow while work around a bug of zoom button. - void SetStyleMask(bool on, NSUInteger flag); - void SetCollectionBehavior(bool on, NSUInteger flag); - - enum TitleBarStyle { - NORMAL, - HIDDEN, - HIDDEN_INSET, - }; - TitleBarStyle title_bar_style() const { return title_bar_style_; } - - protected: - // Return a vector of non-draggable regions that fill a window of size - // |width| by |height|, but leave gaps where the window should be draggable. - std::vector CalculateNonDraggableRegions( - const std::vector& regions, int width, int height); - - private: - // NativeWindow: - gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds); - gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds); - void UpdateDraggableRegions( - const std::vector& regions) override; - - void InstallView(); - void UninstallView(); - - // Install the drag view, which will cover the whole window and decides - // whehter we can drag. - void UpdateDraggableRegionViews(const std::vector& regions); - - base::scoped_nsobject window_; - base::scoped_nsobject window_delegate_; - - // Event monitor for scroll wheel event. - id wheel_event_monitor_; - - // The view that will fill the whole frameless window. - base::scoped_nsobject content_view_; - - std::vector draggable_regions_; - - bool is_kiosk_; - - NSInteger attention_request_id_; // identifier from requestUserAttention - - // The presentation options before entering kiosk mode. - NSApplicationPresentationOptions kiosk_options_; - - // The "titleBarStyle" option. - TitleBarStyle title_bar_style_; - - DISALLOW_COPY_AND_ASSIGN(NativeWindowMac); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NATIVE_WINDOW_MAC_H_ diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm deleted file mode 100644 index 97f24efcaace2..0000000000000 --- a/atom/browser/native_window_mac.mm +++ /dev/null @@ -1,1208 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/native_window_mac.h" - -#include - -#include "atom/browser/window_list.h" -#include "atom/common/color_util.h" -#include "atom/common/draggable_region.h" -#include "atom/common/options_switches.h" -#include "base/mac/mac_util.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/strings/sys_string_conversions.h" -#include "brightray/browser/inspectable_web_contents.h" -#include "brightray/browser/inspectable_web_contents_view.h" -#include "brightray/browser/mac/event_dispatching_window.h" -#include "content/public/browser/browser_accessibility_state.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host_view.h" -#include "native_mate/dictionary.h" -#include "skia/ext/skia_utils_mac.h" -#include "ui/gfx/skia_util.h" - -namespace { - -// Prevents window from resizing during the scope. -class ScopedDisableResize { - public: - ScopedDisableResize() { disable_resize_ = true; } - ~ScopedDisableResize() { disable_resize_ = false; } - - static bool IsResizeDisabled() { return disable_resize_; } - - private: - static bool disable_resize_; -}; - -bool ScopedDisableResize::disable_resize_ = false; - -} // namespace - -// This view always takes the size of its superview. It is intended to be used -// as a NSWindow's contentView. It is needed because NSWindow's implementation -// explicitly resizes the contentView at inopportune times. -@interface FullSizeContentView : NSView -@end - -@implementation FullSizeContentView - -// This method is directly called by NSWindow during a window resize on OSX -// 10.10.0, beta 2. We must override it to prevent the content view from -// shrinking. -- (void)setFrameSize:(NSSize)size { - if ([self superview]) - size = [[self superview] bounds].size; - [super setFrameSize:size]; -} - -// The contentView gets moved around during certain full-screen operations. -// This is less than ideal, and should eventually be removed. -- (void)viewDidMoveToSuperview { - [self setFrame:[[self superview] bounds]]; -} - -@end - -@interface AtomNSWindowDelegate : NSObject { - @private - atom::NativeWindowMac* shell_; - bool is_zooming_; -} -- (id)initWithShell:(atom::NativeWindowMac*)shell; -@end - -@implementation AtomNSWindowDelegate - -- (id)initWithShell:(atom::NativeWindowMac*)shell { - if ((self = [super init])) { - shell_ = shell; - is_zooming_ = false; - } - return self; -} - -- (void)windowDidChangeOcclusionState:(NSNotification *)notification { - // notification.object is the window that changed its state. - // It's safe to use self.window instead if you don't assign one delegate to many windows - NSWindow *window = notification.object; - - // check occlusion binary flag - if (window.occlusionState & NSWindowOcclusionStateVisible) { - // The app is visible - shell_->NotifyWindowShow(); - } else { - // The app is not visible - shell_->NotifyWindowHide(); - } -} - -- (void)windowDidBecomeMain:(NSNotification*)notification { - content::WebContents* web_contents = shell_->web_contents(); - if (!web_contents) - return; - - web_contents->RestoreFocus(); - - content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView(); - if (rwhv) - rwhv->SetActive(true); - - shell_->NotifyWindowFocus(); -} - -- (void)windowDidResignMain:(NSNotification*)notification { - content::WebContents* web_contents = shell_->web_contents(); - if (!web_contents) - return; - - web_contents->StoreFocus(); - - content::RenderWidgetHostView* rwhv = web_contents->GetRenderWidgetHostView(); - if (rwhv) - rwhv->SetActive(false); - - shell_->NotifyWindowBlur(); -} - -- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize { - NSSize newSize = frameSize; - double aspectRatio = shell_->GetAspectRatio(); - - if (aspectRatio > 0.0) { - gfx::Size windowSize = shell_->GetSize(); - gfx::Size contentSize = shell_->GetContentSize(); - gfx::Size extraSize = shell_->GetAspectRatioExtraSize(); - - double extraWidthPlusFrame = - windowSize.width() - contentSize.width() + extraSize.width(); - double extraHeightPlusFrame = - windowSize.height() - contentSize.height() + extraSize.height(); - - newSize.width = - roundf((frameSize.height - extraHeightPlusFrame) * aspectRatio + - extraWidthPlusFrame); - newSize.height = - roundf((newSize.width - extraWidthPlusFrame) / aspectRatio + - extraHeightPlusFrame); - } - - return newSize; -} - -- (void)windowDidResize:(NSNotification*)notification { - shell_->UpdateDraggableRegionViews(); - shell_->NotifyWindowResize(); -} - -- (void)windowDidMove:(NSNotification*)notification { - // TODO(zcbenz): Remove the alias after figuring out a proper - // way to disptach move. - shell_->NotifyWindowMove(); - shell_->NotifyWindowMoved(); -} - -- (void)windowDidMiniaturize:(NSNotification*)notification { - shell_->NotifyWindowMinimize(); -} - -- (void)windowDidDeminiaturize:(NSNotification*)notification { - shell_->NotifyWindowRestore(); -} - -- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame { - is_zooming_ = true; - return YES; -} - -- (void)windowDidEndLiveResize:(NSNotification*)notification { - if (is_zooming_) { - if (shell_->IsMaximized()) - shell_->NotifyWindowMaximize(); - else - shell_->NotifyWindowUnmaximize(); - is_zooming_ = false; - } -} - -- (void)windowWillEnterFullScreen:(NSNotification*)notification { - // Hide the native toolbar before entering fullscreen, so there is no visual - // artifacts. - if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { - NSWindow* window = shell_->GetNativeWindow(); - [window setToolbar:nil]; - } -} - -- (void)windowDidEnterFullScreen:(NSNotification*)notification { - shell_->NotifyWindowEnterFullScreen(); - - // For frameless window we don't show set title for normal mode since the - // titlebar is expected to be empty, but after entering fullscreen mode we - // have to set one, because title bar is visible here. - NSWindow* window = shell_->GetNativeWindow(); - if ((shell_->transparent() || !shell_->has_frame()) && - base::mac::IsOSYosemiteOrLater() && - // FIXME(zcbenz): Showing titlebar for hiddenInset window is weird under - // fullscreen mode. - shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET) { - [window setTitleVisibility:NSWindowTitleVisible]; - } - - // Restore the native toolbar immediately after entering fullscreen, if we do - // this before leaving fullscreen, traffic light buttons will be jumping. - if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) { - base::scoped_nsobject toolbar( - [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]); - [toolbar setShowsBaselineSeparator:NO]; - [window setToolbar:toolbar]; - - // Set window style to hide the toolbar, otherwise the toolbar will show in - // fullscreen mode. - shell_->SetStyleMask(true, NSFullSizeContentViewWindowMask); - } -} - -- (void)windowWillExitFullScreen:(NSNotification*)notification { - // Restore the titlebar visibility. - NSWindow* window = shell_->GetNativeWindow(); - if ((shell_->transparent() || !shell_->has_frame()) && - base::mac::IsOSYosemiteOrLater() && - shell_->title_bar_style() != atom::NativeWindowMac::HIDDEN_INSET) { - [window setTitleVisibility:NSWindowTitleHidden]; - } - - // Turn off the style for toolbar. - if (shell_->title_bar_style() == atom::NativeWindowMac::HIDDEN_INSET) - shell_->SetStyleMask(false, NSFullSizeContentViewWindowMask); -} - -- (void)windowDidExitFullScreen:(NSNotification*)notification { - shell_->NotifyWindowLeaveFullScreen(); -} - -- (void)windowWillClose:(NSNotification*)notification { - shell_->NotifyWindowClosed(); - - // Clears the delegate when window is going to be closed, since EL Capitan it - // is possible that the methods of delegate would get called after the window - // has been closed. - [shell_->GetNativeWindow() setDelegate:nil]; -} - -- (BOOL)windowShouldClose:(id)window { - // When user tries to close the window by clicking the close button, we do - // not close the window immediately, instead we try to close the web page - // fisrt, and when the web page is closed the window will also be closed. - shell_->RequestToClosePage(); - return NO; -} - -- (NSRect)window:(NSWindow*)window - willPositionSheet:(NSWindow*)sheet usingRect:(NSRect)rect { - NSView* view = window.contentView; - - rect.origin.x = shell_->GetSheetOffsetX(); - rect.origin.y = view.frame.size.height - shell_->GetSheetOffsetY(); - return rect; -} - -@end - -@interface AtomNSWindow : EventDispatchingWindow { - @private - atom::NativeWindowMac* shell_; - bool enable_larger_than_screen_; -} -@property BOOL acceptsFirstMouse; -@property BOOL disableAutoHideCursor; -@property BOOL disableKeyOrMainWindow; - -- (void)setShell:(atom::NativeWindowMac*)shell; -- (void)setEnableLargerThanScreen:(bool)enable; -@end - -@implementation AtomNSWindow - -- (void)setShell:(atom::NativeWindowMac*)shell { - shell_ = shell; -} - -- (void)setEnableLargerThanScreen:(bool)enable { - enable_larger_than_screen_ = enable; -} - -// NSWindow overrides. - -- (void)swipeWithEvent:(NSEvent *)event { - if (event.deltaY == 1.0) { - shell_->NotifyWindowSwipe("up"); - } else if (event.deltaX == -1.0) { - shell_->NotifyWindowSwipe("right"); - } else if (event.deltaY == -1.0) { - shell_->NotifyWindowSwipe("down"); - } else if (event.deltaX == 1.0) { - shell_->NotifyWindowSwipe("left"); - } -} - -- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen*)screen { - // Resizing is disabled. - if (ScopedDisableResize::IsResizeDisabled()) - return [self frame]; - - // Enable the window to be larger than screen. - if (enable_larger_than_screen_) - return frameRect; - else - return [super constrainFrameRect:frameRect toScreen:screen]; -} - -- (id)accessibilityAttributeValue:(NSString*)attribute { - if (![attribute isEqualToString:@"AXChildren"]) - return [super accessibilityAttributeValue:attribute]; - - // Filter out objects that aren't the title bar buttons. This has the effect - // of removing the window title, which VoiceOver already sees. - // * when VoiceOver is disabled, this causes Cmd+C to be used for TTS but - // still leaves the buttons available in the accessibility tree. - // * when VoiceOver is enabled, the full accessibility tree is used. - // Without removing the title and with VO disabled, the TTS would always read - // the window title instead of using Cmd+C to get the selected text. - NSPredicate *predicate = [NSPredicate predicateWithFormat: - @"(self isKindOfClass: %@) OR (self.className == %@)", - [NSButtonCell class], - @"RenderWidgetHostViewCocoa"]; - - NSArray *children = [super accessibilityAttributeValue:attribute]; - return [children filteredArrayUsingPredicate:predicate]; -} - -- (BOOL)canBecomeMainWindow { - return !self.disableKeyOrMainWindow; -} - -- (BOOL)canBecomeKeyWindow { - return !self.disableKeyOrMainWindow; -} - -@end - -@interface ControlRegionView : NSView -@end - -@implementation ControlRegionView - -- (BOOL)mouseDownCanMoveWindow { - return NO; -} - -- (NSView*)hitTest:(NSPoint)aPoint { - return nil; -} - -@end - -@interface NSView (WebContentsView) -- (void)setMouseDownCanMoveWindow:(BOOL)can_move; -@end - -@interface AtomProgressBar : NSProgressIndicator -@end - -@implementation AtomProgressBar - -- (void)drawRect:(NSRect)dirtyRect { - if (self.style != NSProgressIndicatorBarStyle) - return; - // Draw edges of rounded rect. - NSRect rect = NSInsetRect([self bounds], 1.0, 1.0); - CGFloat radius = rect.size.height / 2; - NSBezierPath* bezier_path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:radius yRadius:radius]; - [bezier_path setLineWidth:2.0]; - [[NSColor grayColor] set]; - [bezier_path stroke]; - - // Fill the rounded rect. - rect = NSInsetRect(rect, 2.0, 2.0); - radius = rect.size.height / 2; - bezier_path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:radius yRadius:radius]; - [bezier_path setLineWidth:1.0]; - [bezier_path addClip]; - - // Calculate the progress width. - rect.size.width = floor(rect.size.width * ([self doubleValue] / [self maxValue])); - - // Fill the progress bar with color blue. - [[NSColor colorWithSRGBRed:0.2 green:0.6 blue:1 alpha:1] set]; - NSRectFill(rect); -} - -@end - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Handle val, - atom::NativeWindowMac::TitleBarStyle* out) { - std::string title_bar_style; - if (!ConvertFromV8(isolate, val, &title_bar_style)) - return false; - if (title_bar_style == "hidden") { - *out = atom::NativeWindowMac::HIDDEN; - } else if (title_bar_style == "hidden-inset" || // Deprecate this after 2.0 - title_bar_style == "hiddenInset") { - *out = atom::NativeWindowMac::HIDDEN_INSET; - } else { - return false; - } - return true; - } -}; - -} // namespace mate - -namespace atom { - -NativeWindowMac::NativeWindowMac( - brightray::InspectableWebContents* web_contents, - const mate::Dictionary& options, - NativeWindow* parent) - : NativeWindow(web_contents, options, parent), - is_kiosk_(false), - attention_request_id_(0), - title_bar_style_(NORMAL) { - int width = 800, height = 600; - options.Get(options::kWidth, &width); - options.Get(options::kHeight, &height); - - NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame]; - NSRect cocoa_bounds = NSMakeRect( - round((NSWidth(main_screen_rect) - width) / 2) , - round((NSHeight(main_screen_rect) - height) / 2), - width, - height); - - bool resizable = true; - options.Get(options::kResizable, &resizable); - - bool minimizable = true; - options.Get(options::kMinimizable, &minimizable); - - bool maximizable = true; - options.Get(options::kMaximizable, &maximizable); - - bool closable = true; - options.Get(options::kClosable, &closable); - - // New title bar styles are available in Yosemite or newer - if (base::mac::IsOSYosemiteOrLater()) - options.Get(options::kTitleBarStyle, &title_bar_style_); - - std::string windowType; - options.Get(options::kType, &windowType); - - bool useStandardWindow = true; - // eventually deprecate separate "standardWindow" option in favor of - // standard / textured window types - options.Get(options::kStandardWindow, &useStandardWindow); - if (windowType == "textured") { - useStandardWindow = false; - } - - NSUInteger styleMask = NSTitledWindowMask; - if (minimizable) { - styleMask |= NSMiniaturizableWindowMask; - } - if (closable) { - styleMask |= NSClosableWindowMask; - } - if (title_bar_style_ != NORMAL) { - // The window without titlebar is treated the same with frameless window. - set_has_frame(false); - } - if (!useStandardWindow || transparent() || !has_frame()) { - styleMask |= NSTexturedBackgroundWindowMask; - } - if (resizable) { - styleMask |= NSResizableWindowMask; - } - - window_.reset([[AtomNSWindow alloc] - initWithContentRect:cocoa_bounds - styleMask:styleMask - backing:NSBackingStoreBuffered - defer:YES]); - [window_ setShell:this]; - [window_ setEnableLargerThanScreen:enable_larger_than_screen()]; - - window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]); - [window_ setDelegate:window_delegate_]; - - // Only use native parent window for non-modal windows. - if (parent && !is_modal()) { - SetParentWindow(parent); - } - - if (transparent()) { - // Setting the background color to clear will also hide the shadow. - [window_ setBackgroundColor:[NSColor clearColor]]; - } - - if (windowType == "desktop") { - [window_ setLevel:kCGDesktopWindowLevel - 1]; - [window_ setDisableKeyOrMainWindow:YES]; - [window_ setCollectionBehavior: - (NSWindowCollectionBehaviorCanJoinAllSpaces | - NSWindowCollectionBehaviorStationary | - NSWindowCollectionBehaviorIgnoresCycle)]; - } - - bool focusable; - if (options.Get(options::kFocusable, &focusable) && !focusable) - [window_ setDisableKeyOrMainWindow:YES]; - - if (transparent() || !has_frame()) { - if (base::mac::IsOSYosemiteOrLater()) { - // Don't show title bar. - [window_ setTitleVisibility:NSWindowTitleHidden]; - } - // Remove non-transparent corners, see http://git.io/vfonD. - [window_ setOpaque:NO]; - } - - // We will manage window's lifetime ourselves. - [window_ setReleasedWhenClosed:NO]; - - // Hide the title bar. - if (title_bar_style_ == HIDDEN_INSET) { - [window_ setTitlebarAppearsTransparent:YES]; - base::scoped_nsobject toolbar( - [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]); - [toolbar setShowsBaselineSeparator:NO]; - [window_ setToolbar:toolbar]; - } - - // On macOS the initial window size doesn't include window frame. - bool use_content_size = false; - options.Get(options::kUseContentSize, &use_content_size); - if (!has_frame() || !use_content_size) - SetSize(gfx::Size(width, height)); - - // Enable the NSView to accept first mouse event. - bool acceptsFirstMouse = false; - options.Get(options::kAcceptFirstMouse, &acceptsFirstMouse); - [window_ setAcceptsFirstMouse:acceptsFirstMouse]; - - // Disable auto-hiding cursor. - bool disableAutoHideCursor = false; - options.Get(options::kDisableAutoHideCursor, &disableAutoHideCursor); - [window_ setDisableAutoHideCursor:disableAutoHideCursor]; - - NSView* view = inspectable_web_contents()->GetView()->GetNativeView(); - [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - - // Use an NSEvent monitor to listen for the wheel event. - BOOL __block began = NO; - wheel_event_monitor_ = [NSEvent - addLocalMonitorForEventsMatchingMask:NSScrollWheelMask - handler:^(NSEvent* event) { - if ([[event window] windowNumber] != [window_ windowNumber]) - return event; - - if (!web_contents) - return event; - - if (!began && (([event phase] == NSEventPhaseMayBegin) || - ([event phase] == NSEventPhaseBegan))) { - this->NotifyWindowScrollTouchBegin(); - began = YES; - } else if (began && (([event phase] == NSEventPhaseEnded) || - ([event phase] == NSEventPhaseCancelled))) { - this->NotifyWindowScrollTouchEnd(); - began = NO; - } - return event; - }]; - - InstallView(); - - // Set maximizable state last to ensure zoom button does not get reset - // by calls to other APIs. - SetMaximizable(maximizable); -} - -NativeWindowMac::~NativeWindowMac() { - [NSEvent removeMonitor:wheel_event_monitor_]; - Observe(nullptr); -} - -void NativeWindowMac::Close() { - // When this is a sheet showing, performClose won't work. - if (is_modal() && parent() && IsVisible()) { - CloseImmediately(); - return; - } - - if (!IsClosable()) { - WindowList::WindowCloseCancelled(this); - return; - } - - [window_ performClose:nil]; -} - -void NativeWindowMac::CloseImmediately() { - [window_ close]; -} - -void NativeWindowMac::Focus(bool focus) { - if (!IsVisible()) - return; - - if (focus) { - [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - [window_ makeKeyAndOrderFront:nil]; - } else { - [window_ orderBack:nil]; - } -} - -bool NativeWindowMac::IsFocused() { - return [window_ isKeyWindow]; -} - -void NativeWindowMac::Show() { - if (is_modal() && parent()) { - [parent()->GetNativeWindow() beginSheet:window_ - completionHandler:^(NSModalResponse) {}]; - return; - } - - // This method is supposed to put focus on window, however if the app does not - // have focus then "makeKeyAndOrderFront" will only show the window. - [NSApp activateIgnoringOtherApps:YES]; - - [window_ makeKeyAndOrderFront:nil]; -} - -void NativeWindowMac::ShowInactive() { - [window_ orderFrontRegardless]; -} - -void NativeWindowMac::Hide() { - if (is_modal() && parent()) { - [window_ orderOut:nil]; - [parent()->GetNativeWindow() endSheet:window_]; - return; - } - - [window_ orderOut:nil]; -} - -bool NativeWindowMac::IsVisible() { - return [window_ isVisible]; -} - -bool NativeWindowMac::IsEnabled() { - return [window_ attachedSheet] == nil; -} - -void NativeWindowMac::Maximize() { - if (IsMaximized()) - return; - - [window_ zoom:nil]; -} - -void NativeWindowMac::Unmaximize() { - if (!IsMaximized()) - return; - - [window_ zoom:nil]; -} - -bool NativeWindowMac::IsMaximized() { - if (([window_ styleMask] & NSResizableWindowMask) != 0) { - return [window_ isZoomed]; - } else { - NSRect rectScreen = [[NSScreen mainScreen] visibleFrame]; - NSRect rectWindow = [window_ frame]; - return (rectScreen.origin.x == rectWindow.origin.x && - rectScreen.origin.y == rectWindow.origin.y && - rectScreen.size.width == rectWindow.size.width && - rectScreen.size.height == rectWindow.size.height); - } -} - -void NativeWindowMac::Minimize() { - [window_ miniaturize:nil]; -} - -void NativeWindowMac::Restore() { - [window_ deminiaturize:nil]; -} - -bool NativeWindowMac::IsMinimized() { - return [window_ isMiniaturized]; -} - -void NativeWindowMac::SetFullScreen(bool fullscreen) { - if (fullscreen == IsFullscreen()) - return; - - [window_ toggleFullScreen:nil]; -} - -bool NativeWindowMac::IsFullscreen() const { - return [window_ styleMask] & NSFullScreenWindowMask; -} - -void NativeWindowMac::SetBounds(const gfx::Rect& bounds, bool animate) { - // Do nothing if in fullscreen mode. - if (IsFullscreen()) - return; - - // Check size constraints since setFrame does not check it. - gfx::Size size = bounds.size(); - size.SetToMax(GetMinimumSize()); - gfx::Size max_size = GetMaximumSize(); - if (!max_size.IsEmpty()) - size.SetToMin(max_size); - - NSRect cocoa_bounds = NSMakeRect(bounds.x(), 0, size.width(), size.height()); - // Flip coordinates based on the primary screen. - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; - cocoa_bounds.origin.y = - NSHeight([screen frame]) - size.height() - bounds.y(); - - [window_ setFrame:cocoa_bounds display:YES animate:animate]; -} - -gfx::Rect NativeWindowMac::GetBounds() { - NSRect frame = [window_ frame]; - gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame)); - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; - bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame)); - return bounds; -} - -void NativeWindowMac::SetContentSizeConstraints( - const extensions::SizeConstraints& size_constraints) { - auto convertSize = [this](const gfx::Size& size) { - // Our frameless window still has titlebar attached, so setting contentSize - // will result in actual content size being larger. - if (!has_frame()) { - NSRect frame = NSMakeRect(0, 0, size.width(), size.height()); - NSRect content = [window_ contentRectForFrameRect:frame]; - return content.size; - } else { - return NSMakeSize(size.width(), size.height()); - } - }; - - NSView* content = [window_ contentView]; - if (size_constraints.HasMinimumSize()) { - NSSize min_size = convertSize(size_constraints.GetMinimumSize()); - [window_ setContentMinSize:[content convertSize:min_size toView:nil]]; - } - if (size_constraints.HasMaximumSize()) { - NSSize max_size = convertSize(size_constraints.GetMaximumSize()); - [window_ setContentMaxSize:[content convertSize:max_size toView:nil]]; - } - NativeWindow::SetContentSizeConstraints(size_constraints); -} - -void NativeWindowMac::SetResizable(bool resizable) { - // Change styleMask for frameless causes the window to change size, so we have - // to explicitly disables that. - ScopedDisableResize disable_resize; - SetStyleMask(resizable, NSResizableWindowMask); -} - -bool NativeWindowMac::IsResizable() { - return [window_ styleMask] & NSResizableWindowMask; -} - -void NativeWindowMac::SetAspectRatio(double aspect_ratio, - const gfx::Size& extra_size) { - NativeWindow::SetAspectRatio(aspect_ratio, extra_size); - - // Reset the behaviour to default if aspect_ratio is set to 0 or less. - if (aspect_ratio > 0.0) - [window_ setAspectRatio:NSMakeSize(aspect_ratio, 1.0)]; - else - [window_ setResizeIncrements:NSMakeSize(1.0, 1.0)]; -} - -void NativeWindowMac::SetMovable(bool movable) { - [window_ setMovable:movable]; -} - -bool NativeWindowMac::IsMovable() { - return [window_ isMovable]; -} - -void NativeWindowMac::SetMinimizable(bool minimizable) { - SetStyleMask(minimizable, NSMiniaturizableWindowMask); -} - -bool NativeWindowMac::IsMinimizable() { - return [window_ styleMask] & NSMiniaturizableWindowMask; -} - -void NativeWindowMac::SetMaximizable(bool maximizable) { - [[window_ standardWindowButton:NSWindowZoomButton] setEnabled:maximizable]; -} - -bool NativeWindowMac::IsMaximizable() { - return [[window_ standardWindowButton:NSWindowZoomButton] isEnabled]; -} - -void NativeWindowMac::SetFullScreenable(bool fullscreenable) { - SetCollectionBehavior( - fullscreenable, NSWindowCollectionBehaviorFullScreenPrimary); - // On EL Capitan this flag is required to hide fullscreen button. - SetCollectionBehavior( - !fullscreenable, NSWindowCollectionBehaviorFullScreenAuxiliary); -} - -bool NativeWindowMac::IsFullScreenable() { - NSUInteger collectionBehavior = [window_ collectionBehavior]; - return collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary; -} - -void NativeWindowMac::SetClosable(bool closable) { - SetStyleMask(closable, NSClosableWindowMask); -} - -bool NativeWindowMac::IsClosable() { - return [window_ styleMask] & NSClosableWindowMask; -} - -void NativeWindowMac::SetAlwaysOnTop(bool top) { - [window_ setLevel:(top ? NSFloatingWindowLevel : NSNormalWindowLevel)]; -} - -bool NativeWindowMac::IsAlwaysOnTop() { - return [window_ level] == NSFloatingWindowLevel; -} - -void NativeWindowMac::Center() { - [window_ center]; -} - -void NativeWindowMac::SetTitle(const std::string& title) { - // For macOS <= 10.9, the setTitleVisibility API is not available, we have - // to avoid calling setTitle for frameless window. - if (!base::mac::IsOSYosemiteOrLater() && (transparent() || !has_frame())) - return; - - [window_ setTitle:base::SysUTF8ToNSString(title)]; -} - -std::string NativeWindowMac::GetTitle() { - return base::SysNSStringToUTF8([window_ title]);; -} - -void NativeWindowMac::FlashFrame(bool flash) { - if (flash) { - attention_request_id_ = [NSApp requestUserAttention:NSInformationalRequest]; - } else { - [NSApp cancelUserAttentionRequest:attention_request_id_]; - attention_request_id_ = 0; - } -} - -void NativeWindowMac::SetSkipTaskbar(bool skip) { -} - -void NativeWindowMac::SetKiosk(bool kiosk) { - if (kiosk && !is_kiosk_) { - kiosk_options_ = [NSApp currentSystemPresentationOptions]; - NSApplicationPresentationOptions options = - NSApplicationPresentationHideDock + - NSApplicationPresentationHideMenuBar + - NSApplicationPresentationDisableAppleMenu + - NSApplicationPresentationDisableProcessSwitching + - NSApplicationPresentationDisableForceQuit + - NSApplicationPresentationDisableSessionTermination + - NSApplicationPresentationDisableHideApplication; - [NSApp setPresentationOptions:options]; - is_kiosk_ = true; - SetFullScreen(true); - } else if (!kiosk && is_kiosk_) { - is_kiosk_ = false; - SetFullScreen(false); - [NSApp setPresentationOptions:kiosk_options_]; - } -} - -bool NativeWindowMac::IsKiosk() { - return is_kiosk_; -} - -void NativeWindowMac::SetBackgroundColor(const std::string& color_name) { - SkColor color = ParseHexColor(color_name); - base::ScopedCFTypeRef cgcolor = - skia::CGColorCreateFromSkColor(color); - [[[window_ contentView] layer] setBackgroundColor:cgcolor]; - - const auto view = web_contents()->GetRenderWidgetHostView(); - if (view) - view->SetBackgroundColor(color); -} - -void NativeWindowMac::SetHasShadow(bool has_shadow) { - [window_ setHasShadow:has_shadow]; -} - -bool NativeWindowMac::HasShadow() { - return [window_ hasShadow]; -} - -void NativeWindowMac::SetRepresentedFilename(const std::string& filename) { - [window_ setRepresentedFilename:base::SysUTF8ToNSString(filename)]; -} - -std::string NativeWindowMac::GetRepresentedFilename() { - return base::SysNSStringToUTF8([window_ representedFilename]); -} - -void NativeWindowMac::SetDocumentEdited(bool edited) { - [window_ setDocumentEdited:edited]; -} - -bool NativeWindowMac::IsDocumentEdited() { - return [window_ isDocumentEdited]; -} - -void NativeWindowMac::SetIgnoreMouseEvents(bool ignore) { - [window_ setIgnoresMouseEvents:ignore]; -} - -void NativeWindowMac::SetContentProtection(bool enable) { - [window_ setSharingType:enable ? NSWindowSharingNone - : NSWindowSharingReadOnly]; -} - -void NativeWindowMac::SetParentWindow(NativeWindow* parent) { - if (is_modal()) - return; - - NativeWindow::SetParentWindow(parent); - - // Remove current parent window. - if ([window_ parentWindow]) - [[window_ parentWindow] removeChildWindow:window_]; - - // Set new current window. - if (parent) - [parent->GetNativeWindow() addChildWindow:window_ ordered:NSWindowAbove]; -} - -gfx::NativeWindow NativeWindowMac::GetNativeWindow() { - return window_; -} - -gfx::AcceleratedWidget NativeWindowMac::GetAcceleratedWidget() { - return inspectable_web_contents()->GetView()->GetNativeView(); -} - -void NativeWindowMac::SetProgressBar(double progress) { - NSDockTile* dock_tile = [NSApp dockTile]; - - // For the first time API invoked, we need to create a ContentView in DockTile. - if (dock_tile.contentView == NULL) { - NSImageView* image_view = [[NSImageView alloc] init]; - [image_view setImage:[NSApp applicationIconImage]]; - [dock_tile setContentView:image_view]; - } - - if ([[dock_tile.contentView subviews] count] == 0) { - NSProgressIndicator* progress_indicator = [[AtomProgressBar alloc] - initWithFrame:NSMakeRect(0.0f, 0.0f, dock_tile.size.width, 15.0)]; - [progress_indicator setStyle:NSProgressIndicatorBarStyle]; - [progress_indicator setIndeterminate:NO]; - [progress_indicator setBezeled:YES]; - [progress_indicator setMinValue:0]; - [progress_indicator setMaxValue:1]; - [progress_indicator setHidden:NO]; - [dock_tile.contentView addSubview:progress_indicator]; - } - - NSProgressIndicator* progress_indicator = - static_cast([[[dock_tile contentView] subviews] - objectAtIndex:0]); - if (progress < 0) { - [progress_indicator setHidden:YES]; - } else if (progress > 1) { - [progress_indicator setHidden:NO]; - [progress_indicator setIndeterminate:YES]; - [progress_indicator setDoubleValue:1]; - } else { - [progress_indicator setHidden:NO]; - [progress_indicator setDoubleValue:progress]; - } - [dock_tile display]; -} - -void NativeWindowMac::SetOverlayIcon(const gfx::Image& overlay, - const std::string& description) { -} - -void NativeWindowMac::SetVisibleOnAllWorkspaces(bool visible) { - SetCollectionBehavior(visible, NSWindowCollectionBehaviorCanJoinAllSpaces); -} - -bool NativeWindowMac::IsVisibleOnAllWorkspaces() { - NSUInteger collectionBehavior = [window_ collectionBehavior]; - return collectionBehavior & NSWindowCollectionBehaviorCanJoinAllSpaces; -} - -std::vector NativeWindowMac::CalculateNonDraggableRegions( - const std::vector& regions, int width, int height) { - std::vector result; - if (regions.empty()) { - result.push_back(gfx::Rect(0, 0, width, height)); - } else { - std::unique_ptr draggable(DraggableRegionsToSkRegion(regions)); - std::unique_ptr non_draggable(new SkRegion); - non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op); - non_draggable->op(*draggable, SkRegion::kDifference_Op); - for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) { - result.push_back(gfx::SkIRectToRect(it.rect())); - } - } - return result; -} - -gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds( - const gfx::Rect& bounds) { - if (has_frame()) { - gfx::Rect window_bounds( - [window_ frameRectForContentRect:bounds.ToCGRect()]); - int frame_height = window_bounds.height() - bounds.height(); - window_bounds.set_y(window_bounds.y() - frame_height); - return window_bounds; - } else { - return bounds; - } -} - -gfx::Rect NativeWindowMac::WindowBoundsToContentBounds( - const gfx::Rect& bounds) { - if (has_frame()) { - gfx::Rect content_bounds( - [window_ contentRectForFrameRect:bounds.ToCGRect()]); - int frame_height = bounds.height() - content_bounds.height(); - content_bounds.set_y(content_bounds.y() + frame_height); - return content_bounds; - } else { - return bounds; - } -} - -void NativeWindowMac::UpdateDraggableRegions( - const std::vector& regions) { - NativeWindow::UpdateDraggableRegions(regions); - draggable_regions_ = regions; - UpdateDraggableRegionViews(regions); -} - -void NativeWindowMac::InstallView() { - // Make sure the bottom corner is rounded: http://crbug.com/396264. - // But do not enable it on OS X 10.9 for transparent window, otherwise a - // semi-transparent frame would show. - if (!(transparent() && base::mac::IsOSMavericks())) - [[window_ contentView] setWantsLayer:YES]; - - NSView* view = inspectable_web_contents()->GetView()->GetNativeView(); - if (has_frame()) { - [view setFrame:[[window_ contentView] bounds]]; - [[window_ contentView] addSubview:view]; - } else { - // In OSX 10.10, adding subviews to the root view for the NSView hierarchy - // produces warnings. To eliminate the warnings, we resize the contentView - // to fill the window, and add subviews to that. - // http://crbug.com/380412 - content_view_.reset([[FullSizeContentView alloc] init]); - [content_view_ - setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [content_view_ setFrame:[[[window_ contentView] superview] bounds]]; - [window_ setContentView:content_view_]; - - [view setFrame:[content_view_ bounds]]; - [content_view_ addSubview:view]; - - // The fullscreen button should always be hidden for frameless window. - [[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES]; - - if (title_bar_style_ != NORMAL) - return; - - // Hide the window buttons. - [[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES]; - [[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES]; - [[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES]; - - // Some third-party macOS utilities check the zoom button's enabled state to - // determine whether to show custom UI on hover, so we disable it here to - // prevent them from doing so in a frameless app window. - [[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO]; - } -} - -void NativeWindowMac::UninstallView() { - NSView* view = inspectable_web_contents()->GetView()->GetNativeView(); - [view removeFromSuperview]; -} - -void NativeWindowMac::UpdateDraggableRegionViews( - const std::vector& regions) { - if (has_frame()) - return; - - // All ControlRegionViews should be added as children of the WebContentsView, - // because WebContentsView will be removed and re-added when entering and - // leaving fullscreen mode. - NSView* webView = web_contents()->GetNativeView(); - NSInteger webViewWidth = NSWidth([webView bounds]); - NSInteger webViewHeight = NSHeight([webView bounds]); - - if ([webView respondsToSelector:@selector(setMouseDownCanMoveWindow:)]) { - [webView setMouseDownCanMoveWindow:YES]; - } - - // Remove all ControlRegionViews that are added last time. - // Note that [webView subviews] returns the view's mutable internal array and - // it should be copied to avoid mutating the original array while enumerating - // it. - base::scoped_nsobject subviews([[webView subviews] copy]); - for (NSView* subview in subviews.get()) - if ([subview isKindOfClass:[ControlRegionView class]]) - [subview removeFromSuperview]; - - // Draggable regions is implemented by having the whole web view draggable - // (mouseDownCanMoveWindow) and overlaying regions that are not draggable. - std::vector system_drag_exclude_areas = - CalculateNonDraggableRegions(regions, webViewWidth, webViewHeight); - - // Create and add a ControlRegionView for each region that needs to be - // excluded from the dragging. - for (std::vector::const_iterator iter = - system_drag_exclude_areas.begin(); - iter != system_drag_exclude_areas.end(); - ++iter) { - base::scoped_nsobject controlRegion( - [[ControlRegionView alloc] initWithFrame:NSZeroRect]); - [controlRegion setFrame:NSMakeRect(iter->x(), - webViewHeight - iter->bottom(), - iter->width(), - iter->height())]; - [webView addSubview:controlRegion]; - } - - // AppKit will not update its cache of mouseDownCanMoveWindow unless something - // changes. Previously we tried adding an NSView and removing it, but for some - // reason it required reposting the mouse-down event, and didn't always work. - // Calling the below seems to be an effective solution. - [window_ setMovableByWindowBackground:NO]; - [window_ setMovableByWindowBackground:YES]; -} - -void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) { - bool was_maximizable = IsMaximizable(); - if (on) - [window_ setStyleMask:[window_ styleMask] | flag]; - else - [window_ setStyleMask:[window_ styleMask] & (~flag)]; - // Change style mask will make the zoom button revert to default, probably - // a bug of Cocoa or macOS. - SetMaximizable(was_maximizable); -} - -void NativeWindowMac::SetCollectionBehavior(bool on, NSUInteger flag) { - bool was_maximizable = IsMaximizable(); - if (on) - [window_ setCollectionBehavior:[window_ collectionBehavior] | flag]; - else - [window_ setCollectionBehavior:[window_ collectionBehavior] & (~flag)]; - // Change collectionBehavior will make the zoom button revert to default, - // probably a bug of Cocoa or macOS. - SetMaximizable(was_maximizable); -} - -// static -NativeWindow* NativeWindow::Create( - brightray::InspectableWebContents* inspectable_web_contents, - const mate::Dictionary& options, - NativeWindow* parent) { - return new NativeWindowMac(inspectable_web_contents, options, parent); -} - -} // namespace atom diff --git a/atom/browser/native_window_observer.h b/atom/browser/native_window_observer.h deleted file mode 100644 index 16541d0909004..0000000000000 --- a/atom/browser/native_window_observer.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NATIVE_WINDOW_OBSERVER_H_ -#define ATOM_BROWSER_NATIVE_WINDOW_OBSERVER_H_ - -#include - -#include "base/strings/string16.h" -#include "ui/base/window_open_disposition.h" -#include "url/gurl.h" - -#if defined(OS_WIN) -#include -#endif - -namespace atom { - -class NativeWindowObserver { - public: - virtual ~NativeWindowObserver() {} - - // Called when the web page in window wants to create a popup window. - virtual void WillCreatePopupWindow(const base::string16& frame_name, - const GURL& target_url, - const std::string& partition_id, - WindowOpenDisposition disposition) {} - - // Called when user is starting an navigation in web page. - virtual void WillNavigate(bool* prevent_default, const GURL& url) {} - - // Called when the window is gonna closed. - virtual void WillCloseWindow(bool* prevent_default) {} - - // Called before the native window object is going to be destroyed. - virtual void WillDestoryNativeObject() {} - - // Called when the window is closed. - virtual void OnWindowClosed() {} - - // Called when window loses focus. - virtual void OnWindowBlur() {} - - // Called when window gains focus. - virtual void OnWindowFocus() {} - - // Called when window is shown. - virtual void OnWindowShow() {} - - // Called when window is hidden. - virtual void OnWindowHide() {} - - // Called when window is ready to show. - virtual void OnReadyToShow() {} - - // Called when window state changed. - virtual void OnWindowMaximize() {} - virtual void OnWindowUnmaximize() {} - virtual void OnWindowMinimize() {} - virtual void OnWindowRestore() {} - virtual void OnWindowResize() {} - virtual void OnWindowMove() {} - virtual void OnWindowMoved() {} - virtual void OnWindowScrollTouchBegin() {} - virtual void OnWindowScrollTouchEnd() {} - virtual void OnWindowSwipe(const std::string& direction) {} - virtual void OnWindowEnterFullScreen() {} - virtual void OnWindowLeaveFullScreen() {} - virtual void OnWindowEnterHtmlFullScreen() {} - virtual void OnWindowLeaveHtmlFullScreen() {} - - // Called when window message received - #if defined(OS_WIN) - virtual void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {} - #endif - - // Called when renderer is hung. - virtual void OnRendererUnresponsive() {} - - // Called when renderer recovers. - virtual void OnRendererResponsive() {} - - // Called on Windows when App Commands arrive (WM_APPCOMMAND) - virtual void OnExecuteWindowsCommand(const std::string& command_name) {} -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NATIVE_WINDOW_OBSERVER_H_ diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc deleted file mode 100644 index 52e643f3589eb..0000000000000 --- a/atom/browser/native_window_views.cc +++ /dev/null @@ -1,1290 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/native_window_views.h" - -#include -#include - -#include "atom/browser/ui/views/menu_bar.h" -#include "atom/browser/ui/views/menu_layout.h" -#include "atom/browser/window_list.h" -#include "atom/common/color_util.h" -#include "atom/common/draggable_region.h" -#include "atom/common/native_mate_converters/image_converter.h" -#include "atom/common/options_switches.h" -#include "base/strings/utf_string_conversions.h" -#include "brightray/browser/inspectable_web_contents.h" -#include "brightray/browser/inspectable_web_contents_view.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/native_web_keyboard_event.h" -#include "native_mate/dictionary.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/hit_test.h" -#include "ui/gfx/image/image.h" -#include "ui/views/background.h" -#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" -#include "ui/views/controls/webview/webview.h" -#include "ui/views/window/client_view.h" -#include "ui/views/widget/native_widget_private.h" -#include "ui/views/widget/widget.h" -#include "ui/wm/core/window_util.h" -#include "ui/wm/core/shadow_types.h" - -#if defined(USE_X11) -#include "atom/browser/browser.h" -#include "atom/browser/ui/views/global_menu_bar_x11.h" -#include "atom/browser/ui/views/frameless_view.h" -#include "atom/browser/ui/views/native_frame_view.h" -#include "atom/browser/ui/x/event_disabler.h" -#include "atom/browser/ui/x/window_state_watcher.h" -#include "atom/browser/ui/x/x_window_utils.h" -#include "base/strings/string_util.h" -#include "chrome/browser/ui/libgtk2ui/unity_service.h" -#include "ui/base/x/x11_util.h" -#include "ui/gfx/x/x11_types.h" -#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h" -#include "ui/views/window/native_frame_view.h" -#elif defined(OS_WIN) -#include "atom/browser/ui/views/win_frame_view.h" -#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h" -#include "skia/ext/skia_utils_win.h" -#include "ui/base/win/shell.h" -#include "ui/display/win/screen_win.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" -#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" -#endif - -namespace atom { - -namespace { - -// The menu bar height in pixels. -#if defined(OS_WIN) -const int kMenuBarHeight = 20; -#else -const int kMenuBarHeight = 25; -#endif - -#if defined(OS_WIN) -void FlipWindowStyle(HWND handle, bool on, DWORD flag) { - DWORD style = ::GetWindowLong(handle, GWL_STYLE); - if (on) - style |= flag; - else - style &= ~flag; - ::SetWindowLong(handle, GWL_STYLE, style); -} -#endif - -bool IsAltKey(const content::NativeWebKeyboardEvent& event) { - return event.windowsKeyCode == ui::VKEY_MENU; -} - -bool IsAltModifier(const content::NativeWebKeyboardEvent& event) { - typedef content::NativeWebKeyboardEvent::Modifiers Modifiers; - int modifiers = event.modifiers; - modifiers &= ~Modifiers::NumLockOn; - modifiers &= ~Modifiers::CapsLockOn; - return (modifiers == Modifiers::AltKey) || - (modifiers == (Modifiers::AltKey | Modifiers::IsLeft)) || - (modifiers == (Modifiers::AltKey | Modifiers::IsRight)); -} - -#if defined(USE_X11) -int SendClientEvent(XDisplay* display, ::Window window, const char* msg) { - XEvent event = {}; - event.xclient.type = ClientMessage; - event.xclient.send_event = True; - event.xclient.message_type = XInternAtom(display, msg, False); - event.xclient.window = window; - event.xclient.format = 32; - XSendEvent(display, DefaultRootWindow(display), False, - SubstructureRedirectMask | SubstructureNotifyMask, &event); - XFlush(display); - return True; -} -#endif - -class NativeWindowClientView : public views::ClientView { - public: - NativeWindowClientView(views::Widget* widget, - NativeWindowViews* contents_view) - : views::ClientView(widget, contents_view) { - } - virtual ~NativeWindowClientView() {} - - bool CanClose() override { - static_cast(contents_view())->RequestToClosePage(); - return false; - } - - private: - DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView); -}; - -} // namespace - -NativeWindowViews::NativeWindowViews( - brightray::InspectableWebContents* web_contents, - const mate::Dictionary& options, - NativeWindow* parent) - : NativeWindow(web_contents, options, parent), - window_(new views::Widget), - web_view_(inspectable_web_contents()->GetView()->GetView()), - menu_bar_autohide_(false), - menu_bar_visible_(false), - menu_bar_alt_pressed_(false), -#if defined(OS_WIN) - enabled_a11y_support_(false), - thick_frame_(true), -#endif - keyboard_event_handler_(new views::UnhandledKeyboardEventHandler), - disable_count_(0), - use_content_size_(false), - movable_(true), - resizable_(true), - maximizable_(true), - minimizable_(true), - fullscreenable_(true) { - options.Get(options::kTitle, &title_); - options.Get(options::kAutoHideMenuBar, &menu_bar_autohide_); - -#if defined(OS_WIN) - // On Windows we rely on the CanResize() to indicate whether window can be - // resized, and it should be set before window is created. - options.Get(options::kResizable, &resizable_); - options.Get(options::kMinimizable, &minimizable_); - options.Get(options::kMaximizable, &maximizable_); - - // Transparent window must not have thick frame. - options.Get("thickFrame", &thick_frame_); - if (transparent()) - thick_frame_ = false; -#endif - - if (enable_larger_than_screen()) - // We need to set a default maximum window size here otherwise Windows - // will not allow us to resize the window larger than scree. - // Setting directly to INT_MAX somehow doesn't work, so we just devide - // by 10, which should still be large enough. - SetContentSizeConstraints(extensions::SizeConstraints( - gfx::Size(), gfx::Size(INT_MAX / 10, INT_MAX / 10))); - - int width = 800, height = 600; - options.Get(options::kWidth, &width); - options.Get(options::kHeight, &height); - gfx::Rect bounds(0, 0, width, height); - widget_size_ = bounds.size(); - - window_->AddObserver(this); - - views::Widget::InitParams params; - params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; - params.bounds = bounds; - params.delegate = this; - params.type = views::Widget::InitParams::TYPE_WINDOW; - params.remove_standard_frame = !has_frame(); - - if (transparent()) - params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; - - // The given window is most likely not rectangular since it uses - // transparency and has no standard frame, don't show a shadow for it. - if (transparent() && !has_frame()) - params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE; - - bool focusable; - if (options.Get(options::kFocusable, &focusable) && !focusable) - params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; - -#if defined(OS_WIN) - if (parent) - params.parent = parent->GetNativeWindow(); - - params.native_widget = - new views::DesktopNativeWidgetAura(window_.get()); - atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin( - this, - window_.get(), - static_cast(params.native_widget)); - params.desktop_window_tree_host = atom_desktop_window_tree_host_win_; -#elif defined(USE_X11) - std::string name = Browser::Get()->GetName(); - // Set WM_WINDOW_ROLE. - params.wm_role_name = "browser-window"; - // Set WM_CLASS. - params.wm_class_name = base::ToLowerASCII(name); - params.wm_class_class = name; -#endif - - window_->Init(params); - - bool fullscreen = false; - options.Get(options::kFullscreen, &fullscreen); - - std::string window_type; - options.Get(options::kType, &window_type); - -#if defined(USE_X11) - // Start monitoring window states. - window_state_watcher_.reset(new WindowStateWatcher(this)); - - // Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set. - bool use_dark_theme = false; - if (options.Get(options::kDarkTheme, &use_dark_theme) && use_dark_theme) { - XDisplay* xdisplay = gfx::GetXDisplay(); - XChangeProperty(xdisplay, GetAcceleratedWidget(), - XInternAtom(xdisplay, "_GTK_THEME_VARIANT", False), - XInternAtom(xdisplay, "UTF8_STRING", False), - 8, PropModeReplace, - reinterpret_cast("dark"), - 4); - } - - // Before the window is mapped the SetWMSpecState can not work, so we have - // to manually set the _NET_WM_STATE. - std::vector<::Atom> state_atom_list; - bool skip_taskbar = false; - if (options.Get(options::kSkipTaskbar, &skip_taskbar) && skip_taskbar) { - state_atom_list.push_back(GetAtom("_NET_WM_STATE_SKIP_TASKBAR")); - } - - // Before the window is mapped, there is no SHOW_FULLSCREEN_STATE. - if (fullscreen) { - state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN")); - } - - if (parent) { - SetParentWindow(parent); - // Force using dialog type for child window. - window_type = "dialog"; - // Modal window needs the _NET_WM_STATE_MODAL hint. - if (is_modal()) - state_atom_list.push_back(GetAtom("_NET_WM_STATE_MODAL")); - } - - ui::SetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", "ATOM", - state_atom_list); - - // Set the _NET_WM_WINDOW_TYPE. - if (!window_type.empty()) - SetWindowType(GetAcceleratedWidget(), window_type); -#endif - - // Add web view. - SetLayoutManager(new MenuLayout(this, kMenuBarHeight)); - - AddChildView(web_view_); - -#if defined(OS_WIN) - if (!has_frame()) { - // Set Window style so that we get a minimize and maximize animation when - // frameless. - DWORD frame_style = WS_CAPTION; - if (resizable_) - frame_style |= WS_THICKFRAME; - if (minimizable_) - frame_style |= WS_MINIMIZEBOX; - if (maximizable_) - frame_style |= WS_MAXIMIZEBOX; - // We should not show a frame for transparent window. - if (!thick_frame_) - frame_style &= ~(WS_THICKFRAME | WS_CAPTION); - ::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style); - } - - LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE); - // Window without thick frame has to have WS_EX_COMPOSITED style. - if (!thick_frame_) - ex_style |= WS_EX_COMPOSITED; - if (window_type == "toolbar") - ex_style |= WS_EX_TOOLWINDOW; - ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style); -#endif - - // TODO(zcbenz): This was used to force using native frame on Windows 2003, we - // should check whether setting it in InitParams can work. - if (has_frame()) { - window_->set_frame_type(views::Widget::FrameType::FRAME_TYPE_FORCE_NATIVE); - window_->FrameTypeChanged(); - } - - gfx::Size size = bounds.size(); - if (has_frame() && - options.Get(options::kUseContentSize, &use_content_size_) && - use_content_size_) - size = ContentBoundsToWindowBounds(gfx::Rect(size)).size(); - - window_->CenterWindow(size); - Layout(); - -#if defined(OS_WIN) - // Save initial window state. - if (fullscreen) - last_window_state_ = ui::SHOW_STATE_FULLSCREEN; - else - last_window_state_ = ui::SHOW_STATE_NORMAL; - last_normal_bounds_ = GetBounds(); -#endif -} - -NativeWindowViews::~NativeWindowViews() { - window_->RemoveObserver(this); -} - -void NativeWindowViews::Close() { - if (!IsClosable()) { - WindowList::WindowCloseCancelled(this); - return; - } - - window_->Close(); -} - -void NativeWindowViews::CloseImmediately() { - window_->CloseNow(); -} - -void NativeWindowViews::Focus(bool focus) { - // For hidden window focus() should do nothing. - if (!IsVisible()) - return; - - if (focus) { -#if defined(OS_WIN) - window_->Activate(); -#elif defined(USE_X11) - // The "Activate" implementation of Chromium is not reliable on Linux. - ::Window window = GetAcceleratedWidget(); - XDisplay* xdisplay = gfx::GetXDisplay(); - SendClientEvent(xdisplay, window, "_NET_ACTIVE_WINDOW"); - XMapRaised(xdisplay, window); -#endif - } else { - window_->Deactivate(); - } -} - -bool NativeWindowViews::IsFocused() { - return window_->IsActive(); -} - -void NativeWindowViews::Show() { - if (is_modal() && NativeWindow::parent()) - static_cast(NativeWindow::parent())->SetEnabled(false); - - window_->native_widget_private()->ShowWithWindowState(GetRestoredState()); - - NotifyWindowShow(); - -#if defined(USE_X11) - if (global_menu_bar_) - global_menu_bar_->OnWindowMapped(); -#endif -} - -void NativeWindowViews::ShowInactive() { - window_->ShowInactive(); - - NotifyWindowShow(); - -#if defined(USE_X11) - if (global_menu_bar_) - global_menu_bar_->OnWindowMapped(); -#endif -} - -void NativeWindowViews::Hide() { - if (is_modal() && NativeWindow::parent()) - static_cast(NativeWindow::parent())->SetEnabled(true); - - window_->Hide(); - - NotifyWindowHide(); - -#if defined(USE_X11) - if (global_menu_bar_) - global_menu_bar_->OnWindowUnmapped(); -#endif -} - -bool NativeWindowViews::IsVisible() { - return window_->IsVisible(); -} - -bool NativeWindowViews::IsEnabled() { -#if defined(OS_WIN) - return ::IsWindowEnabled(GetAcceleratedWidget()); -#elif defined(USE_X11) - return !event_disabler_.get(); -#endif -} - -void NativeWindowViews::Maximize() { -#if defined(OS_WIN) - // For window without WS_THICKFRAME style, we can not call Maximize(). - if (!thick_frame_) { - restore_bounds_ = GetBounds(); - auto display = - display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition()); - SetBounds(display.work_area(), false); - return; - } -#endif - - if (IsVisible()) - window_->Maximize(); - else - window_->native_widget_private()->ShowWithWindowState( - ui::SHOW_STATE_MAXIMIZED); -} - -void NativeWindowViews::Unmaximize() { -#if defined(OS_WIN) - if (!thick_frame_) { - SetBounds(restore_bounds_, false); - return; - } -#endif - - window_->Restore(); -} - -bool NativeWindowViews::IsMaximized() { - return window_->IsMaximized(); -} - -void NativeWindowViews::Minimize() { - if (IsVisible()) - window_->Minimize(); - else - window_->native_widget_private()->ShowWithWindowState( - ui::SHOW_STATE_MINIMIZED); -} - -void NativeWindowViews::Restore() { - window_->Restore(); -} - -bool NativeWindowViews::IsMinimized() { - return window_->IsMinimized(); -} - -void NativeWindowViews::SetFullScreen(bool fullscreen) { - if (!IsFullScreenable()) - return; - -#if defined(OS_WIN) - // There is no native fullscreen state on Windows. - if (fullscreen) { - last_window_state_ = ui::SHOW_STATE_FULLSCREEN; - NotifyWindowEnterFullScreen(); - } else { - last_window_state_ = ui::SHOW_STATE_NORMAL; - NotifyWindowLeaveFullScreen(); - } - - // For window without WS_THICKFRAME style, we can not call SetFullscreen(). - if (!thick_frame_) { - if (fullscreen) { - restore_bounds_ = GetBounds(); - auto display = - display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition()); - SetBounds(display.bounds(), false); - } else { - SetBounds(restore_bounds_, false); - } - return; - } - - // We set the new value after notifying, so we can handle the size event - // correctly. - window_->SetFullscreen(fullscreen); -#else - if (IsVisible()) - window_->SetFullscreen(fullscreen); - else - window_->native_widget_private()->ShowWithWindowState( - ui::SHOW_STATE_FULLSCREEN); - - // Auto-hide menubar when in fullscreen. - if (fullscreen) - SetMenuBarVisibility(false); - else - SetMenuBarVisibility(!menu_bar_autohide_); -#endif -} - -bool NativeWindowViews::IsFullscreen() const { - return window_->IsFullscreen(); -} - -void NativeWindowViews::SetBounds(const gfx::Rect& bounds, bool animate) { -#if defined(USE_X11) - // On Linux the minimum and maximum size should be updated with window size - // when window is not resizable. - if (!resizable_) { - SetMaximumSize(bounds.size()); - SetMinimumSize(bounds.size()); - } -#endif - - window_->SetBounds(bounds); -} - -gfx::Rect NativeWindowViews::GetBounds() { -#if defined(OS_WIN) - if (IsMinimized()) - return window_->GetRestoredBounds(); -#endif - - return window_->GetWindowBoundsInScreen(); -} - -gfx::Rect NativeWindowViews::GetContentBounds() { - return web_view_->GetBoundsInScreen(); -} - -gfx::Size NativeWindowViews::GetContentSize() { -#if defined(OS_WIN) - if (IsMinimized()) - return NativeWindow::GetContentSize(); -#endif - - return web_view_->size(); -} - -void NativeWindowViews::SetContentSizeConstraints( - const extensions::SizeConstraints& size_constraints) { - NativeWindow::SetContentSizeConstraints(size_constraints); - // widget_delegate() is only available after Init() is called, we make use of - // this to determine whether native widget has initialized. - if (window_ && window_->widget_delegate()) - window_->OnSizeConstraintsChanged(); -#if defined(USE_X11) - if (resizable_) - old_size_constraints_ = size_constraints; -#endif -} - -void NativeWindowViews::SetResizable(bool resizable) { -#if defined(OS_WIN) - if (thick_frame_) - FlipWindowStyle(GetAcceleratedWidget(), resizable, WS_THICKFRAME); -#elif defined(USE_X11) - if (resizable != resizable_) { - // On Linux there is no "resizable" property of a window, we have to set - // both the minimum and maximum size to the window size to achieve it. - if (resizable) { - SetContentSizeConstraints(old_size_constraints_); - } else { - old_size_constraints_ = GetContentSizeConstraints(); - resizable_ = false; - gfx::Size content_size = GetContentSize(); - SetContentSizeConstraints( - extensions::SizeConstraints(content_size, content_size)); - } - } -#endif - - resizable_ = resizable; -} - -bool NativeWindowViews::IsResizable() { -#if defined(OS_WIN) - if (thick_frame_) { - return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME; - } else { - return CanResize(); - } -#else - return CanResize(); -#endif -} - -void NativeWindowViews::SetMovable(bool movable) { - movable_ = movable; -} - -bool NativeWindowViews::IsMovable() { -#if defined(OS_WIN) - return movable_; -#else - return true; // Not implemented on Linux. -#endif -} - -void NativeWindowViews::SetMinimizable(bool minimizable) { -#if defined(OS_WIN) - FlipWindowStyle(GetAcceleratedWidget(), minimizable, WS_MINIMIZEBOX); -#endif - minimizable_ = minimizable; -} - -bool NativeWindowViews::IsMinimizable() { -#if defined(OS_WIN) - return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_MINIMIZEBOX; -#else - return true; // Not implemented on Linux. -#endif -} - -void NativeWindowViews::SetMaximizable(bool maximizable) { -#if defined(OS_WIN) - FlipWindowStyle(GetAcceleratedWidget(), maximizable, WS_MAXIMIZEBOX); -#endif - maximizable_ = maximizable; -} - -bool NativeWindowViews::IsMaximizable() { -#if defined(OS_WIN) - return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_MAXIMIZEBOX; -#else - return true; // Not implemented on Linux. -#endif -} - -void NativeWindowViews::SetFullScreenable(bool fullscreenable) { - fullscreenable_ = fullscreenable; -} - -bool NativeWindowViews::IsFullScreenable() { - return fullscreenable_; -} - -void NativeWindowViews::SetClosable(bool closable) { -#if defined(OS_WIN) - HMENU menu = GetSystemMenu(GetAcceleratedWidget(), false); - if (closable) { - EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED); - } else { - EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); - } -#endif -} - -bool NativeWindowViews::IsClosable() { -#if defined(OS_WIN) - HMENU menu = GetSystemMenu(GetAcceleratedWidget(), false); - MENUITEMINFO info; - memset(&info, 0, sizeof(info)); - info.cbSize = sizeof(info); - info.fMask = MIIM_STATE; - if (!GetMenuItemInfo(menu, SC_CLOSE, false, &info)) { - return false; - } - return !(info.fState & MFS_DISABLED); -#elif defined(USE_X11) - return true; -#endif -} - -void NativeWindowViews::SetAlwaysOnTop(bool top) { - window_->SetAlwaysOnTop(top); -} - -bool NativeWindowViews::IsAlwaysOnTop() { - return window_->IsAlwaysOnTop(); -} - -void NativeWindowViews::Center() { - window_->CenterWindow(GetSize()); -} - -void NativeWindowViews::SetTitle(const std::string& title) { - title_ = title; - window_->UpdateWindowTitle(); -} - -std::string NativeWindowViews::GetTitle() { - return title_; -} - -void NativeWindowViews::FlashFrame(bool flash) { -#if defined(OS_WIN) - // The Chromium's implementation has a bug stopping flash. - if (!flash) { - FLASHWINFO fwi; - fwi.cbSize = sizeof(fwi); - fwi.hwnd = GetAcceleratedWidget(); - fwi.dwFlags = FLASHW_STOP; - fwi.uCount = 0; - FlashWindowEx(&fwi); - return; - } -#endif - window_->FlashFrame(flash); -} - -void NativeWindowViews::SetSkipTaskbar(bool skip) { -#if defined(OS_WIN) - base::win::ScopedComPtr taskbar; - if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL, - CLSCTX_INPROC_SERVER)) || - FAILED(taskbar->HrInit())) - return; - if (skip) - taskbar->DeleteTab(GetAcceleratedWidget()); - else - taskbar->AddTab(GetAcceleratedWidget()); -#elif defined(USE_X11) - SetWMSpecState(GetAcceleratedWidget(), skip, - GetAtom("_NET_WM_STATE_SKIP_TASKBAR")); -#endif -} - -void NativeWindowViews::SetKiosk(bool kiosk) { - SetFullScreen(kiosk); -} - -bool NativeWindowViews::IsKiosk() { - return IsFullscreen(); -} - -void NativeWindowViews::SetBackgroundColor(const std::string& color_name) { - // web views' background color. - SkColor background_color = ParseHexColor(color_name); - set_background(views::Background::CreateSolidBackground(background_color)); - -#if defined(OS_WIN) - // Set the background color of native window. - HBRUSH brush = CreateSolidBrush(skia::SkColorToCOLORREF(background_color)); - ULONG_PTR previous_brush = SetClassLongPtr( - GetAcceleratedWidget(), - GCLP_HBRBACKGROUND, - reinterpret_cast(brush)); - if (previous_brush) - DeleteObject((HBRUSH)previous_brush); -#endif -} - -void NativeWindowViews::SetHasShadow(bool has_shadow) { - wm::SetShadowType( - GetNativeWindow(), - has_shadow ? wm::SHADOW_TYPE_RECTANGULAR : wm::SHADOW_TYPE_NONE); -} - -bool NativeWindowViews::HasShadow() { - return wm::GetShadowType(GetNativeWindow()) != wm::SHADOW_TYPE_NONE; -} - -void NativeWindowViews::SetIgnoreMouseEvents(bool ignore) { -#if defined(OS_WIN) - LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE); - if (ignore) - ex_style |= (WS_EX_TRANSPARENT | WS_EX_LAYERED); - else - ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED); - ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style); -#elif defined(USE_X11) - if (ignore) { - XRectangle r = {0, 0, 1, 1}; - XShapeCombineRectangles(gfx::GetXDisplay(), GetAcceleratedWidget(), - ShapeInput, 0, 0, &r, 1, ShapeSet, YXBanded); - } else { - XShapeCombineMask(gfx::GetXDisplay(), GetAcceleratedWidget(), - ShapeInput, 0, 0, None, ShapeSet); - } -#endif -} - -void NativeWindowViews::SetContentProtection(bool enable) { -#if defined(OS_WIN) - DWORD affinity = enable ? WDA_MONITOR : WDA_NONE; - ::SetWindowDisplayAffinity(GetAcceleratedWidget(), affinity); -#endif -} - -void NativeWindowViews::SetFocusable(bool focusable) { -#if defined(OS_WIN) - LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE); - if (focusable) - ex_style &= ~WS_EX_NOACTIVATE; - else - ex_style |= WS_EX_NOACTIVATE; - ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style); - SetSkipTaskbar(!focusable); - Focus(false); -#endif -} - -void NativeWindowViews::SetMenu(AtomMenuModel* menu_model) { - if (menu_model == nullptr) { - // Remove accelerators - accelerator_table_.clear(); - GetFocusManager()->UnregisterAccelerators(this); - // and menu bar. -#if defined(USE_X11) - global_menu_bar_.reset(); -#endif - SetMenuBarVisibility(false); - menu_bar_.reset(); - return; - } - - RegisterAccelerators(menu_model); - -#if defined(USE_X11) - if (!global_menu_bar_ && ShouldUseGlobalMenuBar()) - global_menu_bar_.reset(new GlobalMenuBarX11(this)); - - // Use global application menu bar when possible. - if (global_menu_bar_ && global_menu_bar_->IsServerStarted()) { - global_menu_bar_->SetMenu(menu_model); - return; - } -#endif - - // Do not show menu bar in frameless window. - if (!has_frame()) - return; - - if (!menu_bar_) { - gfx::Size content_size = GetContentSize(); - menu_bar_.reset(new MenuBar); - menu_bar_->set_owned_by_client(); - - if (!menu_bar_autohide_) { - SetMenuBarVisibility(true); - if (use_content_size_) { - // Enlarge the size constraints for the menu. - extensions::SizeConstraints constraints = GetContentSizeConstraints(); - if (constraints.HasMinimumSize()) { - gfx::Size min_size = constraints.GetMinimumSize(); - min_size.set_height(min_size.height() + kMenuBarHeight); - constraints.set_minimum_size(min_size); - } - if (constraints.HasMaximumSize()) { - gfx::Size max_size = constraints.GetMaximumSize(); - max_size.set_height(max_size.height() + kMenuBarHeight); - constraints.set_maximum_size(max_size); - } - SetContentSizeConstraints(constraints); - - // Resize the window to make sure content size is not changed. - SetContentSize(content_size); - } - } - } - - menu_bar_->SetMenu(menu_model); - Layout(); -} - -void NativeWindowViews::SetParentWindow(NativeWindow* parent) { - NativeWindow::SetParentWindow(parent); - -#if defined(USE_X11) - XDisplay* xdisplay = gfx::GetXDisplay(); - XSetTransientForHint( - xdisplay, GetAcceleratedWidget(), - parent? parent->GetAcceleratedWidget() : DefaultRootWindow(xdisplay)); -#elif defined(OS_WIN) && defined(DEBUG) - // Should work, but does not, it seems that the views toolkit doesn't support - // reparenting on desktop. - if (parent) { - ::SetParent(GetAcceleratedWidget(), parent->GetAcceleratedWidget()); - views::Widget::ReparentNativeView(GetNativeWindow(), - parent->GetNativeWindow()); - wm::AddTransientChild(parent->GetNativeWindow(), GetNativeWindow()); - } else { - if (!GetNativeWindow()->parent()) - return; - ::SetParent(GetAcceleratedWidget(), NULL); - views::Widget::ReparentNativeView(GetNativeWindow(), nullptr); - wm::RemoveTransientChild(GetNativeWindow()->parent(), GetNativeWindow()); - } -#endif -} - -gfx::NativeWindow NativeWindowViews::GetNativeWindow() { - return window_->GetNativeWindow(); -} - -void NativeWindowViews::SetProgressBar(double progress) { -#if defined(OS_WIN) - taskbar_host_.SetProgressBar(GetAcceleratedWidget(), progress); -#elif defined(USE_X11) - if (unity::IsRunning()) { - unity::SetProgressFraction(progress); - } -#endif -} - -void NativeWindowViews::SetOverlayIcon(const gfx::Image& overlay, - const std::string& description) { -#if defined(OS_WIN) - taskbar_host_.SetOverlayIcon(GetAcceleratedWidget(), overlay, description); -#endif -} - -void NativeWindowViews::SetAutoHideMenuBar(bool auto_hide) { - menu_bar_autohide_ = auto_hide; -} - -bool NativeWindowViews::IsMenuBarAutoHide() { - return menu_bar_autohide_; -} - -void NativeWindowViews::SetMenuBarVisibility(bool visible) { - if (!menu_bar_ || menu_bar_visible_ == visible) - return; - - // Always show the accelerator when the auto-hide menu bar shows. - if (menu_bar_autohide_) - menu_bar_->SetAcceleratorVisibility(visible); - - menu_bar_visible_ = visible; - if (visible) { - DCHECK_EQ(child_count(), 1); - AddChildView(menu_bar_.get()); - } else { - DCHECK_EQ(child_count(), 2); - RemoveChildView(menu_bar_.get()); - } - - Layout(); -} - -bool NativeWindowViews::IsMenuBarVisible() { - return menu_bar_visible_; -} - -void NativeWindowViews::SetVisibleOnAllWorkspaces(bool visible) { - window_->SetVisibleOnAllWorkspaces(visible); -} - -bool NativeWindowViews::IsVisibleOnAllWorkspaces() { -#if defined(USE_X11) - // Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to - // determine whether the current window is visible on all workspaces. - XAtom sticky_atom = GetAtom("_NET_WM_STATE_STICKY"); - std::vector wm_states; - ui::GetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", &wm_states); - return std::find(wm_states.begin(), - wm_states.end(), sticky_atom) != wm_states.end(); -#endif - return false; -} - -gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() { - return GetNativeWindow()->GetHost()->GetAcceleratedWidget(); -} - -#if defined(OS_WIN) -void NativeWindowViews::SetIcon(HICON window_icon, HICON app_icon) { - // We are responsible for storing the images. - window_icon_ = base::win::ScopedHICON(CopyIcon(window_icon)); - app_icon_ = base::win::ScopedHICON(CopyIcon(app_icon)); - - HWND hwnd = GetAcceleratedWidget(); - SendMessage(hwnd, WM_SETICON, ICON_SMALL, - reinterpret_cast(window_icon_.get())); - SendMessage(hwnd, WM_SETICON, ICON_BIG, - reinterpret_cast(app_icon_.get())); -} -#elif defined(USE_X11) -void NativeWindowViews::SetIcon(const gfx::ImageSkia& icon) { - views::DesktopWindowTreeHostX11* tree_host = - views::DesktopWindowTreeHostX11::GetHostForXID(GetAcceleratedWidget()); - static_cast(tree_host)->SetWindowIcons( - icon, icon); -} -#endif - -void NativeWindowViews::SetEnabled(bool enable) { - // Handle multiple calls of SetEnabled correctly. - if (enable) { - --disable_count_; - if (disable_count_ != 0) - return; - } else { - ++disable_count_; - if (disable_count_ != 1) - return; - } - -#if defined(OS_WIN) - ::EnableWindow(GetAcceleratedWidget(), enable); -#elif defined(USE_X11) - views::DesktopWindowTreeHostX11* tree_host = - views::DesktopWindowTreeHostX11::GetHostForXID(GetAcceleratedWidget()); - if (enable) { - tree_host->RemoveEventRewriter(event_disabler_.get()); - event_disabler_.reset(); - } else { - event_disabler_.reset(new EventDisabler); - tree_host->AddEventRewriter(event_disabler_.get()); - } -#endif -} - -void NativeWindowViews::OnWidgetActivationChanged( - views::Widget* widget, bool active) { - if (widget != window_.get()) - return; - - // Post the notification to next tick. - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(active ? &NativeWindow::NotifyWindowFocus : - &NativeWindow::NotifyWindowBlur, - GetWeakPtr())); - - if (active && inspectable_web_contents() && - !inspectable_web_contents()->IsDevToolsViewShowing()) - web_contents()->Focus(); - - // Hide menu bar when window is blured. - if (!active && menu_bar_autohide_ && menu_bar_visible_) - SetMenuBarVisibility(false); -} - -void NativeWindowViews::OnWidgetBoundsChanged( - views::Widget* widget, const gfx::Rect& bounds) { - if (widget != window_.get()) - return; - - if (widget_size_ != bounds.size()) { - NotifyWindowResize(); - widget_size_ = bounds.size(); - } -} - -void NativeWindowViews::DeleteDelegate() { - if (is_modal() && NativeWindow::parent()) { - NativeWindowViews* parent = - static_cast(NativeWindow::parent()); - // Enable parent window after current window gets closed. - parent->SetEnabled(true); - // Focus on parent window. - parent->Focus(true); - } - - NotifyWindowClosed(); -} - -views::View* NativeWindowViews::GetInitiallyFocusedView() { - return inspectable_web_contents()->GetView()->GetWebView(); -} - -bool NativeWindowViews::CanResize() const { - return resizable_; -} - -bool NativeWindowViews::CanMaximize() const { - return resizable_ && maximizable_; -} - -bool NativeWindowViews::CanMinimize() const { -#if defined(OS_WIN) - return minimizable_; -#elif defined(USE_X11) - return true; -#endif -} - -base::string16 NativeWindowViews::GetWindowTitle() const { - return base::UTF8ToUTF16(title_); -} - -bool NativeWindowViews::ShouldHandleSystemCommands() const { - return true; -} - -views::Widget* NativeWindowViews::GetWidget() { - return window_.get(); -} - -const views::Widget* NativeWindowViews::GetWidget() const { - return window_.get(); -} - -views::View* NativeWindowViews::GetContentsView() { - return this; -} - -bool NativeWindowViews::ShouldDescendIntoChildForEventHandling( - gfx::NativeView child, - const gfx::Point& location) { - // App window should claim mouse events that fall within the draggable region. - if (draggable_region() && - draggable_region()->contains(location.x(), location.y())) - return false; - - // And the events on border for dragging resizable frameless window. - if (!has_frame() && CanResize()) { - FramelessView* frame = static_cast( - window_->non_client_view()->frame_view()); - return frame->ResizingBorderHitTest(location) == HTNOWHERE; - } - - return true; -} - -views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) { - return new NativeWindowClientView(widget, this); -} - -views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView( - views::Widget* widget) { -#if defined(OS_WIN) - WinFrameView* frame_view = new WinFrameView; - frame_view->Init(this, widget); - return frame_view; -#else - if (has_frame()) { - return new NativeFrameView(this, widget); - } else { - FramelessView* frame_view = new FramelessView; - frame_view->Init(this, widget); - return frame_view; - } -#endif -} - -void NativeWindowViews::OnWidgetMove() { - NotifyWindowMove(); -} - -gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds( - const gfx::Rect& bounds) { - if (!has_frame()) - return bounds; - - gfx::Rect window_bounds(bounds); -#if defined(OS_WIN) - HWND hwnd = GetAcceleratedWidget(); - gfx::Rect dpi_bounds = display::win::ScreenWin::DIPToScreenRect(hwnd, bounds); - window_bounds = display::win::ScreenWin::ScreenToDIPRect( - hwnd, - window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds)); -#endif - - if (menu_bar_ && menu_bar_visible_) { - window_bounds.set_y(window_bounds.y() - kMenuBarHeight); - window_bounds.set_height(window_bounds.height() + kMenuBarHeight); - } - return window_bounds; -} - -gfx::Rect NativeWindowViews::WindowBoundsToContentBounds( - const gfx::Rect& bounds) { - if (!has_frame()) - return bounds; - - gfx::Rect content_bounds(bounds); -#if defined(OS_WIN) - HWND hwnd = GetAcceleratedWidget(); - content_bounds.set_size( - display::win::ScreenWin::DIPToScreenSize(hwnd, content_bounds.size())); - RECT rect; - SetRectEmpty(&rect); - DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); - DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); - AdjustWindowRectEx(&rect, style, FALSE, ex_style); - content_bounds.set_width(content_bounds.width() - (rect.right - rect.left)); - content_bounds.set_height(content_bounds.height() - (rect.bottom - rect.top)); - content_bounds.set_size( - display::win::ScreenWin::ScreenToDIPSize(hwnd, content_bounds.size())); -#endif - - if (menu_bar_ && menu_bar_visible_) { - content_bounds.set_y(content_bounds.y() + kMenuBarHeight); - content_bounds.set_height(content_bounds.height() - kMenuBarHeight); - } - return content_bounds; -} - -void NativeWindowViews::HandleKeyboardEvent( - content::WebContents*, - const content::NativeWebKeyboardEvent& event) { - keyboard_event_handler_->HandleKeyboardEvent(event, GetFocusManager()); - - if (!menu_bar_) - return; - - // Show accelerator when "Alt" is pressed. - if (menu_bar_visible_ && IsAltKey(event)) - menu_bar_->SetAcceleratorVisibility( - event.type == blink::WebInputEvent::RawKeyDown); - - // Show the submenu when "Alt+Key" is pressed. - if (event.type == blink::WebInputEvent::RawKeyDown && !IsAltKey(event) && - IsAltModifier(event)) { - if (!menu_bar_visible_ && - (menu_bar_->GetAcceleratorIndex(event.windowsKeyCode) != -1)) - SetMenuBarVisibility(true); - menu_bar_->ActivateAccelerator(event.windowsKeyCode); - return; - } - - if (!menu_bar_autohide_) - return; - - // Toggle the menu bar only when a single Alt is released. - if (event.type == blink::WebInputEvent::RawKeyDown && IsAltKey(event)) { - // When a single Alt is pressed: - menu_bar_alt_pressed_ = true; - } else if (event.type == blink::WebInputEvent::KeyUp && IsAltKey(event) && - menu_bar_alt_pressed_) { - // When a single Alt is released right after a Alt is pressed: - menu_bar_alt_pressed_ = false; - SetMenuBarVisibility(!menu_bar_visible_); - } else { - // When any other keys except single Alt have been pressed/released: - menu_bar_alt_pressed_ = false; - } -} - -gfx::Size NativeWindowViews::GetMinimumSize() { - return NativeWindow::GetMinimumSize(); -} - -gfx::Size NativeWindowViews::GetMaximumSize() { - return NativeWindow::GetMaximumSize(); -} - -bool NativeWindowViews::AcceleratorPressed(const ui::Accelerator& accelerator) { - return accelerator_util::TriggerAcceleratorTableCommand( - &accelerator_table_, accelerator); -} - -void NativeWindowViews::RegisterAccelerators(AtomMenuModel* menu_model) { - // Clear previous accelerators. - views::FocusManager* focus_manager = GetFocusManager(); - accelerator_table_.clear(); - focus_manager->UnregisterAccelerators(this); - - // Register accelerators with focus manager. - accelerator_util::GenerateAcceleratorTable(&accelerator_table_, menu_model); - accelerator_util::AcceleratorTable::const_iterator iter; - for (iter = accelerator_table_.begin(); - iter != accelerator_table_.end(); - ++iter) { - focus_manager->RegisterAccelerator( - iter->first, ui::AcceleratorManager::kNormalPriority, this); - } -} - -ui::WindowShowState NativeWindowViews::GetRestoredState() { - if (IsMaximized()) - return ui::SHOW_STATE_MAXIMIZED; - if (IsFullscreen()) - return ui::SHOW_STATE_FULLSCREEN; - - return ui::SHOW_STATE_NORMAL; -} - -// static -NativeWindow* NativeWindow::Create( - brightray::InspectableWebContents* inspectable_web_contents, - const mate::Dictionary& options, - NativeWindow* parent) { - return new NativeWindowViews(inspectable_web_contents, options, parent); -} - -} // namespace atom diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h deleted file mode 100644 index 51b00e8831fdc..0000000000000 --- a/atom/browser/native_window_views.h +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_ -#define ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_ - -#include "atom/browser/native_window.h" - -#include -#include - -#include "atom/browser/ui/accelerator_util.h" -#include "ui/views/widget/widget_delegate.h" -#include "ui/views/widget/widget_observer.h" - -#if defined(OS_WIN) -#include "atom/browser/ui/win/message_handler_delegate.h" -#include "atom/browser/ui/win/taskbar_host.h" -#include "base/win/scoped_gdi_object.h" -#endif - -namespace views { -class UnhandledKeyboardEventHandler; -} - -namespace atom { - -class GlobalMenuBarX11; -class MenuBar; -class WindowStateWatcher; - -#if defined(OS_WIN) -class AtomDesktopWindowTreeHostWin; -#elif defined(USE_X11) -class EventDisabler; -#endif - -class NativeWindowViews : public NativeWindow, -#if defined(OS_WIN) - public MessageHandlerDelegate, -#endif - public views::WidgetDelegateView, - public views::WidgetObserver { - public: - NativeWindowViews(brightray::InspectableWebContents* inspectable_web_contents, - const mate::Dictionary& options, - NativeWindow* parent); - ~NativeWindowViews() override; - - // NativeWindow: - void Close() override; - void CloseImmediately() override; - void Focus(bool focus) override; - bool IsFocused() override; - void Show() override; - void ShowInactive() override; - void Hide() override; - bool IsVisible() override; - bool IsEnabled() override; - void Maximize() override; - void Unmaximize() override; - bool IsMaximized() override; - void Minimize() override; - void Restore() override; - bool IsMinimized() override; - void SetFullScreen(bool fullscreen) override; - bool IsFullscreen() const override; - void SetBounds(const gfx::Rect& bounds, bool animate) override; - gfx::Rect GetBounds() override; - gfx::Rect GetContentBounds() override; - gfx::Size GetContentSize() override; - void SetContentSizeConstraints( - const extensions::SizeConstraints& size_constraints) override; - void SetResizable(bool resizable) override; - bool IsResizable() override; - void SetMovable(bool movable) override; - bool IsMovable() override; - void SetMinimizable(bool minimizable) override; - bool IsMinimizable() override; - void SetMaximizable(bool maximizable) override; - bool IsMaximizable() override; - void SetFullScreenable(bool fullscreenable) override; - bool IsFullScreenable() override; - void SetClosable(bool closable) override; - bool IsClosable() override; - void SetAlwaysOnTop(bool top) override; - bool IsAlwaysOnTop() override; - void Center() override; - void SetTitle(const std::string& title) override; - std::string GetTitle() override; - void FlashFrame(bool flash) override; - void SetSkipTaskbar(bool skip) override; - void SetKiosk(bool kiosk) override; - bool IsKiosk() override; - void SetBackgroundColor(const std::string& color_name) override; - void SetHasShadow(bool has_shadow) override; - bool HasShadow() override; - void SetIgnoreMouseEvents(bool ignore) override; - void SetContentProtection(bool enable) override; - void SetFocusable(bool focusable) override; - void SetMenu(AtomMenuModel* menu_model) override; - void SetParentWindow(NativeWindow* parent) override; - gfx::NativeWindow GetNativeWindow() override; - void SetOverlayIcon(const gfx::Image& overlay, - const std::string& description) override; - void SetProgressBar(double value) override; - void SetAutoHideMenuBar(bool auto_hide) override; - bool IsMenuBarAutoHide() override; - void SetMenuBarVisibility(bool visible) override; - bool IsMenuBarVisible() override; - void SetVisibleOnAllWorkspaces(bool visible) override; - bool IsVisibleOnAllWorkspaces() override; - - gfx::AcceleratedWidget GetAcceleratedWidget() override; - -#if defined(OS_WIN) - void SetIcon(HICON small_icon, HICON app_icon); -#elif defined(USE_X11) - void SetIcon(const gfx::ImageSkia& icon); -#endif - - void SetEnabled(bool enable); - - views::Widget* widget() const { return window_.get(); } - -#if defined(OS_WIN) - TaskbarHost& taskbar_host() { return taskbar_host_; } -#endif - - private: - // views::WidgetObserver: - void OnWidgetActivationChanged( - views::Widget* widget, bool active) override; - void OnWidgetBoundsChanged( - views::Widget* widget, const gfx::Rect& bounds) override; - - // views::WidgetDelegate: - void DeleteDelegate() override; - views::View* GetInitiallyFocusedView() override; - bool CanResize() const override; - bool CanMaximize() const override; - bool CanMinimize() const override; - base::string16 GetWindowTitle() const override; - bool ShouldHandleSystemCommands() const override; - views::Widget* GetWidget() override; - const views::Widget* GetWidget() const override; - views::View* GetContentsView() override; - bool ShouldDescendIntoChildForEventHandling( - gfx::NativeView child, - const gfx::Point& location) override; - views::ClientView* CreateClientView(views::Widget* widget) override; - views::NonClientFrameView* CreateNonClientFrameView( - views::Widget* widget) override; - void OnWidgetMove() override; -#if defined(OS_WIN) - bool ExecuteWindowsCommand(int command_id) override; -#endif - -#if defined(OS_WIN) - // MessageHandlerDelegate: - bool PreHandleMSG( - UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override; - void HandleSizeEvent(WPARAM w_param, LPARAM l_param); -#endif - - // NativeWindow: - gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) override; - gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) override; - void HandleKeyboardEvent( - content::WebContents*, - const content::NativeWebKeyboardEvent& event) override; - - // views::View: - gfx::Size GetMinimumSize() override; - gfx::Size GetMaximumSize() override; - bool AcceleratorPressed(const ui::Accelerator& accelerator) override; - - // Register accelerators supported by the menu model. - void RegisterAccelerators(AtomMenuModel* menu_model); - - // Returns the restore state for the window. - ui::WindowShowState GetRestoredState(); - - std::unique_ptr window_; - views::View* web_view_; // Managed by inspectable_web_contents_. - - std::unique_ptr menu_bar_; - bool menu_bar_autohide_; - bool menu_bar_visible_; - bool menu_bar_alt_pressed_; - -#if defined(USE_X11) - std::unique_ptr global_menu_bar_; - - // Handles window state events. - std::unique_ptr window_state_watcher_; - - // To disable the mouse events. - std::unique_ptr event_disabler_; - - // The "resizable" flag on Linux is implemented by setting size constraints, - // we need to make sure size constraints are restored when window becomes - // resizable again. - extensions::SizeConstraints old_size_constraints_; -#elif defined(OS_WIN) - // Weak ref. - AtomDesktopWindowTreeHostWin* atom_desktop_window_tree_host_win_; - - ui::WindowShowState last_window_state_; - - // There's an issue with restore on Windows, that sometimes causes the Window - // to receive the wrong size (#2498). To circumvent that, we keep tabs on the - // size of the window while in the normal state (not maximized, minimized or - // fullscreen), so we restore it correctly. - gfx::Rect last_normal_bounds_; - - // last_normal_bounds_ may or may not require update on WM_MOVE. When a - // window is maximized, it is moved (WM_MOVE) to maximum size first and then - // sized (WM_SIZE). In this case, last_normal_bounds_ should not update. We - // keep last_normal_bounds_candidate_ as a candidate which will become valid - // last_normal_bounds_ if the moves are consecutive with no WM_SIZE event in - // between. - gfx::Rect last_normal_bounds_candidate_; - - bool consecutive_moves_; - - // In charge of running taskbar related APIs. - TaskbarHost taskbar_host_; - - // If true we have enabled a11y - bool enabled_a11y_support_; - - // Whether to show the WS_THICKFRAME style. - bool thick_frame_; - - // The bounds of window before maximize/fullscreen. - gfx::Rect restore_bounds_; - - // The icons of window and taskbar. - base::win::ScopedHICON window_icon_; - base::win::ScopedHICON app_icon_; -#endif - - // Handles unhandled keyboard messages coming back from the renderer process. - std::unique_ptr keyboard_event_handler_; - - // Map from accelerator to menu item's command id. - accelerator_util::AcceleratorTable accelerator_table_; - - // How many times the Disable has been called. - int disable_count_; - - bool use_content_size_; - bool movable_; - bool resizable_; - bool maximizable_; - bool minimizable_; - bool fullscreenable_; - std::string title_; - gfx::Size widget_size_; - - DISALLOW_COPY_AND_ASSIGN(NativeWindowViews); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NATIVE_WINDOW_VIEWS_H_ diff --git a/atom/browser/native_window_views_win.cc b/atom/browser/native_window_views_win.cc deleted file mode 100644 index bb6d9858f0455..0000000000000 --- a/atom/browser/native_window_views_win.cc +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/browser.h" -#include "atom/browser/native_window_views.h" -#include "content/public/browser/browser_accessibility_state.h" - -namespace atom { - -namespace { - -// Convert Win32 WM_APPCOMMANDS to strings. -const char* AppCommandToString(int command_id) { - switch (command_id) { - case APPCOMMAND_BROWSER_BACKWARD : return "browser-backward"; - case APPCOMMAND_BROWSER_FORWARD : return "browser-forward"; - case APPCOMMAND_BROWSER_REFRESH : return "browser-refresh"; - case APPCOMMAND_BROWSER_STOP : return "browser-stop"; - case APPCOMMAND_BROWSER_SEARCH : return "browser-search"; - case APPCOMMAND_BROWSER_FAVORITES : return "browser-favorites"; - case APPCOMMAND_BROWSER_HOME : return "browser-home"; - case APPCOMMAND_VOLUME_MUTE : return "volume-mute"; - case APPCOMMAND_VOLUME_DOWN : return "volume-down"; - case APPCOMMAND_VOLUME_UP : return "volume-up"; - case APPCOMMAND_MEDIA_NEXTTRACK : return "media-nexttrack"; - case APPCOMMAND_MEDIA_PREVIOUSTRACK : return "media-previoustrack"; - case APPCOMMAND_MEDIA_STOP : return "media-stop"; - case APPCOMMAND_MEDIA_PLAY_PAUSE : return "media-play_pause"; - case APPCOMMAND_LAUNCH_MAIL : return "launch-mail"; - case APPCOMMAND_LAUNCH_MEDIA_SELECT : return "launch-media-select"; - case APPCOMMAND_LAUNCH_APP1 : return "launch-app1"; - case APPCOMMAND_LAUNCH_APP2 : return "launch-app2"; - case APPCOMMAND_BASS_DOWN : return "bass-down"; - case APPCOMMAND_BASS_BOOST : return "bass-boost"; - case APPCOMMAND_BASS_UP : return "bass-up"; - case APPCOMMAND_TREBLE_DOWN : return "treble-down"; - case APPCOMMAND_TREBLE_UP : return "treble-up"; - case APPCOMMAND_MICROPHONE_VOLUME_MUTE : return "microphone-volume-mute"; - case APPCOMMAND_MICROPHONE_VOLUME_DOWN : return "microphone-volume-down"; - case APPCOMMAND_MICROPHONE_VOLUME_UP : return "microphone-volume-up"; - case APPCOMMAND_HELP : return "help"; - case APPCOMMAND_FIND : return "find"; - case APPCOMMAND_NEW : return "new"; - case APPCOMMAND_OPEN : return "open"; - case APPCOMMAND_CLOSE : return "close"; - case APPCOMMAND_SAVE : return "save"; - case APPCOMMAND_PRINT : return "print"; - case APPCOMMAND_UNDO : return "undo"; - case APPCOMMAND_REDO : return "redo"; - case APPCOMMAND_COPY : return "copy"; - case APPCOMMAND_CUT : return "cut"; - case APPCOMMAND_PASTE : return "paste"; - case APPCOMMAND_REPLY_TO_MAIL : return "reply-to-mail"; - case APPCOMMAND_FORWARD_MAIL : return "forward-mail"; - case APPCOMMAND_SEND_MAIL : return "send-mail"; - case APPCOMMAND_SPELL_CHECK : return "spell-check"; - case APPCOMMAND_MIC_ON_OFF_TOGGLE : return "mic-on-off-toggle"; - case APPCOMMAND_CORRECTION_LIST : return "correction-list"; - case APPCOMMAND_MEDIA_PLAY : return "media-play"; - case APPCOMMAND_MEDIA_PAUSE : return "media-pause"; - case APPCOMMAND_MEDIA_RECORD : return "media-record"; - case APPCOMMAND_MEDIA_FAST_FORWARD : return "media-fast-forward"; - case APPCOMMAND_MEDIA_REWIND : return "media-rewind"; - case APPCOMMAND_MEDIA_CHANNEL_UP : return "media-channel-up"; - case APPCOMMAND_MEDIA_CHANNEL_DOWN : return "media-channel-down"; - case APPCOMMAND_DELETE : return "delete"; - case APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE: - return "dictate-or-command-control-toggle"; - default: - return "unknown"; - } -} - -} // namespace - -bool NativeWindowViews::ExecuteWindowsCommand(int command_id) { - std::string command = AppCommandToString(command_id); - NotifyWindowExecuteWindowsCommand(command); - return false; -} - -bool NativeWindowViews::PreHandleMSG( - UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) { - NotifyWindowMessage(message, w_param, l_param); - - switch (message) { - // Screen readers send WM_GETOBJECT in order to get the accessibility - // object, so take this opportunity to push Chromium into accessible - // mode if it isn't already, always say we didn't handle the message - // because we still want Chromium to handle returning the actual - // accessibility object. - case WM_GETOBJECT: { - const DWORD obj_id = static_cast(l_param); - if (enabled_a11y_support_) return false; - - if (obj_id == OBJID_CLIENT) { - const auto axState = content::BrowserAccessibilityState::GetInstance(); - if (axState && !axState->IsAccessibleBrowser()) { - axState->OnScreenReaderDetected(); - enabled_a11y_support_ = true; - Browser::Get()->OnAccessibilitySupportChanged(); - } - } - - return false; - } - case WM_COMMAND: - // Handle thumbar button click message. - if (HIWORD(w_param) == THBN_CLICKED) - return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param)); - return false; - case WM_SIZE: { - consecutive_moves_ = false; - // Handle window state change. - HandleSizeEvent(w_param, l_param); - return false; - } - case WM_MOVING: { - if (!movable_) - ::GetWindowRect(GetAcceleratedWidget(), (LPRECT)l_param); - return false; - } - case WM_MOVE: { - if (last_window_state_ == ui::SHOW_STATE_NORMAL) { - if (consecutive_moves_) - last_normal_bounds_ = last_normal_bounds_candidate_; - last_normal_bounds_candidate_ = GetBounds(); - consecutive_moves_ = true; - } - return false; - } - default: - return false; - } -} - -void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) { - // Here we handle the WM_SIZE event in order to figure out what is the current - // window state and notify the user accordingly. - switch (w_param) { - case SIZE_MAXIMIZED: - last_window_state_ = ui::SHOW_STATE_MAXIMIZED; - NotifyWindowMaximize(); - break; - case SIZE_MINIMIZED: - last_window_state_ = ui::SHOW_STATE_MINIMIZED; - NotifyWindowMinimize(); - break; - case SIZE_RESTORED: - if (last_window_state_ == ui::SHOW_STATE_NORMAL) { - // Window was resized so we save it's new size. - last_normal_bounds_ = GetBounds(); - } else { - switch (last_window_state_) { - case ui::SHOW_STATE_MAXIMIZED: - last_window_state_ = ui::SHOW_STATE_NORMAL; - - // When the window is restored we resize it to the previous known - // normal size. - SetBounds(last_normal_bounds_, false); - - NotifyWindowUnmaximize(); - break; - case ui::SHOW_STATE_MINIMIZED: - if (IsFullscreen()) { - last_window_state_ = ui::SHOW_STATE_FULLSCREEN; - NotifyWindowEnterFullScreen(); - } else { - last_window_state_ = ui::SHOW_STATE_NORMAL; - - // When the window is restored we resize it to the previous known - // normal size. - SetBounds(last_normal_bounds_, false); - - NotifyWindowRestore(); - } - break; - } - } - break; - } -} - -} // namespace atom diff --git a/atom/browser/net/asar/asar_protocol_handler.cc b/atom/browser/net/asar/asar_protocol_handler.cc deleted file mode 100644 index ffa2b3c9f2887..0000000000000 --- a/atom/browser/net/asar/asar_protocol_handler.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/asar/asar_protocol_handler.h" - -#include "atom/browser/net/asar/url_request_asar_job.h" -#include "net/base/filename_util.h" -#include "net/base/net_errors.h" - -namespace asar { - -AsarProtocolHandler::AsarProtocolHandler( - const scoped_refptr& file_task_runner) - : file_task_runner_(file_task_runner) {} - -AsarProtocolHandler::~AsarProtocolHandler() { -} - -net::URLRequestJob* AsarProtocolHandler::MaybeCreateJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const { - base::FilePath full_path; - net::FileURLToFilePath(request->url(), &full_path); - auto* job = new URLRequestAsarJob(request, network_delegate); - job->Initialize(file_task_runner_, full_path); - return job; -} - -bool AsarProtocolHandler::IsSafeRedirectTarget(const GURL& location) const { - return false; -} - -} // namespace asar diff --git a/atom/browser/net/asar/asar_protocol_handler.h b/atom/browser/net/asar/asar_protocol_handler.h deleted file mode 100644 index e0cb74d5d1bf4..0000000000000 --- a/atom/browser/net/asar/asar_protocol_handler.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_ASAR_ASAR_PROTOCOL_HANDLER_H_ -#define ATOM_BROWSER_NET_ASAR_ASAR_PROTOCOL_HANDLER_H_ - -#include "base/memory/ref_counted.h" -#include "net/url_request/url_request_job_factory.h" - -namespace base { -class TaskRunner; -} - -namespace asar { - -class AsarProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { - public: - explicit AsarProtocolHandler( - const scoped_refptr& file_task_runner); - virtual ~AsarProtocolHandler(); - - // net::URLRequestJobFactory::ProtocolHandler: - net::URLRequestJob* MaybeCreateJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override; - bool IsSafeRedirectTarget(const GURL& location) const override; - - private: - const scoped_refptr file_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(AsarProtocolHandler); -}; - -} // namespace asar - -#endif // ATOM_BROWSER_NET_ASAR_ASAR_PROTOCOL_HANDLER_H_ diff --git a/atom/browser/net/asar/url_request_asar_job.cc b/atom/browser/net/asar/url_request_asar_job.cc deleted file mode 100644 index ad3a4c2724b39..0000000000000 --- a/atom/browser/net/asar/url_request_asar_job.cc +++ /dev/null @@ -1,346 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/asar/url_request_asar_job.h" - -#include -#include - -#include "atom/common/asar/archive.h" -#include "atom/common/asar/asar_util.h" -#include "atom/common/atom_constants.h" -#include "base/bind.h" -#include "base/files/file_util.h" -#include "base/strings/string_util.h" -#include "base/synchronization/lock.h" -#include "base/task_runner.h" -#include "net/base/file_stream.h" -#include "net/base/filename_util.h" -#include "net/base/io_buffer.h" -#include "net/base/load_flags.h" -#include "net/base/mime_util.h" -#include "net/base/net_errors.h" -#include "net/filter/filter.h" -#include "net/http/http_util.h" -#include "net/url_request/url_request_status.h" - -#if defined(OS_WIN) -#include "base/win/shortcut.h" -#endif - -namespace asar { - -URLRequestAsarJob::FileMetaInfo::FileMetaInfo() - : file_size(0), - mime_type_result(false), - file_exists(false), - is_directory(false) { -} - -URLRequestAsarJob::URLRequestAsarJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) - : net::URLRequestJob(request, network_delegate), - type_(TYPE_ERROR), - remaining_bytes_(0), - range_parse_result_(net::OK), - weak_ptr_factory_(this) {} - -URLRequestAsarJob::~URLRequestAsarJob() {} - -void URLRequestAsarJob::Initialize( - const scoped_refptr file_task_runner, - const base::FilePath& file_path) { - // Determine whether it is an asar file. - base::FilePath asar_path, relative_path; - if (!GetAsarArchivePath(file_path, &asar_path, &relative_path)) { - InitializeFileJob(file_task_runner, file_path); - return; - } - - std::shared_ptr archive = GetOrCreateAsarArchive(asar_path); - Archive::FileInfo file_info; - if (!archive || !archive->GetFileInfo(relative_path, &file_info)) { - type_ = TYPE_ERROR; - return; - } - - if (file_info.unpacked) { - base::FilePath real_path; - archive->CopyFileOut(relative_path, &real_path); - InitializeFileJob(file_task_runner, real_path); - return; - } - - InitializeAsarJob(file_task_runner, archive, relative_path, file_info); -} - -void URLRequestAsarJob::InitializeAsarJob( - const scoped_refptr file_task_runner, - std::shared_ptr archive, - const base::FilePath& file_path, - const Archive::FileInfo& file_info) { - type_ = TYPE_ASAR; - file_task_runner_ = file_task_runner; - stream_.reset(new net::FileStream(file_task_runner_)); - archive_ = archive; - file_path_ = file_path; - file_info_ = file_info; -} - -void URLRequestAsarJob::InitializeFileJob( - const scoped_refptr file_task_runner, - const base::FilePath& file_path) { - type_ = TYPE_FILE; - file_task_runner_ = file_task_runner; - stream_.reset(new net::FileStream(file_task_runner_)); - file_path_ = file_path; -} - -void URLRequestAsarJob::Start() { - if (type_ == TYPE_ASAR) { - remaining_bytes_ = static_cast(file_info_.size); - - int flags = base::File::FLAG_OPEN | - base::File::FLAG_READ | - base::File::FLAG_ASYNC; - int rv = stream_->Open(archive_->path(), flags, - base::Bind(&URLRequestAsarJob::DidOpen, - weak_ptr_factory_.GetWeakPtr())); - if (rv != net::ERR_IO_PENDING) - DidOpen(rv); - } else if (type_ == TYPE_FILE) { - auto* meta_info = new FileMetaInfo(); - file_task_runner_->PostTaskAndReply( - FROM_HERE, - base::Bind(&URLRequestAsarJob::FetchMetaInfo, file_path_, - base::Unretained(meta_info)), - base::Bind(&URLRequestAsarJob::DidFetchMetaInfo, - weak_ptr_factory_.GetWeakPtr(), - base::Owned(meta_info))); - } else { - NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, - net::ERR_FILE_NOT_FOUND)); - } -} - -void URLRequestAsarJob::Kill() { - stream_.reset(); - weak_ptr_factory_.InvalidateWeakPtrs(); - - URLRequestJob::Kill(); -} - -int URLRequestAsarJob::ReadRawData(net::IOBuffer* dest, int dest_size) { - if (remaining_bytes_ < dest_size) - dest_size = static_cast(remaining_bytes_); - - // If we should copy zero bytes because |remaining_bytes_| is zero, short - // circuit here. - if (!dest_size) - return 0; - - int rv = stream_->Read(dest, - dest_size, - base::Bind(&URLRequestAsarJob::DidRead, - weak_ptr_factory_.GetWeakPtr(), - make_scoped_refptr(dest))); - if (rv >= 0) { - remaining_bytes_ -= rv; - DCHECK_GE(remaining_bytes_, 0); - } - - return rv; -} - -bool URLRequestAsarJob::IsRedirectResponse(GURL* location, - int* http_status_code) { - if (type_ != TYPE_FILE) - return false; -#if defined(OS_WIN) - // Follow a Windows shortcut. - // We just resolve .lnk file, ignore others. - if (!base::LowerCaseEqualsASCII(file_path_.Extension(), ".lnk")) - return false; - - base::FilePath new_path = file_path_; - bool resolved; - resolved = base::win::ResolveShortcut(new_path, &new_path, NULL); - - // If shortcut is not resolved succesfully, do not redirect. - if (!resolved) - return false; - - *location = net::FilePathToFileURL(new_path); - *http_status_code = 301; - return true; -#else - return false; -#endif -} - -std::unique_ptr URLRequestAsarJob::SetupFilter() const { - // Bug 9936 - .svgz files needs to be decompressed. - return base::LowerCaseEqualsASCII(file_path_.Extension(), ".svgz") - ? net::Filter::GZipFactory() : nullptr; -} - -bool URLRequestAsarJob::GetMimeType(std::string* mime_type) const { - if (type_ == TYPE_ASAR) { - return net::GetMimeTypeFromFile(file_path_, mime_type); - } else { - if (meta_info_.mime_type_result) { - *mime_type = meta_info_.mime_type; - return true; - } - return false; - } -} - -void URLRequestAsarJob::SetExtraRequestHeaders( - const net::HttpRequestHeaders& headers) { - std::string range_header; - if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { - // This job only cares about the Range header. This method stashes the value - // for later use in DidOpen(), which is responsible for some of the range - // validation as well. NotifyStartError is not legal to call here since - // the job has not started. - std::vector ranges; - if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { - if (ranges.size() == 1) { - byte_range_ = ranges[0]; - } else { - range_parse_result_ = net::ERR_REQUEST_RANGE_NOT_SATISFIABLE; - } - } - } -} - -int URLRequestAsarJob::GetResponseCode() const { - // Request Job gets created only if path exists. - return 200; -} - -void URLRequestAsarJob::GetResponseInfo(net::HttpResponseInfo* info) { - std::string status("HTTP/1.1 200 OK"); - auto* headers = new net::HttpResponseHeaders(status); - - headers->AddHeader(atom::kCORSHeader); - info->headers = headers; -} - -void URLRequestAsarJob::FetchMetaInfo(const base::FilePath& file_path, - FileMetaInfo* meta_info) { - base::File::Info file_info; - meta_info->file_exists = base::GetFileInfo(file_path, &file_info); - if (meta_info->file_exists) { - meta_info->file_size = file_info.size; - meta_info->is_directory = file_info.is_directory; - } - // On Windows GetMimeTypeFromFile() goes to the registry. Thus it should be - // done in WorkerPool. - meta_info->mime_type_result = - net::GetMimeTypeFromFile(file_path, &meta_info->mime_type); -} - -void URLRequestAsarJob::DidFetchMetaInfo(const FileMetaInfo* meta_info) { - meta_info_ = *meta_info; - if (!meta_info_.file_exists || meta_info_.is_directory) { - DidOpen(net::ERR_FILE_NOT_FOUND); - return; - } - - int flags = base::File::FLAG_OPEN | - base::File::FLAG_READ | - base::File::FLAG_ASYNC; - int rv = stream_->Open(file_path_, flags, - base::Bind(&URLRequestAsarJob::DidOpen, - weak_ptr_factory_.GetWeakPtr())); - if (rv != net::ERR_IO_PENDING) - DidOpen(rv); -} - -void URLRequestAsarJob::DidOpen(int result) { - if (result != net::OK) { - NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, - result)); - return; - } - - if (range_parse_result_ != net::OK) { - NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, - range_parse_result_)); - return; - } - - if (type_ == TYPE_ASAR) { - int rv = stream_->Seek(file_info_.offset, - base::Bind(&URLRequestAsarJob::DidSeek, - weak_ptr_factory_.GetWeakPtr())); - if (rv != net::ERR_IO_PENDING) { - // stream_->Seek() failed, so pass an intentionally erroneous value - // into DidSeek(). - DidSeek(-1); - } - } else { - if (!byte_range_.ComputeBounds(meta_info_.file_size)) { - NotifyStartError( - net::URLRequestStatus(net::URLRequestStatus::FAILED, - net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); - return; - } - - remaining_bytes_ = byte_range_.last_byte_position() - - byte_range_.first_byte_position() + 1; - - if (remaining_bytes_ > 0 && byte_range_.first_byte_position() != 0) { - int rv = stream_->Seek(byte_range_.first_byte_position(), - base::Bind(&URLRequestAsarJob::DidSeek, - weak_ptr_factory_.GetWeakPtr())); - if (rv != net::ERR_IO_PENDING) { - // stream_->Seek() failed, so pass an intentionally erroneous value - // into DidSeek(). - DidSeek(-1); - } - } else { - // We didn't need to call stream_->Seek() at all, so we pass to DidSeek() - // the value that would mean seek success. This way we skip the code - // handling seek failure. - DidSeek(byte_range_.first_byte_position()); - } - } -} - -void URLRequestAsarJob::DidSeek(int64_t result) { - if (type_ == TYPE_ASAR) { - if (result != static_cast(file_info_.offset)) { - NotifyStartError( - net::URLRequestStatus(net::URLRequestStatus::FAILED, - net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); - return; - } - } else { - if (result != byte_range_.first_byte_position()) { - NotifyStartError( - net::URLRequestStatus(net::URLRequestStatus::FAILED, - net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); - return; - } - } - set_expected_content_size(remaining_bytes_); - NotifyHeadersComplete(); -} - -void URLRequestAsarJob::DidRead(scoped_refptr buf, int result) { - if (result >= 0) { - remaining_bytes_ -= result; - DCHECK_GE(remaining_bytes_, 0); - } - - buf = nullptr; - - ReadRawDataComplete(result); -} - -} // namespace asar diff --git a/atom/browser/net/asar/url_request_asar_job.h b/atom/browser/net/asar/url_request_asar_job.h deleted file mode 100644 index 8c32932fa5e53..0000000000000 --- a/atom/browser/net/asar/url_request_asar_job.h +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_ASAR_URL_REQUEST_ASAR_JOB_H_ -#define ATOM_BROWSER_NET_ASAR_URL_REQUEST_ASAR_JOB_H_ - -#include -#include - -#include "atom/browser/net/js_asker.h" -#include "atom/common/asar/archive.h" -#include "base/files/file_path.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "net/http/http_byte_range.h" -#include "net/url_request/url_request_job.h" - -namespace base { -class TaskRunner; -} - -namespace net { -class FileStream; -} - -namespace asar { - -// Createa a request job according to the file path. -net::URLRequestJob* CreateJobFromPath( - const base::FilePath& full_path, - net::URLRequest* request, - net::NetworkDelegate* network_delegate, - const scoped_refptr file_task_runner); - -class URLRequestAsarJob : public net::URLRequestJob { - public: - URLRequestAsarJob(net::URLRequest* request, - net::NetworkDelegate* network_delegate); - - void Initialize(const scoped_refptr file_task_runner, - const base::FilePath& file_path); - - protected: - virtual ~URLRequestAsarJob(); - - void InitializeAsarJob(const scoped_refptr file_task_runner, - std::shared_ptr archive, - const base::FilePath& file_path, - const Archive::FileInfo& file_info); - void InitializeFileJob(const scoped_refptr file_task_runner, - const base::FilePath& file_path); - - // net::URLRequestJob: - void Start() override; - void Kill() override; - int ReadRawData(net::IOBuffer* buf, int buf_size) override; - bool IsRedirectResponse(GURL* location, int* http_status_code) override; - std::unique_ptr SetupFilter() const override; - bool GetMimeType(std::string* mime_type) const override; - void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override; - int GetResponseCode() const override; - void GetResponseInfo(net::HttpResponseInfo* info) override; - - private: - // Meta information about the file. It's used as a member in the - // URLRequestFileJob and also passed between threads because disk access is - // necessary to obtain it. - struct FileMetaInfo { - FileMetaInfo(); - - // Size of the file. - int64_t file_size; - // Mime type associated with the file. - std::string mime_type; - // Result returned from GetMimeTypeFromFile(), i.e. flag showing whether - // obtaining of the mime type was successful. - bool mime_type_result; - // Flag showing whether the file exists. - bool file_exists; - // Flag showing whether the file name actually refers to a directory. - bool is_directory; - }; - - // Fetches file info on a background thread. - static void FetchMetaInfo(const base::FilePath& file_path, - FileMetaInfo* meta_info); - - // Callback after fetching file info on a background thread. - void DidFetchMetaInfo(const FileMetaInfo* meta_info); - - - // Callback after opening file on a background thread. - void DidOpen(int result); - - // Callback after seeking to the beginning of |byte_range_| in the file - // on a background thread. - void DidSeek(int64_t result); - - // Callback after data is asynchronously read from the file into |buf|. - void DidRead(scoped_refptr buf, int result); - - // The type of this job. - enum JobType { - TYPE_ERROR, - TYPE_ASAR, - TYPE_FILE, - }; - JobType type_; - - std::shared_ptr archive_; - base::FilePath file_path_; - Archive::FileInfo file_info_; - - std::unique_ptr stream_; - FileMetaInfo meta_info_; - scoped_refptr file_task_runner_; - - net::HttpByteRange byte_range_; - int64_t remaining_bytes_; - - net::Error range_parse_result_; - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(URLRequestAsarJob); -}; - -} // namespace asar - -#endif // ATOM_BROWSER_NET_ASAR_URL_REQUEST_ASAR_JOB_H_ diff --git a/atom/browser/net/atom_cert_verifier.cc b/atom/browser/net/atom_cert_verifier.cc deleted file mode 100644 index dd588b9501ce3..0000000000000 --- a/atom/browser/net/atom_cert_verifier.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/atom_cert_verifier.h" - -#include "atom/browser/browser.h" -#include "atom/common/native_mate_converters/net_converter.h" -#include "content/public/browser/browser_thread.h" -#include "net/base/net_errors.h" -#include "net/cert/crl_set.h" -#include "net/cert/x509_certificate.h" - -using content::BrowserThread; - -namespace atom { - -namespace { - -void OnResult( - net::CertVerifyResult* verify_result, - const net::CompletionCallback& callback, - bool result) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(callback, result ? net::OK : net::ERR_FAILED)); -} - -} // namespace - -AtomCertVerifier::AtomCertVerifier() - : default_cert_verifier_(net::CertVerifier::CreateDefault()) { -} - -AtomCertVerifier::~AtomCertVerifier() { -} - -void AtomCertVerifier::SetVerifyProc(const VerifyProc& proc) { - verify_proc_ = proc; -} - -int AtomCertVerifier::Verify( - net::X509Certificate* cert, - const std::string& hostname, - const std::string& ocsp_response, - int flags, - net::CRLSet* crl_set, - net::CertVerifyResult* verify_result, - const net::CompletionCallback& callback, - std::unique_ptr* out_req, - const net::BoundNetLog& net_log) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - if (verify_proc_.is_null()) - return default_cert_verifier_->Verify( - cert, hostname, ocsp_response, flags, crl_set, verify_result, callback, - out_req, net_log); - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(verify_proc_, hostname, make_scoped_refptr(cert), - base::Bind(OnResult, verify_result, callback))); - return net::ERR_IO_PENDING; -} - -bool AtomCertVerifier::SupportsOCSPStapling() { - return true; -} - -} // namespace atom diff --git a/atom/browser/net/atom_cert_verifier.h b/atom/browser/net/atom_cert_verifier.h deleted file mode 100644 index c8b4bf9290bbb..0000000000000 --- a/atom/browser/net/atom_cert_verifier.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_ -#define ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_ - -#include -#include - -#include "net/cert/cert_verifier.h" - -namespace atom { - -class AtomCertVerifier : public net::CertVerifier { - public: - AtomCertVerifier(); - virtual ~AtomCertVerifier(); - - using VerifyProc = - base::Callback, - const base::Callback&)>; - - void SetVerifyProc(const VerifyProc& proc); - - protected: - // net::CertVerifier: - int Verify(net::X509Certificate* cert, - const std::string& hostname, - const std::string& ocsp_response, - int flags, - net::CRLSet* crl_set, - net::CertVerifyResult* verify_result, - const net::CompletionCallback& callback, - std::unique_ptr* out_req, - const net::BoundNetLog& net_log) override; - bool SupportsOCSPStapling() override; - - private: - VerifyProc verify_proc_; - std::unique_ptr default_cert_verifier_; - - DISALLOW_COPY_AND_ASSIGN(AtomCertVerifier); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_ATOM_CERT_VERIFIER_H_ diff --git a/atom/browser/net/atom_network_delegate.cc b/atom/browser/net/atom_network_delegate.cc deleted file mode 100644 index 323342ca823dc..0000000000000 --- a/atom/browser/net/atom_network_delegate.cc +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/atom_network_delegate.h" - -#include - -#include "atom/common/native_mate_converters/net_converter.h" -#include "base/stl_util.h" -#include "base/strings/string_util.h" -#include "brightray/browser/net/devtools_network_transaction.h" -#include "content/public/browser/browser_thread.h" -#include "net/url_request/url_request.h" - -using brightray::DevToolsNetworkTransaction; -using content::BrowserThread; - -namespace atom { - -const char* ResourceTypeToString(content::ResourceType type) { - switch (type) { - case content::RESOURCE_TYPE_MAIN_FRAME: - return "mainFrame"; - case content::RESOURCE_TYPE_SUB_FRAME: - return "subFrame"; - case content::RESOURCE_TYPE_STYLESHEET: - return "stylesheet"; - case content::RESOURCE_TYPE_SCRIPT: - return "script"; - case content::RESOURCE_TYPE_IMAGE: - return "image"; - case content::RESOURCE_TYPE_OBJECT: - return "object"; - case content::RESOURCE_TYPE_XHR: - return "xhr"; - default: - return "other"; - } -} - -namespace { - -using ResponseHeadersContainer = - std::pair*, const std::string&>; - -void RunSimpleListener(const AtomNetworkDelegate::SimpleListener& listener, - std::unique_ptr details) { - return listener.Run(*(details.get())); -} - -void RunResponseListener( - const AtomNetworkDelegate::ResponseListener& listener, - std::unique_ptr details, - const AtomNetworkDelegate::ResponseCallback& callback) { - return listener.Run(*(details.get()), callback); -} - -// Test whether the URL of |request| matches |patterns|. -bool MatchesFilterCondition(net::URLRequest* request, - const URLPatterns& patterns) { - if (patterns.empty()) - return true; - - for (const auto& pattern : patterns) { - if (pattern.MatchesURL(request->url())) - return true; - } - return false; -} - -// Overloaded by multiple types to fill the |details| object. -void ToDictionary(base::DictionaryValue* details, net::URLRequest* request) { - FillRequestDetails(details, request); - details->SetInteger("id", request->identifier()); - details->SetDouble("timestamp", base::Time::Now().ToDoubleT() * 1000); - auto info = content::ResourceRequestInfo::ForRequest(request); - details->SetString("resourceType", - info ? ResourceTypeToString(info->GetResourceType()) - : "other"); -} - -void ToDictionary(base::DictionaryValue* details, - const net::HttpRequestHeaders& headers) { - std::unique_ptr dict(new base::DictionaryValue); - net::HttpRequestHeaders::Iterator it(headers); - while (it.GetNext()) - dict->SetString(it.name(), it.value()); - details->Set("requestHeaders", std::move(dict)); -} - -void ToDictionary(base::DictionaryValue* details, - const net::HttpResponseHeaders* headers) { - if (!headers) - return; - - std::unique_ptr dict(new base::DictionaryValue); - size_t iter = 0; - std::string key; - std::string value; - while (headers->EnumerateHeaderLines(&iter, &key, &value)) { - if (dict->HasKey(key)) { - base::ListValue* values = nullptr; - if (dict->GetList(key, &values)) - values->AppendString(value); - } else { - std::unique_ptr values(new base::ListValue); - values->AppendString(value); - dict->Set(key, std::move(values)); - } - } - details->Set("responseHeaders", std::move(dict)); - details->SetString("statusLine", headers->GetStatusLine()); - details->SetInteger("statusCode", headers->response_code()); -} - -void ToDictionary(base::DictionaryValue* details, const GURL& location) { - details->SetString("redirectURL", location.spec()); -} - -void ToDictionary(base::DictionaryValue* details, - const net::HostPortPair& host_port) { - if (host_port.host().empty()) - details->SetString("ip", host_port.host()); -} - -void ToDictionary(base::DictionaryValue* details, bool from_cache) { - details->SetBoolean("fromCache", from_cache); -} - -void ToDictionary(base::DictionaryValue* details, - const net::URLRequestStatus& status) { - details->SetString("error", net::ErrorToString(status.error())); -} - -// Helper function to fill |details| with arbitrary |args|. -template -void FillDetailsObject(base::DictionaryValue* details, Arg arg) { - ToDictionary(details, arg); -} - -template -void FillDetailsObject(base::DictionaryValue* details, Arg arg, Args... args) { - ToDictionary(details, arg); - FillDetailsObject(details, args...); -} - -// Fill the native types with the result from the response object. -void ReadFromResponseObject(const base::DictionaryValue& response, - GURL* new_location) { - std::string url; - if (response.GetString("redirectURL", &url)) - *new_location = GURL(url); -} - -void ReadFromResponseObject(const base::DictionaryValue& response, - net::HttpRequestHeaders* headers) { - const base::DictionaryValue* dict; - if (response.GetDictionary("requestHeaders", &dict)) { - headers->Clear(); - for (base::DictionaryValue::Iterator it(*dict); - !it.IsAtEnd(); - it.Advance()) { - std::string value; - if (it.value().GetAsString(&value)) - headers->SetHeader(it.key(), value); - } - } -} - -void ReadFromResponseObject(const base::DictionaryValue& response, - const ResponseHeadersContainer& container) { - const base::DictionaryValue* dict; - std::string status_line; - if (!response.GetString("statusLine", &status_line)) - status_line = container.second; - if (response.GetDictionary("responseHeaders", &dict)) { - auto headers = container.first; - *headers = new net::HttpResponseHeaders(""); - (*headers)->ReplaceStatusLine(status_line); - for (base::DictionaryValue::Iterator it(*dict); - !it.IsAtEnd(); - it.Advance()) { - const base::ListValue* list; - if (it.value().GetAsList(&list)) { - (*headers)->RemoveHeader(it.key()); - for (size_t i = 0; i < list->GetSize(); ++i) { - std::string value; - if (list->GetString(i, &value)) - (*headers)->AddHeader(it.key() + " : " + value); - } - } - } - } -} - -} // namespace - -AtomNetworkDelegate::AtomNetworkDelegate() { -} - -AtomNetworkDelegate::~AtomNetworkDelegate() { -} - -void AtomNetworkDelegate::SetSimpleListenerInIO( - SimpleEvent type, - const URLPatterns& patterns, - const SimpleListener& callback) { - if (callback.is_null()) - simple_listeners_.erase(type); - else - simple_listeners_[type] = { patterns, callback }; -} - -void AtomNetworkDelegate::SetResponseListenerInIO( - ResponseEvent type, - const URLPatterns& patterns, - const ResponseListener& callback) { - if (callback.is_null()) - response_listeners_.erase(type); - else - response_listeners_[type] = { patterns, callback }; -} - -void AtomNetworkDelegate::SetDevToolsNetworkEmulationClientId( - const std::string& client_id) { - base::AutoLock auto_lock(lock_); - client_id_ = client_id; -} - -int AtomNetworkDelegate::OnBeforeURLRequest( - net::URLRequest* request, - const net::CompletionCallback& callback, - GURL* new_url) { - if (!ContainsKey(response_listeners_, kOnBeforeRequest)) - return brightray::NetworkDelegate::OnBeforeURLRequest( - request, callback, new_url); - - return HandleResponseEvent(kOnBeforeRequest, request, callback, new_url); -} - -int AtomNetworkDelegate::OnBeforeSendHeaders( - net::URLRequest* request, - const net::CompletionCallback& callback, - net::HttpRequestHeaders* headers) { - std::string client_id; - { - base::AutoLock auto_lock(lock_); - client_id = client_id_; - } - - if (!client_id.empty()) - headers->SetHeader( - DevToolsNetworkTransaction::kDevToolsEmulateNetworkConditionsClientId, - client_id); - if (!ContainsKey(response_listeners_, kOnBeforeSendHeaders)) - return brightray::NetworkDelegate::OnBeforeSendHeaders( - request, callback, headers); - - return HandleResponseEvent( - kOnBeforeSendHeaders, request, callback, headers, *headers); -} - -void AtomNetworkDelegate::OnSendHeaders( - net::URLRequest* request, - const net::HttpRequestHeaders& headers) { - if (!ContainsKey(simple_listeners_, kOnSendHeaders)) { - brightray::NetworkDelegate::OnSendHeaders(request, headers); - return; - } - - HandleSimpleEvent(kOnSendHeaders, request, headers); -} - -int AtomNetworkDelegate::OnHeadersReceived( - net::URLRequest* request, - const net::CompletionCallback& callback, - const net::HttpResponseHeaders* original, - scoped_refptr* override, - GURL* allowed) { - if (!ContainsKey(response_listeners_, kOnHeadersReceived)) - return brightray::NetworkDelegate::OnHeadersReceived( - request, callback, original, override, allowed); - - return HandleResponseEvent( - kOnHeadersReceived, request, callback, - std::make_pair(override, original->GetStatusLine()), original); -} - -void AtomNetworkDelegate::OnBeforeRedirect(net::URLRequest* request, - const GURL& new_location) { - if (!ContainsKey(simple_listeners_, kOnBeforeRedirect)) { - brightray::NetworkDelegate::OnBeforeRedirect(request, new_location); - return; - } - - HandleSimpleEvent(kOnBeforeRedirect, request, new_location, - request->response_headers(), request->GetSocketAddress(), - request->was_cached()); -} - -void AtomNetworkDelegate::OnResponseStarted(net::URLRequest* request) { - if (!ContainsKey(simple_listeners_, kOnResponseStarted)) { - brightray::NetworkDelegate::OnResponseStarted(request); - return; - } - - if (request->status().status() != net::URLRequestStatus::SUCCESS) - return; - - HandleSimpleEvent(kOnResponseStarted, request, request->response_headers(), - request->was_cached()); -} - -void AtomNetworkDelegate::OnCompleted(net::URLRequest* request, bool started) { - // OnCompleted may happen before other events. - callbacks_.erase(request->identifier()); - - if (request->status().status() == net::URLRequestStatus::FAILED || - request->status().status() == net::URLRequestStatus::CANCELED) { - // Error event. - OnErrorOccurred(request, started); - return; - } else if (request->response_headers() && - net::HttpResponseHeaders::IsRedirectResponseCode( - request->response_headers()->response_code())) { - // Redirect event. - brightray::NetworkDelegate::OnCompleted(request, started); - return; - } - - if (!ContainsKey(simple_listeners_, kOnCompleted)) { - brightray::NetworkDelegate::OnCompleted(request, started); - return; - } - - HandleSimpleEvent(kOnCompleted, request, request->response_headers(), - request->was_cached()); -} - -void AtomNetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) { - callbacks_.erase(request->identifier()); -} - -void AtomNetworkDelegate::OnErrorOccurred( - net::URLRequest* request, bool started) { - if (!ContainsKey(simple_listeners_, kOnErrorOccurred)) { - brightray::NetworkDelegate::OnCompleted(request, started); - return; - } - - HandleSimpleEvent(kOnErrorOccurred, request, request->was_cached(), - request->status()); -} - -template -int AtomNetworkDelegate::HandleResponseEvent( - ResponseEvent type, - net::URLRequest* request, - const net::CompletionCallback& callback, - Out out, - Args... args) { - const auto& info = response_listeners_[type]; - if (!MatchesFilterCondition(request, info.url_patterns)) - return net::OK; - - std::unique_ptr details(new base::DictionaryValue); - FillDetailsObject(details.get(), request, args...); - - // The |request| could be destroyed before the |callback| is called. - callbacks_[request->identifier()] = callback; - - ResponseCallback response = - base::Bind(&AtomNetworkDelegate::OnListenerResultInUI, - base::Unretained(this), request->identifier(), out); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(RunResponseListener, info.listener, base::Passed(&details), - response)); - return net::ERR_IO_PENDING; -} - -template -void AtomNetworkDelegate::HandleSimpleEvent( - SimpleEvent type, net::URLRequest* request, Args... args) { - const auto& info = simple_listeners_[type]; - if (!MatchesFilterCondition(request, info.url_patterns)) - return; - - std::unique_ptr details(new base::DictionaryValue); - FillDetailsObject(details.get(), request, args...); - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(RunSimpleListener, info.listener, base::Passed(&details))); -} - -template -void AtomNetworkDelegate::OnListenerResultInIO( - uint64_t id, T out, std::unique_ptr response) { - // The request has been destroyed. - if (!ContainsKey(callbacks_, id)) - return; - - ReadFromResponseObject(*response.get(), out); - - bool cancel = false; - response->GetBoolean("cancel", &cancel); - callbacks_[id].Run(cancel ? net::ERR_BLOCKED_BY_CLIENT : net::OK); -} - -template -void AtomNetworkDelegate::OnListenerResultInUI( - uint64_t id, T out, const base::DictionaryValue& response) { - std::unique_ptr copy = response.CreateDeepCopy(); - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&AtomNetworkDelegate::OnListenerResultInIO, - base::Unretained(this), id, out, base::Passed(©))); -} - -} // namespace atom diff --git a/atom/browser/net/atom_network_delegate.h b/atom/browser/net/atom_network_delegate.h deleted file mode 100644 index 62653df0baebb..0000000000000 --- a/atom/browser/net/atom_network_delegate.h +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_ATOM_NETWORK_DELEGATE_H_ -#define ATOM_BROWSER_NET_ATOM_NETWORK_DELEGATE_H_ - -#include -#include -#include - -#include "brightray/browser/network_delegate.h" -#include "base/callback.h" -#include "base/synchronization/lock.h" -#include "base/values.h" -#include "extensions/common/url_pattern.h" -#include "net/base/net_errors.h" -#include "net/http/http_request_headers.h" -#include "net/http/http_response_headers.h" -#include "content/public/browser/resource_request_info.h" - -namespace extensions { -class URLPattern; -} - -namespace atom { - -using URLPatterns = std::set; - -const char* ResourceTypeToString(content::ResourceType type); - -class AtomNetworkDelegate : public brightray::NetworkDelegate { - public: - using ResponseCallback = base::Callback; - using SimpleListener = base::Callback; - using ResponseListener = base::Callback; - - enum SimpleEvent { - kOnSendHeaders, - kOnBeforeRedirect, - kOnResponseStarted, - kOnCompleted, - kOnErrorOccurred, - }; - - enum ResponseEvent { - kOnBeforeRequest, - kOnBeforeSendHeaders, - kOnHeadersReceived, - }; - - struct SimpleListenerInfo { - URLPatterns url_patterns; - SimpleListener listener; - }; - - struct ResponseListenerInfo { - URLPatterns url_patterns; - ResponseListener listener; - }; - - AtomNetworkDelegate(); - ~AtomNetworkDelegate() override; - - void SetSimpleListenerInIO(SimpleEvent type, - const URLPatterns& patterns, - const SimpleListener& callback); - void SetResponseListenerInIO(ResponseEvent type, - const URLPatterns& patterns, - const ResponseListener& callback); - - void SetDevToolsNetworkEmulationClientId(const std::string& client_id); - - protected: - // net::NetworkDelegate: - int OnBeforeURLRequest(net::URLRequest* request, - const net::CompletionCallback& callback, - GURL* new_url) override; - int OnBeforeSendHeaders(net::URLRequest* request, - const net::CompletionCallback& callback, - net::HttpRequestHeaders* headers) override; - void OnSendHeaders(net::URLRequest* request, - const net::HttpRequestHeaders& headers) override; - int OnHeadersReceived( - net::URLRequest* request, - const net::CompletionCallback& callback, - const net::HttpResponseHeaders* original_response_headers, - scoped_refptr* override_response_headers, - GURL* allowed_unsafe_redirect_url) override; - void OnBeforeRedirect(net::URLRequest* request, - const GURL& new_location) override; - void OnResponseStarted(net::URLRequest* request) override; - void OnCompleted(net::URLRequest* request, bool started) override; - void OnURLRequestDestroyed(net::URLRequest* request) override; - - private: - void OnErrorOccurred(net::URLRequest* request, bool started); - - template - void HandleSimpleEvent(SimpleEvent type, - net::URLRequest* request, - Args... args); - template - int HandleResponseEvent(ResponseEvent type, - net::URLRequest* request, - const net::CompletionCallback& callback, - Out out, - Args... args); - - // Deal with the results of Listener. - template - void OnListenerResultInIO( - uint64_t id, T out, std::unique_ptr response); - template - void OnListenerResultInUI( - uint64_t id, T out, const base::DictionaryValue& response); - - std::map simple_listeners_; - std::map response_listeners_; - std::map callbacks_; - - base::Lock lock_; - - // Client id for devtools network emulation. - std::string client_id_; - - DISALLOW_COPY_AND_ASSIGN(AtomNetworkDelegate); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_ATOM_NETWORK_DELEGATE_H_ diff --git a/atom/browser/net/atom_ssl_config_service.cc b/atom/browser/net/atom_ssl_config_service.cc deleted file mode 100644 index c306a8a391753..0000000000000 --- a/atom/browser/net/atom_ssl_config_service.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/atom_ssl_config_service.h" - -#include -#include - -#include "base/command_line.h" -#include "base/strings/string_split.h" -#include "atom/common/options_switches.h" -#include "content/public/browser/browser_thread.h" -#include "net/socket/ssl_client_socket.h" -#include "net/ssl/ssl_cipher_suite_names.h" - -namespace atom { - -namespace { - -uint16_t GetSSLProtocolVersion(const std::string& version_string) { - uint16_t version = 0; // Invalid - if (version_string == "tls1") - version = net::SSL_PROTOCOL_VERSION_TLS1; - else if (version_string == "tls1.1") - version = net::SSL_PROTOCOL_VERSION_TLS1_1; - else if (version_string == "tls1.2") - version = net::SSL_PROTOCOL_VERSION_TLS1_2; - return version; -} - -std::vector ParseCipherSuites( - const std::vector& cipher_strings) { - std::vector cipher_suites; - cipher_suites.reserve(cipher_strings.size()); - - for (auto& cipher_string : cipher_strings) { - uint16_t cipher_suite = 0; - if (!net::ParseSSLCipherString(cipher_string, &cipher_suite)) { - LOG(ERROR) << "Ignoring unrecognised cipher suite : " - << cipher_string; - continue; - } - cipher_suites.push_back(cipher_suite); - } - return cipher_suites; -} - -} // namespace - -AtomSSLConfigService::AtomSSLConfigService() { - auto cmd_line = base::CommandLine::ForCurrentProcess(); - if (cmd_line->HasSwitch(switches::kSSLVersionFallbackMin)) { - auto version_string = - cmd_line->GetSwitchValueASCII(switches::kSSLVersionFallbackMin); - config_.version_fallback_min = GetSSLProtocolVersion(version_string); - } - - if (cmd_line->HasSwitch(switches::kCipherSuiteBlacklist)) { - auto cipher_strings = base::SplitString( - cmd_line->GetSwitchValueASCII(switches::kCipherSuiteBlacklist), - ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - config_.disabled_cipher_suites = ParseCipherSuites(cipher_strings); - } -} - -AtomSSLConfigService::~AtomSSLConfigService() { -} - -void AtomSSLConfigService::GetSSLConfig(net::SSLConfig* config) { - *config = config_; -} - -} // namespace atom diff --git a/atom/browser/net/atom_ssl_config_service.h b/atom/browser/net/atom_ssl_config_service.h deleted file mode 100644 index 2e3ac4f6c5977..0000000000000 --- a/atom/browser/net/atom_ssl_config_service.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_ATOM_SSL_CONFIG_SERVICE_H_ -#define ATOM_BROWSER_NET_ATOM_SSL_CONFIG_SERVICE_H_ - -#include "net/ssl/ssl_config_service.h" - -namespace atom { - -class AtomSSLConfigService : public net::SSLConfigService { - public: - AtomSSLConfigService(); - ~AtomSSLConfigService() override; - - // net::SSLConfigService: - void GetSSLConfig(net::SSLConfig* config) override; - - private: - net::SSLConfig config_; - - DISALLOW_COPY_AND_ASSIGN(AtomSSLConfigService); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_ATOM_SSL_CONFIG_SERVICE_H_ diff --git a/atom/browser/net/atom_url_request_job_factory.cc b/atom/browser/net/atom_url_request_job_factory.cc deleted file mode 100644 index 7e2eb95149ca9..0000000000000 --- a/atom/browser/net/atom_url_request_job_factory.cc +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/atom_url_request_job_factory.h" - -#include "base/memory/ptr_util.h" -#include "base/stl_util.h" -#include "content/public/browser/browser_thread.h" -#include "net/base/load_flags.h" -#include "net/url_request/url_request.h" - -using content::BrowserThread; - -namespace atom { - -typedef net::URLRequestJobFactory::ProtocolHandler ProtocolHandler; - -AtomURLRequestJobFactory::AtomURLRequestJobFactory() {} - -AtomURLRequestJobFactory::~AtomURLRequestJobFactory() { - Clear(); -} - -bool AtomURLRequestJobFactory::SetProtocolHandler( - const std::string& scheme, - std::unique_ptr protocol_handler) { - if (!protocol_handler) { - auto it = protocol_handler_map_.find(scheme); - if (it == protocol_handler_map_.end()) - return false; - - delete it->second; - protocol_handler_map_.erase(it); - return true; - } - - if (ContainsKey(protocol_handler_map_, scheme)) - return false; - protocol_handler_map_[scheme] = protocol_handler.release(); - return true; -} - -bool AtomURLRequestJobFactory::InterceptProtocol( - const std::string& scheme, - std::unique_ptr protocol_handler) { - if (!ContainsKey(protocol_handler_map_, scheme) || - ContainsKey(original_protocols_, scheme)) - return false; - ProtocolHandler* original_protocol_handler = protocol_handler_map_[scheme]; - protocol_handler_map_[scheme] = protocol_handler.release(); - original_protocols_.set(scheme, base::WrapUnique(original_protocol_handler)); - return true; -} - -bool AtomURLRequestJobFactory::UninterceptProtocol(const std::string& scheme) { - if (!original_protocols_.contains(scheme)) - return false; - protocol_handler_map_[scheme] = - original_protocols_.take_and_erase(scheme).release(); - return true; -} - -ProtocolHandler* AtomURLRequestJobFactory::GetProtocolHandler( - const std::string& scheme) const { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - auto it = protocol_handler_map_.find(scheme); - if (it == protocol_handler_map_.end()) - return nullptr; - return it->second; -} - -bool AtomURLRequestJobFactory::HasProtocolHandler( - const std::string& scheme) const { - return ContainsKey(protocol_handler_map_, scheme); -} - -void AtomURLRequestJobFactory::Clear() { - STLDeleteValues(&protocol_handler_map_); -} - -net::URLRequestJob* AtomURLRequestJobFactory::MaybeCreateJobWithProtocolHandler( - const std::string& scheme, - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - auto it = protocol_handler_map_.find(scheme); - if (it == protocol_handler_map_.end()) - return nullptr; - return it->second->MaybeCreateJob(request, network_delegate); -} - -net::URLRequestJob* AtomURLRequestJobFactory::MaybeInterceptRedirect( - net::URLRequest* request, - net::NetworkDelegate* network_delegate, - const GURL& location) const { - return nullptr; -} - -net::URLRequestJob* AtomURLRequestJobFactory::MaybeInterceptResponse( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const { - return nullptr; -} - -bool AtomURLRequestJobFactory::IsHandledProtocol( - const std::string& scheme) const { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - return HasProtocolHandler(scheme) || - net::URLRequest::IsHandledProtocol(scheme); -} - -bool AtomURLRequestJobFactory::IsHandledURL(const GURL& url) const { - if (!url.is_valid()) { - // We handle error cases. - return true; - } - return IsHandledProtocol(url.scheme()); -} - -bool AtomURLRequestJobFactory::IsSafeRedirectTarget( - const GURL& location) const { - return IsHandledURL(location); -} - -} // namespace atom diff --git a/atom/browser/net/atom_url_request_job_factory.h b/atom/browser/net/atom_url_request_job_factory.h deleted file mode 100644 index 5b439c2f9cd8f..0000000000000 --- a/atom/browser/net/atom_url_request_job_factory.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_ATOM_URL_REQUEST_JOB_FACTORY_H_ -#define ATOM_BROWSER_NET_ATOM_URL_REQUEST_JOB_FACTORY_H_ - -#include -#include -#include -#include - -#include "base/containers/scoped_ptr_hash_map.h" -#include "net/url_request/url_request_job_factory.h" - -namespace atom { - -class AtomURLRequestJobFactory : public net::URLRequestJobFactory { - public: - AtomURLRequestJobFactory(); - virtual ~AtomURLRequestJobFactory(); - - // Sets the ProtocolHandler for a scheme. Returns true on success, false on - // failure (a ProtocolHandler already exists for |scheme|). On success, - // URLRequestJobFactory takes ownership of |protocol_handler|. - bool SetProtocolHandler(const std::string& scheme, - std::unique_ptr protocol_handler); - - // Intercepts the ProtocolHandler for a scheme. - bool InterceptProtocol( - const std::string& scheme, - std::unique_ptr protocol_handler); - bool UninterceptProtocol(const std::string& scheme); - - // Returns the protocol handler registered with scheme. - ProtocolHandler* GetProtocolHandler(const std::string& scheme) const; - - // Whether the protocol handler is registered by the job factory. - bool HasProtocolHandler(const std::string& scheme) const; - - // Clear all protocol handlers. - void Clear(); - - // URLRequestJobFactory implementation - net::URLRequestJob* MaybeCreateJobWithProtocolHandler( - const std::string& scheme, - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override; - net::URLRequestJob* MaybeInterceptRedirect( - net::URLRequest* request, - net::NetworkDelegate* network_delegate, - const GURL& location) const override; - net::URLRequestJob* MaybeInterceptResponse( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override; - bool IsHandledProtocol(const std::string& scheme) const override; - bool IsHandledURL(const GURL& url) const override; - bool IsSafeRedirectTarget(const GURL& location) const override; - - private: - using ProtocolHandlerMap = std::map; - - ProtocolHandlerMap protocol_handler_map_; - - // Map that stores the original protocols of schemes. - using OriginalProtocolsMap = base::ScopedPtrHashMap< - std::string, std::unique_ptr>; - // Can only be accessed in IO thread. - OriginalProtocolsMap original_protocols_; - - DISALLOW_COPY_AND_ASSIGN(AtomURLRequestJobFactory); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_ATOM_URL_REQUEST_JOB_FACTORY_H_ diff --git a/atom/browser/net/http_protocol_handler.cc b/atom/browser/net/http_protocol_handler.cc deleted file mode 100644 index cf5fc01c08849..0000000000000 --- a/atom/browser/net/http_protocol_handler.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/http_protocol_handler.h" - -#include "net/url_request/url_request_http_job.h" - -namespace atom { - -HttpProtocolHandler::HttpProtocolHandler(const std::string& scheme) - : scheme_(scheme) { -} - -HttpProtocolHandler::~HttpProtocolHandler() { -} - -net::URLRequestJob* HttpProtocolHandler::MaybeCreateJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const { - return net::URLRequestHttpJob::Factory(request, - network_delegate, - scheme_); -} - -} // namespace atom diff --git a/atom/browser/net/http_protocol_handler.h b/atom/browser/net/http_protocol_handler.h deleted file mode 100644 index 98085374175b1..0000000000000 --- a/atom/browser/net/http_protocol_handler.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_HTTP_PROTOCOL_HANDLER_H_ -#define ATOM_BROWSER_NET_HTTP_PROTOCOL_HANDLER_H_ - -#include - -#include "net/url_request/url_request_job_factory.h" - -namespace atom { - -class HttpProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { - public: - explicit HttpProtocolHandler(const std::string&); - virtual ~HttpProtocolHandler(); - - // net::URLRequestJobFactory::ProtocolHandler: - net::URLRequestJob* MaybeCreateJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override; - - private: - std::string scheme_; -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_HTTP_PROTOCOL_HANDLER_H_ diff --git a/atom/browser/net/js_asker.cc b/atom/browser/net/js_asker.cc deleted file mode 100644 index 67fb578650fbe..0000000000000 --- a/atom/browser/net/js_asker.cc +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/js_asker.h" - -#include - -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/v8_value_converter.h" - -namespace atom { - -namespace internal { - -namespace { - -// The callback which is passed to |handler|. -void HandlerCallback(const BeforeStartCallback& before_start, - const ResponseCallback& callback, - mate::Arguments* args) { - // If there is no argument passed then we failed. - v8::Local value; - if (!args->GetNext(&value)) { - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(callback, false, nullptr)); - return; - } - - // Give the job a chance to parse V8 value. - before_start.Run(args->isolate(), value); - - // Pass whatever user passed to the actaul request job. - V8ValueConverter converter; - v8::Local context = args->isolate()->GetCurrentContext(); - std::unique_ptr options(converter.FromV8Value(value, context)); - content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(callback, true, base::Passed(&options))); -} - -} // namespace - -void AskForOptions(v8::Isolate* isolate, - const JavaScriptHandler& handler, - std::unique_ptr request_details, - const BeforeStartCallback& before_start, - const ResponseCallback& callback) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - v8::Locker locker(isolate); - v8::HandleScope handle_scope(isolate); - v8::Local context = isolate->GetCurrentContext(); - v8::Context::Scope context_scope(context); - handler.Run( - *(request_details.get()), - mate::ConvertToV8(isolate, - base::Bind(&HandlerCallback, before_start, callback))); -} - -bool IsErrorOptions(base::Value* value, int* error) { - if (value->IsType(base::Value::TYPE_DICTIONARY)) { - base::DictionaryValue* dict = static_cast(value); - if (dict->GetInteger("error", error)) - return true; - } else if (value->IsType(base::Value::TYPE_INTEGER)) { - if (value->GetAsInteger(error)) - return true; - } - return false; -} - -} // namespace internal - -} // namespace atom diff --git a/atom/browser/net/js_asker.h b/atom/browser/net/js_asker.h deleted file mode 100644 index df64a21750494..0000000000000 --- a/atom/browser/net/js_asker.h +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_JS_ASKER_H_ -#define ATOM_BROWSER_NET_JS_ASKER_H_ - -#include "atom/common/native_mate_converters/net_converter.h" -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/values.h" -#include "content/public/browser/browser_thread.h" -#include "net/base/net_errors.h" -#include "net/http/http_response_headers.h" -#include "net/url_request/url_request_context_getter.h" -#include "net/url_request/url_request_job.h" -#include "v8/include/v8.h" - -namespace atom { - -using JavaScriptHandler = - base::Callback)>; - -namespace internal { - -using BeforeStartCallback = - base::Callback)>; -using ResponseCallback = - base::Callback options)>; - -// Ask handler for options in UI thread. -void AskForOptions(v8::Isolate* isolate, - const JavaScriptHandler& handler, - std::unique_ptr request_details, - const BeforeStartCallback& before_start, - const ResponseCallback& callback); - -// Test whether the |options| means an error. -bool IsErrorOptions(base::Value* value, int* error); - -} // namespace internal - -template -class JsAsker : public RequestJob { - public: - JsAsker(net::URLRequest* request, net::NetworkDelegate* network_delegate) - : RequestJob(request, network_delegate), weak_factory_(this) {} - - // Called by |CustomProtocolHandler| to store handler related information. - void SetHandlerInfo( - v8::Isolate* isolate, - net::URLRequestContextGetter* request_context_getter, - const JavaScriptHandler& handler) { - isolate_ = isolate; - request_context_getter_ = request_context_getter; - handler_ = handler; - } - - // Subclass should do initailze work here. - virtual void BeforeStartInUI(v8::Isolate*, v8::Local) {} - virtual void StartAsync(std::unique_ptr options) = 0; - - net::URLRequestContextGetter* request_context_getter() const { - return request_context_getter_; - } - - private: - // RequestJob: - void Start() override { - std::unique_ptr request_details( - new base::DictionaryValue); - FillRequestDetails(request_details.get(), RequestJob::request()); - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&internal::AskForOptions, - isolate_, - handler_, - base::Passed(&request_details), - base::Bind(&JsAsker::BeforeStartInUI, - weak_factory_.GetWeakPtr()), - base::Bind(&JsAsker::OnResponse, - weak_factory_.GetWeakPtr()))); - } - void GetResponseInfo(net::HttpResponseInfo* info) override { - info->headers = new net::HttpResponseHeaders(""); - } - - // Called when the JS handler has sent the response, we need to decide whether - // to start, or fail the job. - void OnResponse(bool success, std::unique_ptr value) { - int error = net::ERR_NOT_IMPLEMENTED; - if (success && value && !internal::IsErrorOptions(value.get(), &error)) { - StartAsync(std::move(value)); - } else { - RequestJob::NotifyStartError( - net::URLRequestStatus(net::URLRequestStatus::FAILED, error)); - } - } - - v8::Isolate* isolate_; - net::URLRequestContextGetter* request_context_getter_; - JavaScriptHandler handler_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(JsAsker); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_JS_ASKER_H_ diff --git a/atom/browser/net/url_request_async_asar_job.cc b/atom/browser/net/url_request_async_asar_job.cc deleted file mode 100644 index 942f06233e3de..0000000000000 --- a/atom/browser/net/url_request_async_asar_job.cc +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/url_request_async_asar_job.h" - -#include - -#include "atom/common/atom_constants.h" - -namespace atom { - -URLRequestAsyncAsarJob::URLRequestAsyncAsarJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) - : JsAsker(request, network_delegate) { -} - -void URLRequestAsyncAsarJob::StartAsync(std::unique_ptr options) { - base::FilePath::StringType file_path; - if (options->IsType(base::Value::TYPE_DICTIONARY)) { - static_cast(options.get())->GetString( - "path", &file_path); - } else if (options->IsType(base::Value::TYPE_STRING)) { - options->GetAsString(&file_path); - } - - if (file_path.empty()) { - NotifyStartError(net::URLRequestStatus( - net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED)); - } else { - asar::URLRequestAsarJob::Initialize( - content::BrowserThread::GetBlockingPool()-> - GetTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN), - base::FilePath(file_path)); - asar::URLRequestAsarJob::Start(); - } -} - -void URLRequestAsyncAsarJob::GetResponseInfo(net::HttpResponseInfo* info) { - std::string status("HTTP/1.1 200 OK"); - auto* headers = new net::HttpResponseHeaders(status); - - headers->AddHeader(kCORSHeader); - info->headers = headers; -} - -} // namespace atom diff --git a/atom/browser/net/url_request_async_asar_job.h b/atom/browser/net/url_request_async_asar_job.h deleted file mode 100644 index 032f3d9924132..0000000000000 --- a/atom/browser/net/url_request_async_asar_job.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_ -#define ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_ - -#include "atom/browser/net/asar/url_request_asar_job.h" -#include "atom/browser/net/js_asker.h" - -namespace atom { - -// Like URLRequestAsarJob, but asks the JavaScript handler for file path. -class URLRequestAsyncAsarJob : public JsAsker { - public: - URLRequestAsyncAsarJob(net::URLRequest*, net::NetworkDelegate*); - - // JsAsker: - void StartAsync(std::unique_ptr options) override; - - // URLRequestJob: - void GetResponseInfo(net::HttpResponseInfo* info) override; - - private: - DISALLOW_COPY_AND_ASSIGN(URLRequestAsyncAsarJob); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_URL_REQUEST_ASYNC_ASAR_JOB_H_ diff --git a/atom/browser/net/url_request_buffer_job.cc b/atom/browser/net/url_request_buffer_job.cc deleted file mode 100644 index 70f4603081746..0000000000000 --- a/atom/browser/net/url_request_buffer_job.cc +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/url_request_buffer_job.h" - -#include - -#include "atom/common/atom_constants.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "net/base/mime_util.h" -#include "net/base/net_errors.h" - -namespace atom { - -namespace { - -std::string GetExtFromURL(const GURL& url) { - std::string spec = url.spec(); - size_t index = spec.find_last_of('.'); - if (index == std::string::npos || index == spec.size()) - return std::string(); - return spec.substr(index + 1, spec.size() - index - 1); -} - -} // namespace - -URLRequestBufferJob::URLRequestBufferJob( - net::URLRequest* request, net::NetworkDelegate* network_delegate) - : JsAsker(request, network_delegate), - status_code_(net::HTTP_NOT_IMPLEMENTED) { -} - -void URLRequestBufferJob::StartAsync(std::unique_ptr options) { - const base::BinaryValue* binary = nullptr; - if (options->IsType(base::Value::TYPE_DICTIONARY)) { - base::DictionaryValue* dict = - static_cast(options.get()); - dict->GetString("mimeType", &mime_type_); - dict->GetString("charset", &charset_); - dict->GetBinary("data", &binary); - } else if (options->IsType(base::Value::TYPE_BINARY)) { - options->GetAsBinary(&binary); - } - - if (mime_type_.empty()) { - std::string ext = GetExtFromURL(request()->url()); -#if defined(OS_WIN) - net::GetWellKnownMimeTypeFromExtension(base::UTF8ToUTF16(ext), &mime_type_); -#else - net::GetWellKnownMimeTypeFromExtension(ext, &mime_type_); -#endif - } - - if (!binary) { - NotifyStartError(net::URLRequestStatus( - net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED)); - return; - } - - data_ = new base::RefCountedBytes( - reinterpret_cast(binary->GetBuffer()), - binary->GetSize()); - status_code_ = net::HTTP_OK; - net::URLRequestSimpleJob::Start(); -} - -void URLRequestBufferJob::GetResponseInfo(net::HttpResponseInfo* info) { - std::string status("HTTP/1.1 "); - status.append(base::IntToString(status_code_)); - status.append(" "); - status.append(net::GetHttpReasonPhrase(status_code_)); - status.append("\0\0", 2); - auto* headers = new net::HttpResponseHeaders(status); - - headers->AddHeader(kCORSHeader); - - if (!mime_type_.empty()) { - std::string content_type_header(net::HttpRequestHeaders::kContentType); - content_type_header.append(": "); - content_type_header.append(mime_type_); - headers->AddHeader(content_type_header); - } - - info->headers = headers; -} - -int URLRequestBufferJob::GetRefCountedData( - std::string* mime_type, - std::string* charset, - scoped_refptr* data, - const net::CompletionCallback& callback) const { - *mime_type = mime_type_; - *charset = charset_; - *data = data_; - return net::OK; -} - -} // namespace atom diff --git a/atom/browser/net/url_request_buffer_job.h b/atom/browser/net/url_request_buffer_job.h deleted file mode 100644 index 356ca9347f6f8..0000000000000 --- a/atom/browser/net/url_request_buffer_job.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_URL_REQUEST_BUFFER_JOB_H_ -#define ATOM_BROWSER_NET_URL_REQUEST_BUFFER_JOB_H_ - -#include - -#include "atom/browser/net/js_asker.h" -#include "base/memory/ref_counted_memory.h" -#include "net/http/http_status_code.h" -#include "net/url_request/url_request_simple_job.h" - -namespace atom { - -class URLRequestBufferJob : public JsAsker { - public: - URLRequestBufferJob(net::URLRequest*, net::NetworkDelegate*); - - // JsAsker: - void StartAsync(std::unique_ptr options) override; - - // URLRequestJob: - void GetResponseInfo(net::HttpResponseInfo* info) override; - - // URLRequestSimpleJob: - int GetRefCountedData(std::string* mime_type, - std::string* charset, - scoped_refptr* data, - const net::CompletionCallback& callback) const override; - - private: - std::string mime_type_; - std::string charset_; - scoped_refptr data_; - net::HttpStatusCode status_code_; - - DISALLOW_COPY_AND_ASSIGN(URLRequestBufferJob); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_URL_REQUEST_BUFFER_JOB_H_ diff --git a/atom/browser/net/url_request_fetch_job.cc b/atom/browser/net/url_request_fetch_job.cc deleted file mode 100644 index 5f11c674769fe..0000000000000 --- a/atom/browser/net/url_request_fetch_job.cc +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/url_request_fetch_job.h" - -#include -#include - -#include "base/memory/ptr_util.h" -#include "base/strings/string_util.h" -#include "native_mate/dictionary.h" -#include "net/base/io_buffer.h" -#include "net/base/net_errors.h" -#include "net/http/http_response_headers.h" -#include "net/url_request/url_fetcher.h" -#include "net/url_request/url_fetcher_response_writer.h" - -using content::BrowserThread; - -namespace atom { - -namespace { - -// Convert string to RequestType. -net::URLFetcher::RequestType GetRequestType(const std::string& raw) { - std::string method = base::ToUpperASCII(raw); - if (method.empty() || method == "GET") - return net::URLFetcher::GET; - else if (method == "POST") - return net::URLFetcher::POST; - else if (method == "HEAD") - return net::URLFetcher::HEAD; - else if (method == "DELETE") - return net::URLFetcher::DELETE_REQUEST; - else if (method == "PUT") - return net::URLFetcher::PUT; - else if (method == "PATCH") - return net::URLFetcher::PATCH; - else // Use "GET" as fallback. - return net::URLFetcher::GET; -} - -// Pipe the response writer back to URLRequestFetchJob. -class ResponsePiper : public net::URLFetcherResponseWriter { - public: - explicit ResponsePiper(URLRequestFetchJob* job) - : first_write_(true), job_(job) {} - - // net::URLFetcherResponseWriter: - int Initialize(const net::CompletionCallback& callback) override { - return net::OK; - } - int Write(net::IOBuffer* buffer, - int num_bytes, - const net::CompletionCallback& callback) override { - if (first_write_) { - // The URLFetcherResponseWriter doesn't have an event when headers have - // been read, so we have to emulate by hooking to first write event. - job_->HeadersCompleted(); - first_write_ = false; - } - return job_->DataAvailable(buffer, num_bytes, callback); - } - int Finish(const net::CompletionCallback& callback) override { - return net::OK; - } - - private: - bool first_write_; - URLRequestFetchJob* job_; - - DISALLOW_COPY_AND_ASSIGN(ResponsePiper); -}; - -} // namespace - -URLRequestFetchJob::URLRequestFetchJob( - net::URLRequest* request, net::NetworkDelegate* network_delegate) - : JsAsker(request, network_delegate), - pending_buffer_size_(0), - write_num_bytes_(0) { -} - -void URLRequestFetchJob::BeforeStartInUI( - v8::Isolate* isolate, v8::Local value) { - mate::Dictionary options; - if (!mate::ConvertFromV8(isolate, value, &options)) - return; - - // When |session| is set to |null| we use a new request context for fetch job. - // TODO(zcbenz): Handle the case when it is not null. - v8::Local session; - if (options.Get("session", &session) && session->IsNull()) { - // We have to create the URLRequestContextGetter on UI thread. - url_request_context_getter_ = new brightray::URLRequestContextGetter( - this, nullptr, nullptr, base::FilePath(), true, - BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO), - BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE), - nullptr, content::URLRequestInterceptorScopedVector()); - } -} - -void URLRequestFetchJob::StartAsync(std::unique_ptr options) { - if (!options->IsType(base::Value::TYPE_DICTIONARY)) { - NotifyStartError(net::URLRequestStatus( - net::URLRequestStatus::FAILED, net::ERR_NOT_IMPLEMENTED)); - return; - } - - std::string url, method, referrer; - base::DictionaryValue* upload_data = nullptr; - base::DictionaryValue* dict = - static_cast(options.get()); - dict->GetString("url", &url); - dict->GetString("method", &method); - dict->GetString("referrer", &referrer); - dict->GetDictionary("uploadData", &upload_data); - - // Check if URL is valid. - GURL formated_url(url); - if (!formated_url.is_valid()) { - NotifyStartError(net::URLRequestStatus( - net::URLRequestStatus::FAILED, net::ERR_INVALID_URL)); - return; - } - - // Use |request|'s method if |method| is not specified. - net::URLFetcher::RequestType request_type; - if (method.empty()) - request_type = GetRequestType(request()->method()); - else - request_type = GetRequestType(method); - - fetcher_ = net::URLFetcher::Create(formated_url, request_type, this); - fetcher_->SaveResponseWithWriter(base::WrapUnique(new ResponsePiper(this))); - - // A request context getter is passed by the user. - if (url_request_context_getter_) - fetcher_->SetRequestContext(url_request_context_getter_.get()); - else - fetcher_->SetRequestContext(request_context_getter()); - - // Use |request|'s referrer if |referrer| is not specified. - if (referrer.empty()) - fetcher_->SetReferrer(request()->referrer()); - else - fetcher_->SetReferrer(referrer); - - // Set the data needed for POSTs. - if (upload_data && request_type == net::URLFetcher::POST) { - std::string content_type, data; - upload_data->GetString("contentType", &content_type); - upload_data->GetString("data", &data); - fetcher_->SetUploadData(content_type, data); - } - - // Use |request|'s headers. - fetcher_->SetExtraRequestHeaders( - request()->extra_request_headers().ToString()); - - fetcher_->Start(); -} - -void URLRequestFetchJob::HeadersCompleted() { - response_info_.reset(new net::HttpResponseInfo); - response_info_->headers = fetcher_->GetResponseHeaders(); - NotifyHeadersComplete(); -} - -int URLRequestFetchJob::DataAvailable(net::IOBuffer* buffer, - int num_bytes, - const net::CompletionCallback& callback) { - // When pending_buffer_ is empty, there's no ReadRawData() operation waiting - // for IO completion, we have to save the parameters until the request is - // ready to read data. - if (!pending_buffer_.get()) { - write_buffer_ = buffer; - write_num_bytes_ = num_bytes; - write_callback_ = callback; - return net::ERR_IO_PENDING; - } - - // Write data to the pending buffer and clear them after the writing. - int bytes_read = BufferCopy(buffer, num_bytes, - pending_buffer_.get(), pending_buffer_size_); - ClearPendingBuffer(); - ReadRawDataComplete(bytes_read); - return bytes_read; -} - -void URLRequestFetchJob::Kill() { - JsAsker::Kill(); - fetcher_.reset(); -} - -int URLRequestFetchJob::ReadRawData(net::IOBuffer* dest, int dest_size) { - if (GetResponseCode() == 204) { - request()->set_received_response_content_length(prefilter_bytes_read()); - return net::OK; - } - - // When write_buffer_ is empty, there is no data valable yet, we have to save - // the dest buffer util DataAvailable. - if (!write_buffer_.get()) { - pending_buffer_ = dest; - pending_buffer_size_ = dest_size; - return net::ERR_IO_PENDING; - } - - // Read from the write buffer and clear them after reading. - int bytes_read = BufferCopy(write_buffer_.get(), write_num_bytes_, - dest, dest_size); - net::CompletionCallback write_callback = write_callback_; - ClearWriteBuffer(); - write_callback.Run(bytes_read); - return bytes_read; -} - -bool URLRequestFetchJob::GetMimeType(std::string* mime_type) const { - if (!response_info_ || !response_info_->headers) - return false; - - return response_info_->headers->GetMimeType(mime_type); -} - -void URLRequestFetchJob::GetResponseInfo(net::HttpResponseInfo* info) { - if (response_info_) - *info = *response_info_; -} - -int URLRequestFetchJob::GetResponseCode() const { - if (!response_info_ || !response_info_->headers) - return -1; - - return response_info_->headers->response_code(); -} - -void URLRequestFetchJob::OnURLFetchComplete(const net::URLFetcher* source) { - if (!response_info_) { - // Since we notify header completion only after first write there will be - // no response object constructed for http respones with no content 204. - // We notify header completion here. - HeadersCompleted(); - return; - } - - ClearPendingBuffer(); - ClearWriteBuffer(); - - if (fetcher_->GetStatus().is_success()) - ReadRawDataComplete(0); - else - NotifyStartError(fetcher_->GetStatus()); -} - -int URLRequestFetchJob::BufferCopy(net::IOBuffer* source, int num_bytes, - net::IOBuffer* target, int target_size) { - int bytes_written = std::min(num_bytes, target_size); - memcpy(target->data(), source->data(), bytes_written); - return bytes_written; -} - -void URLRequestFetchJob::ClearPendingBuffer() { - pending_buffer_ = nullptr; - pending_buffer_size_ = 0; -} - -void URLRequestFetchJob::ClearWriteBuffer() { - write_buffer_ = nullptr; - write_num_bytes_ = 0; - write_callback_.Reset(); -} - -} // namespace atom diff --git a/atom/browser/net/url_request_fetch_job.h b/atom/browser/net/url_request_fetch_job.h deleted file mode 100644 index 906ba68d39651..0000000000000 --- a/atom/browser/net/url_request_fetch_job.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_ -#define ATOM_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_ - -#include - -#include "atom/browser/net/js_asker.h" -#include "browser/url_request_context_getter.h" -#include "net/url_request/url_fetcher_delegate.h" - -namespace atom { - -class URLRequestFetchJob : public JsAsker, - public net::URLFetcherDelegate, - public brightray::URLRequestContextGetter::Delegate { - public: - URLRequestFetchJob(net::URLRequest*, net::NetworkDelegate*); - - // Called by response writer. - void HeadersCompleted(); - int DataAvailable(net::IOBuffer* buffer, - int num_bytes, - const net::CompletionCallback& callback); - - protected: - // JsAsker: - void BeforeStartInUI(v8::Isolate*, v8::Local) override; - void StartAsync(std::unique_ptr options) override; - - // net::URLRequestJob: - void Kill() override; - int ReadRawData(net::IOBuffer* buf, int buf_size) override; - bool GetMimeType(std::string* mime_type) const override; - void GetResponseInfo(net::HttpResponseInfo* info) override; - int GetResponseCode() const override; - - // net::URLFetcherDelegate: - void OnURLFetchComplete(const net::URLFetcher* source) override; - - private: - int BufferCopy(net::IOBuffer* source, int num_bytes, - net::IOBuffer* target, int target_size); - void ClearPendingBuffer(); - void ClearWriteBuffer(); - - scoped_refptr url_request_context_getter_; - std::unique_ptr fetcher_; - std::unique_ptr response_info_; - - // Saved arguments passed to ReadRawData. - scoped_refptr pending_buffer_; - int pending_buffer_size_; - - // Saved arguments passed to DataAvailable. - scoped_refptr write_buffer_; - int write_num_bytes_; - net::CompletionCallback write_callback_; - - DISALLOW_COPY_AND_ASSIGN(URLRequestFetchJob); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_URL_REQUEST_FETCH_JOB_H_ diff --git a/atom/browser/net/url_request_string_job.cc b/atom/browser/net/url_request_string_job.cc deleted file mode 100644 index abec345e63d58..0000000000000 --- a/atom/browser/net/url_request_string_job.cc +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/net/url_request_string_job.h" - -#include - -#include "atom/common/atom_constants.h" -#include "net/base/net_errors.h" - -namespace atom { - -URLRequestStringJob::URLRequestStringJob( - net::URLRequest* request, net::NetworkDelegate* network_delegate) - : JsAsker(request, network_delegate) { -} - -void URLRequestStringJob::StartAsync(std::unique_ptr options) { - if (options->IsType(base::Value::TYPE_DICTIONARY)) { - base::DictionaryValue* dict = - static_cast(options.get()); - dict->GetString("mimeType", &mime_type_); - dict->GetString("charset", &charset_); - dict->GetString("data", &data_); - } else if (options->IsType(base::Value::TYPE_STRING)) { - options->GetAsString(&data_); - } - net::URLRequestSimpleJob::Start(); -} - -void URLRequestStringJob::GetResponseInfo(net::HttpResponseInfo* info) { - std::string status("HTTP/1.1 200 OK"); - auto* headers = new net::HttpResponseHeaders(status); - - headers->AddHeader(kCORSHeader); - - if (!mime_type_.empty()) { - std::string content_type_header(net::HttpRequestHeaders::kContentType); - content_type_header.append(": "); - content_type_header.append(mime_type_); - headers->AddHeader(content_type_header); - } - - info->headers = headers; -} - -int URLRequestStringJob::GetData( - std::string* mime_type, - std::string* charset, - std::string* data, - const net::CompletionCallback& callback) const { - *mime_type = mime_type_; - *charset = charset_; - *data = data_; - return net::OK; -} - -} // namespace atom diff --git a/atom/browser/net/url_request_string_job.h b/atom/browser/net/url_request_string_job.h deleted file mode 100644 index 474473cca87d5..0000000000000 --- a/atom/browser/net/url_request_string_job.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_ -#define ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_ - -#include - -#include "atom/browser/net/js_asker.h" -#include "net/url_request/url_request_simple_job.h" - -namespace atom { - -class URLRequestStringJob : public JsAsker { - public: - URLRequestStringJob(net::URLRequest*, net::NetworkDelegate*); - - // JsAsker: - void StartAsync(std::unique_ptr options) override; - - // URLRequestJob: - void GetResponseInfo(net::HttpResponseInfo* info) override; - - // URLRequestSimpleJob: - int GetData(std::string* mime_type, - std::string* charset, - std::string* data, - const net::CompletionCallback& callback) const override; - - private: - std::string mime_type_; - std::string charset_; - std::string data_; - - DISALLOW_COPY_AND_ASSIGN(URLRequestStringJob); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NET_URL_REQUEST_STRING_JOB_H_ diff --git a/atom/browser/node_debugger.cc b/atom/browser/node_debugger.cc deleted file mode 100644 index 55025dd69f72c..0000000000000 --- a/atom/browser/node_debugger.cc +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/node_debugger.h" - -#include - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "content/public/browser/browser_thread.h" -#include "net/test/embedded_test_server/tcp_listen_socket.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace { - -// NodeDebugger is stored in Isolate's data, slots 0, 1, 3 have already been -// taken by gin, blink and node, using 2 is a safe option for now. -const int kIsolateSlot = 2; - -const char* kContentLength = "Content-Length"; - -} // namespace - -NodeDebugger::NodeDebugger(v8::Isolate* isolate) - : isolate_(isolate), - thread_("NodeDebugger"), - content_length_(-1), - weak_factory_(this) { - bool use_debug_agent = false; - int port = 5858; - - std::string port_str; - base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); - if (cmd->HasSwitch("debug")) { - use_debug_agent = true; - port_str = cmd->GetSwitchValueASCII("debug"); - } else if (cmd->HasSwitch("debug-brk")) { - use_debug_agent = true; - port_str = cmd->GetSwitchValueASCII("debug-brk"); - } - - if (use_debug_agent) { - if (!port_str.empty()) - base::StringToInt(port_str, &port); - - isolate_->SetData(kIsolateSlot, this); - v8::Debug::SetMessageHandler(DebugMessageHandler); - - uv_async_init(uv_default_loop(), &weak_up_ui_handle_, ProcessMessageInUI); - - // Start a new IO thread. - base::Thread::Options options; - options.message_loop_type = base::MessageLoop::TYPE_IO; - if (!thread_.StartWithOptions(options)) { - LOG(ERROR) << "Unable to start debugger thread"; - return; - } - - // Start the server in new IO thread. - thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&NodeDebugger::StartServer, weak_factory_.GetWeakPtr(), - port)); - } -} - -NodeDebugger::~NodeDebugger() { - thread_.Stop(); -} - -bool NodeDebugger::IsRunning() const { - return thread_.IsRunning(); -} - -void NodeDebugger::StartServer(int port) { - server_ = net::test_server::TCPListenSocket::CreateAndListen( - "127.0.0.1", port, this); - if (!server_) { - LOG(ERROR) << "Cannot start debugger server"; - return; - } -} - -void NodeDebugger::CloseSession() { - accepted_socket_.reset(); -} - -void NodeDebugger::OnMessage(const std::string& message) { - if (message.find("\"type\":\"request\",\"command\":\"disconnect\"}") != - std::string::npos) - CloseSession(); - - base::string16 message16 = base::UTF8ToUTF16(message); - v8::Debug::SendCommand( - isolate_, - reinterpret_cast(message16.data()), message16.size()); - - uv_async_send(&weak_up_ui_handle_); -} - -void NodeDebugger::SendMessage(const std::string& message) { - if (accepted_socket_) { - std::string header = base::StringPrintf( - "%s: %d\r\n\r\n", kContentLength, static_cast(message.size())); - accepted_socket_->Send(header); - accepted_socket_->Send(message); - } -} - -void NodeDebugger::SendConnectMessage() { - accepted_socket_->Send(base::StringPrintf( - "Type: connect\r\n" - "V8-Version: %s\r\n" - "Protocol-Version: 1\r\n" - "Embedding-Host: %s\r\n" - "%s: 0\r\n", - v8::V8::GetVersion(), ATOM_PRODUCT_NAME, kContentLength), true); -} - -// static -void NodeDebugger::ProcessMessageInUI(uv_async_t* handle) { - v8::Debug::ProcessDebugMessages(); -} - -// static -void NodeDebugger::DebugMessageHandler(const v8::Debug::Message& message) { - NodeDebugger* self = static_cast( - message.GetIsolate()->GetData(kIsolateSlot)); - - if (self) { - std::string message8(*v8::String::Utf8Value(message.GetJSON())); - self->thread_.message_loop()->PostTask( - FROM_HERE, - base::Bind(&NodeDebugger::SendMessage, self->weak_factory_.GetWeakPtr(), - message8)); - } -} - -void NodeDebugger::DidAccept( - net::test_server::StreamListenSocket* server, - std::unique_ptr socket) { - // Only accept one session. - if (accepted_socket_) { - socket->Send(std::string("Remote debugging session already active"), true); - return; - } - - accepted_socket_ = std::move(socket); - SendConnectMessage(); -} - -void NodeDebugger::DidRead(net::test_server::StreamListenSocket* socket, - const char* data, - int len) { - buffer_.append(data, len); - - do { - if (buffer_.size() == 0) - return; - - // Read the "Content-Length" header. - if (content_length_ < 0) { - size_t pos = buffer_.find("\r\n\r\n"); - if (pos == std::string::npos) - return; - - // We can be sure that the header is "Content-Length: xxx\r\n". - std::string content_length = buffer_.substr(16, pos - 16); - if (!base::StringToInt(content_length, &content_length_)) { - DidClose(accepted_socket_.get()); - return; - } - - // Strip header from buffer. - buffer_ = buffer_.substr(pos + 4); - } - - // Read the message. - if (buffer_.size() >= static_cast(content_length_)) { - std::string message = buffer_.substr(0, content_length_); - buffer_ = buffer_.substr(content_length_); - - OnMessage(message); - - // Get ready for next message. - content_length_ = -1; - } - } while (true); -} - -void NodeDebugger::DidClose(net::test_server::StreamListenSocket* socket) { - // If we lost the connection, then simulate a disconnect msg: - OnMessage("{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}"); -} - -} // namespace atom diff --git a/atom/browser/node_debugger.h b/atom/browser/node_debugger.h deleted file mode 100644 index 118812a139a5e..0000000000000 --- a/atom/browser/node_debugger.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_NODE_DEBUGGER_H_ -#define ATOM_BROWSER_NODE_DEBUGGER_H_ - -#include -#include - -#include "base/memory/weak_ptr.h" -#include "base/threading/thread.h" -#include "net/test/embedded_test_server/stream_listen_socket.h" -#include "v8/include/v8-debug.h" -#include "vendor/node/deps/uv/include/uv.h" - -namespace atom { - -// Add support for node's "--debug" switch. -class NodeDebugger : public net::test_server::StreamListenSocket::Delegate { - public: - explicit NodeDebugger(v8::Isolate* isolate); - virtual ~NodeDebugger(); - - bool IsRunning() const; - - private: - void StartServer(int port); - void CloseSession(); - void OnMessage(const std::string& message); - void SendMessage(const std::string& message); - void SendConnectMessage(); - - static void ProcessMessageInUI(uv_async_t* handle); - - static void DebugMessageHandler(const v8::Debug::Message& message); - - // net::test_server::StreamListenSocket::Delegate: - void DidAccept( - net::test_server::StreamListenSocket* server, - std::unique_ptr socket) override; - void DidRead(net::test_server::StreamListenSocket* socket, - const char* data, - int len) override; - void DidClose(net::test_server::StreamListenSocket* socket) override; - - v8::Isolate* isolate_; - - uv_async_t weak_up_ui_handle_; - - base::Thread thread_; - std::unique_ptr server_; - std::unique_ptr accepted_socket_; - - std::string buffer_; - int content_length_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(NodeDebugger); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_NODE_DEBUGGER_H_ diff --git a/atom/browser/osr/osr_output_device.cc b/atom/browser/osr/osr_output_device.cc deleted file mode 100644 index dd806136338ee..0000000000000 --- a/atom/browser/osr/osr_output_device.cc +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/osr/osr_output_device.h" - -#include "third_party/skia/include/core/SkDevice.h" -#include "ui/gfx/skia_util.h" - -namespace atom { - -OffScreenOutputDevice::OffScreenOutputDevice(bool transparent, - const OnPaintCallback& callback) - : transparent_(transparent), - callback_(callback), - active_(false) { - DCHECK(!callback_.is_null()); -} - -OffScreenOutputDevice::~OffScreenOutputDevice() { -} - -void OffScreenOutputDevice::Resize( - const gfx::Size& pixel_size, float scale_factor) { - scale_factor_ = scale_factor; - - if (viewport_pixel_size_ == pixel_size) return; - viewport_pixel_size_ = pixel_size; - - canvas_.reset(); - bitmap_.reset(new SkBitmap); - bitmap_->allocN32Pixels(viewport_pixel_size_.width(), - viewport_pixel_size_.height(), - !transparent_); - if (bitmap_->drawsNothing()) { - NOTREACHED(); - bitmap_.reset(); - return; - } - - if (transparent_) - bitmap_->eraseARGB(0, 0, 0, 0); - - canvas_.reset(new SkCanvas(*bitmap_)); -} - -SkCanvas* OffScreenOutputDevice::BeginPaint(const gfx::Rect& damage_rect) { - DCHECK(canvas_.get()); - DCHECK(bitmap_.get()); - - damage_rect_ = damage_rect; - - return canvas_.get(); -} - -void OffScreenOutputDevice::EndPaint() { - DCHECK(canvas_.get()); - DCHECK(bitmap_.get()); - - if (!bitmap_.get()) return; - - cc::SoftwareOutputDevice::EndPaint(); - - if (active_) - OnPaint(damage_rect_); -} - -void OffScreenOutputDevice::SetActive(bool active) { - if (active == active_) - return; - active_ = active; - - if (active_) - OnPaint(gfx::Rect(viewport_pixel_size_)); -} - -void OffScreenOutputDevice::OnPaint(const gfx::Rect& damage_rect) { - gfx::Rect rect = damage_rect; - - rect.Intersect(gfx::Rect(viewport_pixel_size_)); - if (rect.IsEmpty()) - return; - - SkAutoLockPixels bitmap_pixels_lock(*bitmap_); - callback_.Run(rect, *bitmap_); -} - -} // namespace atom diff --git a/atom/browser/osr/osr_output_device.h b/atom/browser/osr/osr_output_device.h deleted file mode 100644 index 5710bc41b8319..0000000000000 --- a/atom/browser/osr/osr_output_device.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_OSR_OSR_OUTPUT_DEVICE_H_ -#define ATOM_BROWSER_OSR_OSR_OUTPUT_DEVICE_H_ - -#include "base/callback.h" -#include "cc/output/software_output_device.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkCanvas.h" - -namespace atom { - -typedef base::Callback OnPaintCallback; - -class OffScreenOutputDevice : public cc::SoftwareOutputDevice { - public: - OffScreenOutputDevice(bool transparent, const OnPaintCallback& callback); - ~OffScreenOutputDevice(); - - // cc::SoftwareOutputDevice: - void Resize(const gfx::Size& pixel_size, float scale_factor) override; - SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override; - void EndPaint() override; - - void SetActive(bool active); - void OnPaint(const gfx::Rect& damage_rect); - - private: - const bool transparent_; - OnPaintCallback callback_; - - bool active_; - - std::unique_ptr canvas_; - std::unique_ptr bitmap_; - - DISALLOW_COPY_AND_ASSIGN(OffScreenOutputDevice); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_OSR_OSR_OUTPUT_DEVICE_H_ diff --git a/atom/browser/osr/osr_render_widget_host_view.cc b/atom/browser/osr/osr_render_widget_host_view.cc deleted file mode 100644 index 71a0a8d4661db..0000000000000 --- a/atom/browser/osr/osr_render_widget_host_view.cc +++ /dev/null @@ -1,861 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/osr/osr_render_widget_host_view.h" - -#include - -#include "base/callback_helpers.h" -#include "base/location.h" -#include "base/memory/ptr_util.h" -#include "base/single_thread_task_runner.h" -#include "base/time/time.h" -#include "cc/output/copy_output_request.h" -#include "cc/scheduler/delay_based_time_source.h" -#include "components/display_compositor/gl_helper.h" -#include "content/browser/renderer_host/render_widget_host_impl.h" -#include "content/browser/renderer_host/render_widget_host_delegate.h" -#include "content/common/view_messages.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/context_factory.h" -#include "content/public/browser/render_widget_host_view_frame_subscriber.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/layer_type.h" -#include "ui/events/latency_info.h" -#include "ui/gfx/geometry/dip_util.h" -#include "ui/gfx/native_widget_types.h" - -namespace atom { - -namespace { - -const float kDefaultScaleFactor = 1.0; -const int kFrameRetryLimit = 2; - -} // namespace - -class AtomCopyFrameGenerator { - public: - AtomCopyFrameGenerator(int frame_rate_threshold_ms, - OffScreenRenderWidgetHostView* view) - : frame_rate_threshold_ms_(frame_rate_threshold_ms), - view_(view), - frame_pending_(false), - frame_in_progress_(false), - frame_retry_count_(0), - weak_ptr_factory_(this) { - last_time_ = base::Time::Now(); - } - - void GenerateCopyFrame( - bool force_frame, - const gfx::Rect& damage_rect) { - if (force_frame && !frame_pending_) - frame_pending_ = true; - - if (!frame_pending_) - return; - - if (!damage_rect.IsEmpty()) - pending_damage_rect_.Union(damage_rect); - - if (frame_in_progress_) - return; - - frame_in_progress_ = true; - - const int64_t frame_rate_delta = - (base::TimeTicks::Now() - frame_start_time_).InMilliseconds(); - if (frame_rate_delta < frame_rate_threshold_ms_) { - content::BrowserThread::PostDelayedTask(content::BrowserThread::UI, - FROM_HERE, - base::Bind(&AtomCopyFrameGenerator::InternalGenerateCopyFrame, - weak_ptr_factory_.GetWeakPtr()), base::TimeDelta::FromMilliseconds( - frame_rate_threshold_ms_ - frame_rate_delta)); - return; - } - - InternalGenerateCopyFrame(); - } - - bool frame_pending() const { return frame_pending_; } - - void set_frame_rate_threshold_ms(int frame_rate_threshold_ms) { - frame_rate_threshold_ms_ = frame_rate_threshold_ms; - } - - private: - void InternalGenerateCopyFrame() { - frame_pending_ = false; - frame_start_time_ = base::TimeTicks::Now(); - - if (!view_->render_widget_host()) - return; - - const gfx::Rect damage_rect = pending_damage_rect_; - pending_damage_rect_.SetRect(0, 0, 0, 0); - - std::unique_ptr request = - cc::CopyOutputRequest::CreateRequest(base::Bind( - &AtomCopyFrameGenerator::CopyFromCompositingSurfaceHasResult, - weak_ptr_factory_.GetWeakPtr(), - damage_rect)); - - request->set_area(gfx::Rect(view_->GetPhysicalBackingSize())); - - view_->DelegatedFrameHostGetLayer()->RequestCopyOfOutput( - std::move(request)); - } - - void CopyFromCompositingSurfaceHasResult( - const gfx::Rect& damage_rect, - std::unique_ptr result) { - if (result->IsEmpty() || result->size().IsEmpty() || - !view_->render_widget_host()) { - OnCopyFrameCaptureFailure(damage_rect); - return; - } - - if (result->HasTexture()) { - PrepareTextureCopyOutputResult(damage_rect, std::move(result)); - return; - } - - DCHECK(result->HasBitmap()); - PrepareBitmapCopyOutputResult(damage_rect, std::move(result)); - } - - void PrepareTextureCopyOutputResult( - const gfx::Rect& damage_rect, - std::unique_ptr result) { - DCHECK(result->HasTexture()); - base::ScopedClosureRunner scoped_callback_runner( - base::Bind(&AtomCopyFrameGenerator::OnCopyFrameCaptureFailure, - weak_ptr_factory_.GetWeakPtr(), - damage_rect)); - - const gfx::Size& result_size = result->size(); - SkIRect bitmap_size; - if (bitmap_) - bitmap_->getBounds(&bitmap_size); - - if (!bitmap_ || - bitmap_size.width() != result_size.width() || - bitmap_size.height() != result_size.height()) { - bitmap_.reset(new SkBitmap); - bitmap_->allocN32Pixels(result_size.width(), - result_size.height(), - true); - if (bitmap_->drawsNothing()) - return; - } - - content::ImageTransportFactory* factory = - content::ImageTransportFactory::GetInstance(); - display_compositor::GLHelper* gl_helper = factory->GetGLHelper(); - if (!gl_helper) - return; - - std::unique_ptr bitmap_pixels_lock( - new SkAutoLockPixels(*bitmap_)); - uint8_t* pixels = static_cast(bitmap_->getPixels()); - - cc::TextureMailbox texture_mailbox; - std::unique_ptr release_callback; - result->TakeTexture(&texture_mailbox, &release_callback); - DCHECK(texture_mailbox.IsTexture()); - if (!texture_mailbox.IsTexture()) - return; - - ignore_result(scoped_callback_runner.Release()); - - gl_helper->CropScaleReadbackAndCleanMailbox( - texture_mailbox.mailbox(), - texture_mailbox.sync_token(), - result_size, - gfx::Rect(result_size), - result_size, - pixels, - kN32_SkColorType, - base::Bind( - &AtomCopyFrameGenerator::CopyFromCompositingSurfaceFinishedProxy, - weak_ptr_factory_.GetWeakPtr(), - base::Passed(&release_callback), - damage_rect, - base::Passed(&bitmap_), - base::Passed(&bitmap_pixels_lock)), - display_compositor::GLHelper::SCALER_QUALITY_FAST); - } - - static void CopyFromCompositingSurfaceFinishedProxy( - base::WeakPtr generator, - std::unique_ptr release_callback, - const gfx::Rect& damage_rect, - std::unique_ptr bitmap, - std::unique_ptr bitmap_pixels_lock, - bool result) { - gpu::SyncToken sync_token; - if (result) { - display_compositor::GLHelper* gl_helper = - content::ImageTransportFactory::GetInstance()->GetGLHelper(); - if (gl_helper) - gl_helper->GenerateSyncToken(&sync_token); - } - const bool lost_resource = !sync_token.HasData(); - release_callback->Run(sync_token, lost_resource); - - if (generator) { - generator->CopyFromCompositingSurfaceFinished( - damage_rect, std::move(bitmap), std::move(bitmap_pixels_lock), - result); - } else { - bitmap_pixels_lock.reset(); - bitmap.reset(); - } - } - - void CopyFromCompositingSurfaceFinished( - const gfx::Rect& damage_rect, - std::unique_ptr bitmap, - std::unique_ptr bitmap_pixels_lock, - bool result) { - DCHECK(!bitmap_); - bitmap_ = std::move(bitmap); - - if (result) { - OnCopyFrameCaptureSuccess(damage_rect, *bitmap_, - std::move(bitmap_pixels_lock)); - } else { - bitmap_pixels_lock.reset(); - OnCopyFrameCaptureFailure(damage_rect); - } - } - - void PrepareBitmapCopyOutputResult( - const gfx::Rect& damage_rect, - std::unique_ptr result) { - DCHECK(result->HasBitmap()); - std::unique_ptr source = result->TakeBitmap(); - DCHECK(source); - if (source) { - std::unique_ptr bitmap_pixels_lock( - new SkAutoLockPixels(*source)); - OnCopyFrameCaptureSuccess(damage_rect, *source, - std::move(bitmap_pixels_lock)); - } else { - OnCopyFrameCaptureFailure(damage_rect); - } - } - - void OnCopyFrameCaptureFailure( - const gfx::Rect& damage_rect) { - pending_damage_rect_.Union(damage_rect); - - const bool force_frame = (++frame_retry_count_ <= kFrameRetryLimit); - OnCopyFrameCaptureCompletion(force_frame); - } - - void OnCopyFrameCaptureSuccess( - const gfx::Rect& damage_rect, - const SkBitmap& bitmap, - std::unique_ptr bitmap_pixels_lock) { - view_->OnPaint(damage_rect, bitmap); - - if (frame_retry_count_ > 0) - frame_retry_count_ = 0; - - OnCopyFrameCaptureCompletion(false); - } - - void OnCopyFrameCaptureCompletion(bool force_frame) { - frame_in_progress_ = false; - - if (frame_pending_) { - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&AtomCopyFrameGenerator::GenerateCopyFrame, - weak_ptr_factory_.GetWeakPtr(), - force_frame, - gfx::Rect())); - } - } - - int frame_rate_threshold_ms_; - OffScreenRenderWidgetHostView* view_; - - base::Time last_time_; - - base::TimeTicks frame_start_time_; - bool frame_pending_; - bool frame_in_progress_; - int frame_retry_count_; - std::unique_ptr bitmap_; - gfx::Rect pending_damage_rect_; - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(AtomCopyFrameGenerator); -}; - -class AtomBeginFrameTimer : public cc::DelayBasedTimeSourceClient { - public: - AtomBeginFrameTimer(int frame_rate_threshold_ms, - const base::Closure& callback) - : callback_(callback) { - time_source_ = cc::DelayBasedTimeSource::Create( - base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms), - content::BrowserThread::GetMessageLoopProxyForThread( - content::BrowserThread::UI).get()); - time_source_->SetClient(this); - } - - void SetActive(bool active) { - time_source_->SetActive(active); - } - - bool IsActive() const { - return time_source_->Active(); - } - - void SetFrameRateThresholdMs(int frame_rate_threshold_ms) { - time_source_->SetTimebaseAndInterval( - base::TimeTicks::Now(), - base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms)); - } - - private: - void OnTimerTick() override { - callback_.Run(); - } - - const base::Closure callback_; - std::unique_ptr time_source_; - - DISALLOW_COPY_AND_ASSIGN(AtomBeginFrameTimer); -}; - -OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView( - bool transparent, - const OnPaintCallback& callback, - content::RenderWidgetHost* host, - NativeWindow* native_window) - : render_widget_host_(content::RenderWidgetHostImpl::From(host)), - native_window_(native_window), - software_output_device_(nullptr), - transparent_(transparent), - callback_(callback), - frame_rate_(60), - frame_rate_threshold_ms_(0), - last_time_(base::Time::Now()), - scale_factor_(kDefaultScaleFactor), - is_showing_(!render_widget_host_->is_hidden()), - size_(native_window->GetSize()), - painting_(true), - root_layer_(new ui::Layer(ui::LAYER_SOLID_COLOR)), - delegated_frame_host_(new content::DelegatedFrameHost(this)), - weak_ptr_factory_(this) { - DCHECK(render_widget_host_); - render_widget_host_->SetView(this); - -#if defined(OS_MACOSX) - CreatePlatformWidget(); -#else - compositor_.reset( - new ui::Compositor(content::GetContextFactory(), - base::ThreadTaskRunnerHandle::Get())); - compositor_->SetAcceleratedWidget(native_window_->GetAcceleratedWidget()); -#endif - compositor_->SetDelegate(this); - compositor_->SetRootLayer(root_layer_.get()); - - ResizeRootLayer(); -} - -OffScreenRenderWidgetHostView::~OffScreenRenderWidgetHostView() { - if (is_showing_) - delegated_frame_host_->WasHidden(); - delegated_frame_host_->ResetCompositor(); - -#if defined(OS_MACOSX) - DestroyPlatformWidget(); -#endif -} - -void OffScreenRenderWidgetHostView::OnBeginFrameTimerTick() { - const base::TimeTicks frame_time = base::TimeTicks::Now(); - const base::TimeDelta vsync_period = - base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_); - SendBeginFrame(frame_time, vsync_period); -} - -void OffScreenRenderWidgetHostView::SendBeginFrame( - base::TimeTicks frame_time, base::TimeDelta vsync_period) { - base::TimeTicks display_time = frame_time + vsync_period; - - base::TimeDelta estimated_browser_composite_time = - base::TimeDelta::FromMicroseconds( - (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60)); - - base::TimeTicks deadline = display_time - estimated_browser_composite_time; - - render_widget_host_->Send(new ViewMsg_BeginFrame( - render_widget_host_->GetRoutingID(), - cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline, - vsync_period, cc::BeginFrameArgs::NORMAL))); -} - -bool OffScreenRenderWidgetHostView::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(OffScreenRenderWidgetHostView, message) - IPC_MESSAGE_HANDLER(ViewHostMsg_SetNeedsBeginFrames, - OnSetNeedsBeginFrames) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - if (!handled) - return content::RenderWidgetHostViewBase::OnMessageReceived(message); - return handled; -} - -void OffScreenRenderWidgetHostView::InitAsChild(gfx::NativeView) { -} - -content::RenderWidgetHost* OffScreenRenderWidgetHostView::GetRenderWidgetHost() - const { - return render_widget_host_; -} - -void OffScreenRenderWidgetHostView::SetSize(const gfx::Size& size) { - size_ = size; - - const gfx::Size& size_in_pixels = - gfx::ConvertSizeToPixel(scale_factor_, size); - - root_layer_->SetBounds(gfx::Rect(size)); - compositor_->SetScaleAndSize(scale_factor_, size_in_pixels); -} - -void OffScreenRenderWidgetHostView::SetBounds(const gfx::Rect& new_bounds) { -} - -gfx::Vector2dF OffScreenRenderWidgetHostView::GetLastScrollOffset() const { - return last_scroll_offset_; -} - -gfx::NativeView OffScreenRenderWidgetHostView::GetNativeView() const { - return gfx::NativeView(); -} - -gfx::NativeViewAccessible -OffScreenRenderWidgetHostView::GetNativeViewAccessible() { - return gfx::NativeViewAccessible(); -} - -ui::TextInputClient* OffScreenRenderWidgetHostView::GetTextInputClient() { - return nullptr; -} - -void OffScreenRenderWidgetHostView::Focus() { -} - -bool OffScreenRenderWidgetHostView::HasFocus() const { - return false; -} - -bool OffScreenRenderWidgetHostView::IsSurfaceAvailableForCopy() const { - return delegated_frame_host_->CanCopyToBitmap(); -} - -void OffScreenRenderWidgetHostView::Show() { - if (is_showing_) - return; - - is_showing_ = true; - if (render_widget_host_) - render_widget_host_->WasShown(ui::LatencyInfo()); - delegated_frame_host_->SetCompositor(compositor_.get()); - delegated_frame_host_->WasShown(ui::LatencyInfo()); -} - -void OffScreenRenderWidgetHostView::Hide() { - if (!is_showing_) - return; - - if (render_widget_host_) - render_widget_host_->WasHidden(); - delegated_frame_host_->WasHidden(); - delegated_frame_host_->ResetCompositor(); - is_showing_ = false; -} - -bool OffScreenRenderWidgetHostView::IsShowing() { - return is_showing_; -} - -gfx::Rect OffScreenRenderWidgetHostView::GetViewBounds() const { - return gfx::Rect(size_); -} - -void OffScreenRenderWidgetHostView::SetBackgroundColor(SkColor color) { - if (transparent_) - color = SkColorSetARGB(SK_AlphaTRANSPARENT, 0, 0, 0); - - content::RenderWidgetHostViewBase::SetBackgroundColor(color); - - const bool opaque = !transparent_ && GetBackgroundOpaque(); - if (render_widget_host_) - render_widget_host_->SetBackgroundOpaque(opaque); -} - -gfx::Size OffScreenRenderWidgetHostView::GetVisibleViewportSize() const { - return size_; -} - -void OffScreenRenderWidgetHostView::SetInsets(const gfx::Insets& insets) { -} - -bool OffScreenRenderWidgetHostView::LockMouse() { - return false; -} - -void OffScreenRenderWidgetHostView::UnlockMouse() { -} - -bool OffScreenRenderWidgetHostView::GetScreenColorProfile(std::vector*) { - return false; -} - -void OffScreenRenderWidgetHostView::OnSwapCompositorFrame( - uint32_t output_surface_id, - std::unique_ptr frame) { - TRACE_EVENT0("electron", - "OffScreenRenderWidgetHostView::OnSwapCompositorFrame"); - - if (frame->metadata.root_scroll_offset != last_scroll_offset_) { - last_scroll_offset_ = frame->metadata.root_scroll_offset; - } - - if (frame->delegated_frame_data) { - if (software_output_device_) { - if (!begin_frame_timer_.get()) { - software_output_device_->SetActive(painting_); - } - - delegated_frame_host_->SwapDelegatedFrame(output_surface_id, - std::move(frame)); - } else { - if (!copy_frame_generator_.get()) { - copy_frame_generator_.reset( - new AtomCopyFrameGenerator(frame_rate_threshold_ms_, this)); - } - - cc::RenderPass* root_pass = - frame->delegated_frame_data->render_pass_list.back().get(); - gfx::Size frame_size = root_pass->output_rect.size(); - gfx::Rect damage_rect = - gfx::ToEnclosingRect(gfx::RectF(root_pass->damage_rect)); - damage_rect.Intersect(gfx::Rect(frame_size)); - - delegated_frame_host_->SwapDelegatedFrame(output_surface_id, - std::move(frame)); - - if (painting_) - copy_frame_generator_->GenerateCopyFrame(true, damage_rect); - } - } -} - -void OffScreenRenderWidgetHostView::ClearCompositorFrame() { - delegated_frame_host_->ClearDelegatedFrame(); -} - -void OffScreenRenderWidgetHostView::InitAsPopup( - content::RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { -} - -void OffScreenRenderWidgetHostView::InitAsFullscreen( - content::RenderWidgetHostView *) { -} - -void OffScreenRenderWidgetHostView::UpdateCursor(const content::WebCursor &) { -} - -void OffScreenRenderWidgetHostView::SetIsLoading(bool loading) { -} - -void OffScreenRenderWidgetHostView::TextInputStateChanged( - const content::TextInputState& params) { -} - -void OffScreenRenderWidgetHostView::ImeCancelComposition() { -} - -void OffScreenRenderWidgetHostView::RenderProcessGone(base::TerminationStatus, - int) { - Destroy(); -} - -void OffScreenRenderWidgetHostView::Destroy() { - delete this; -} - -void OffScreenRenderWidgetHostView::SetTooltipText(const base::string16 &) { -} - -void OffScreenRenderWidgetHostView::SelectionBoundsChanged( - const ViewHostMsg_SelectionBounds_Params &) { -} - -void OffScreenRenderWidgetHostView::CopyFromCompositingSurface( - const gfx::Rect& src_subrect, - const gfx::Size& dst_size, - const content::ReadbackRequestCallback& callback, - const SkColorType preferred_color_type) { - delegated_frame_host_->CopyFromCompositingSurface( - src_subrect, dst_size, callback, preferred_color_type); -} - -void OffScreenRenderWidgetHostView::CopyFromCompositingSurfaceToVideoFrame( - const gfx::Rect& src_subrect, - const scoped_refptr& target, - const base::Callback& callback) { - delegated_frame_host_->CopyFromCompositingSurfaceToVideoFrame( - src_subrect, target, callback); -} - -bool OffScreenRenderWidgetHostView::CanCopyToVideoFrame() const { - return delegated_frame_host_->CanCopyToVideoFrame(); -} - -void OffScreenRenderWidgetHostView::BeginFrameSubscription( - std::unique_ptr subscriber) { - delegated_frame_host_->BeginFrameSubscription(std::move(subscriber)); -} - -void OffScreenRenderWidgetHostView::EndFrameSubscription() { - delegated_frame_host_->EndFrameSubscription(); -} - -bool OffScreenRenderWidgetHostView::HasAcceleratedSurface(const gfx::Size &) { - return false; -} - -void OffScreenRenderWidgetHostView::GetScreenInfo( - blink::WebScreenInfo* results) { - results->rect = gfx::Rect(size_); - results->availableRect = gfx::Rect(size_); - results->depth = 24; - results->depthPerComponent = 8; - results->deviceScaleFactor = scale_factor_; - results->orientationAngle = 0; - results->orientationType = blink::WebScreenOrientationLandscapePrimary; -} - -bool OffScreenRenderWidgetHostView::GetScreenColorProfile( - blink::WebVector*) { - return false; -} - -gfx::Rect OffScreenRenderWidgetHostView::GetBoundsInRootWindow() { - return gfx::Rect(size_); -} - -void OffScreenRenderWidgetHostView::LockCompositingSurface() { -} - -void OffScreenRenderWidgetHostView::UnlockCompositingSurface() { -} - -void OffScreenRenderWidgetHostView::ImeCompositionRangeChanged( - const gfx::Range &, const std::vector&) { -} - -gfx::Size OffScreenRenderWidgetHostView::GetPhysicalBackingSize() const { - return size_; -} - -gfx::Size OffScreenRenderWidgetHostView::GetRequestedRendererSize() const { - return size_; -} - -int OffScreenRenderWidgetHostView:: - DelegatedFrameHostGetGpuMemoryBufferClientId() - const { - return render_widget_host_->GetProcess()->GetID(); -} - -ui::Layer* OffScreenRenderWidgetHostView::DelegatedFrameHostGetLayer() const { - return const_cast(root_layer_.get()); -} - -bool OffScreenRenderWidgetHostView::DelegatedFrameHostIsVisible() const { - return !render_widget_host_->is_hidden(); -} - -SkColor OffScreenRenderWidgetHostView::DelegatedFrameHostGetGutterColor( - SkColor color) const { - return color; -} - -gfx::Size OffScreenRenderWidgetHostView::DelegatedFrameHostDesiredSizeInDIP() - const { - return size_; -} - -bool OffScreenRenderWidgetHostView::DelegatedFrameCanCreateResizeLock() const { - return false; -} - -std::unique_ptr - OffScreenRenderWidgetHostView::DelegatedFrameHostCreateResizeLock( - bool defer_compositor_lock) { - return nullptr; -} - -void OffScreenRenderWidgetHostView::DelegatedFrameHostResizeLockWasReleased() { - return render_widget_host_->WasResized(); -} - -void OffScreenRenderWidgetHostView::DelegatedFrameHostSendCompositorSwapAck( - int output_surface_id, const cc::CompositorFrameAck& ack) { - render_widget_host_->Send(new ViewMsg_SwapCompositorFrameAck( - render_widget_host_->GetRoutingID(), - output_surface_id, ack)); -} - -void OffScreenRenderWidgetHostView:: - DelegatedFrameHostSendReclaimCompositorResources( - int output_surface_id, const cc::CompositorFrameAck& ack) { - render_widget_host_->Send(new ViewMsg_ReclaimCompositorResources( - render_widget_host_->GetRoutingID(), - output_surface_id, ack)); -} - -void OffScreenRenderWidgetHostView:: - DelegatedFrameHostOnLostCompositorResources() { - render_widget_host_->ScheduleComposite(); -} - -void OffScreenRenderWidgetHostView::DelegatedFrameHostUpdateVSyncParameters( - const base::TimeTicks& timebase, const base::TimeDelta& interval) { - render_widget_host_->UpdateVSyncParameters(timebase, interval); -} - -void OffScreenRenderWidgetHostView::SetBeginFrameSource( - cc::BeginFrameSource* source) { -} - -std::unique_ptr - OffScreenRenderWidgetHostView::CreateSoftwareOutputDevice( - ui::Compositor* compositor) { - DCHECK_EQ(compositor_.get(), compositor); - DCHECK(!copy_frame_generator_); - DCHECK(!software_output_device_); - - software_output_device_ = new OffScreenOutputDevice( - transparent_, - base::Bind(&OffScreenRenderWidgetHostView::OnPaint, - weak_ptr_factory_.GetWeakPtr())); - return base::WrapUnique(software_output_device_); -} - -bool OffScreenRenderWidgetHostView::InstallTransparency() { - if (transparent_) { - SetBackgroundColor(SkColor()); - compositor_->SetHostHasTransparentBackground(true); - return true; - } - return false; -} - -bool OffScreenRenderWidgetHostView::IsAutoResizeEnabled() const { - return false; -} - -void OffScreenRenderWidgetHostView::OnSetNeedsBeginFrames(bool enabled) { - SetupFrameRate(false); - - begin_frame_timer_->SetActive(enabled); - - if (software_output_device_) { - software_output_device_->SetActive(enabled && painting_); - } -} - -void OffScreenRenderWidgetHostView::OnPaint( - const gfx::Rect& damage_rect, const SkBitmap& bitmap) { - TRACE_EVENT0("electron", "OffScreenRenderWidgetHostView::OnPaint"); - callback_.Run(damage_rect, bitmap); -} - -void OffScreenRenderWidgetHostView::SetPainting(bool painting) { - painting_ = painting; - - if (software_output_device_) { - software_output_device_->SetActive(painting_); - } -} - -bool OffScreenRenderWidgetHostView::IsPainting() const { - return painting_; -} - -void OffScreenRenderWidgetHostView::SetFrameRate(int frame_rate) { - if (frame_rate <= 0) - frame_rate = 1; - if (frame_rate > 60) - frame_rate = 60; - - frame_rate_ = frame_rate; - - SetupFrameRate(true); -} - -int OffScreenRenderWidgetHostView::GetFrameRate() const { - return frame_rate_; -} - -void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) { - if (!force && frame_rate_threshold_ms_ != 0) - return; - - frame_rate_threshold_ms_ = 1000 / frame_rate_; - - compositor_->vsync_manager()->SetAuthoritativeVSyncInterval( - base::TimeDelta::FromMilliseconds(frame_rate_threshold_ms_)); - - if (copy_frame_generator_.get()) { - copy_frame_generator_->set_frame_rate_threshold_ms( - frame_rate_threshold_ms_); - } - - if (begin_frame_timer_.get()) { - begin_frame_timer_->SetFrameRateThresholdMs(frame_rate_threshold_ms_); - } else { - begin_frame_timer_.reset(new AtomBeginFrameTimer( - frame_rate_threshold_ms_, - base::Bind(&OffScreenRenderWidgetHostView::OnBeginFrameTimerTick, - weak_ptr_factory_.GetWeakPtr()))); - } -} - -void OffScreenRenderWidgetHostView::ResizeRootLayer() { - SetupFrameRate(false); - - const float orgScaleFactor = scale_factor_; - const bool scaleFactorDidChange = (orgScaleFactor != scale_factor_); - - gfx::Size size = GetViewBounds().size(); - - if (!scaleFactorDidChange && size == root_layer_->bounds().size()) - return; - - const gfx::Size& size_in_pixels = - gfx::ConvertSizeToPixel(scale_factor_, size); - - root_layer_->SetBounds(gfx::Rect(size)); - compositor_->SetScaleAndSize(scale_factor_, size_in_pixels); -} - -} // namespace atom diff --git a/atom/browser/osr/osr_render_widget_host_view.h b/atom/browser/osr/osr_render_widget_host_view.h deleted file mode 100644 index 74da984363ab6..0000000000000 --- a/atom/browser/osr/osr_render_widget_host_view.h +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_OSR_OSR_RENDER_WIDGET_HOST_VIEW_H_ -#define ATOM_BROWSER_OSR_OSR_RENDER_WIDGET_HOST_VIEW_H_ - -#include -#include - -#if defined(OS_WIN) -#include -#endif - -#include "atom/browser/native_window.h" -#include "atom/browser/osr/osr_output_device.h" -#include "base/process/kill.h" -#include "base/threading/thread.h" -#include "base/time/time.h" -#include "cc/scheduler/begin_frame_source.h" -#include "cc/output/compositor_frame.h" -#include "content/browser/renderer_host/delegated_frame_host.h" -#include "content/browser/renderer_host/render_widget_host_impl.h" -#include "content/browser/renderer_host/render_widget_host_view_base.h" -#include "content/browser/renderer_host/resize_lock.h" -#include "ui/compositor/compositor.h" -#include "ui/compositor/layer_delegate.h" -#include "ui/compositor/layer_owner.h" -#include "ui/base/ime/text_input_client.h" -#include "ui/gfx/geometry/point.h" -#include "third_party/WebKit/public/platform/WebVector.h" - -#if defined(OS_WIN) -#include "ui/gfx/win/window_impl.h" -#endif - -#if defined(OS_MACOSX) -#include "content/browser/renderer_host/browser_compositor_view_mac.h" -#include "ui/accelerated_widget_mac/accelerated_widget_mac.h" -#endif - -#if defined(OS_MACOSX) -#ifdef __OBJC__ -@class CALayer; -@class NSWindow; -#else -class CALayer; -class NSWindow; -#endif -#endif - -namespace atom { - -class AtomCopyFrameGenerator; -class AtomBeginFrameTimer; - -class OffScreenRenderWidgetHostView - : public content::RenderWidgetHostViewBase, -#if defined(OS_MACOSX) - public ui::AcceleratedWidgetMacNSView, -#endif - public ui::CompositorDelegate, - public content::DelegatedFrameHostClient { - public: - OffScreenRenderWidgetHostView(bool transparent, - const OnPaintCallback& callback, - content::RenderWidgetHost* render_widget_host, - NativeWindow* native_window); - ~OffScreenRenderWidgetHostView() override; - - // content::RenderWidgetHostView: - bool OnMessageReceived(const IPC::Message&) override; - void InitAsChild(gfx::NativeView) override; - content::RenderWidgetHost* GetRenderWidgetHost(void) const override; - void SetSize(const gfx::Size &) override; - void SetBounds(const gfx::Rect &) override; - gfx::Vector2dF GetLastScrollOffset(void) const override; - gfx::NativeView GetNativeView(void) const override; - gfx::NativeViewAccessible GetNativeViewAccessible(void) override; - ui::TextInputClient* GetTextInputClient() override; - void Focus(void) override; - bool HasFocus(void) const override; - bool IsSurfaceAvailableForCopy(void) const override; - void Show(void) override; - void Hide(void) override; - bool IsShowing(void) override; - gfx::Rect GetViewBounds(void) const override; - gfx::Size GetVisibleViewportSize() const override; - void SetInsets(const gfx::Insets&) override; - void SetBackgroundColor(SkColor color) override; - bool LockMouse(void) override; - void UnlockMouse(void) override; - bool GetScreenColorProfile(std::vector*) override; -#if defined(OS_MACOSX) - ui::AcceleratedWidgetMac* GetAcceleratedWidgetMac() const override; - void SetActive(bool active) override; - void ShowDefinitionForSelection() override; - bool SupportsSpeech() const override; - void SpeakSelection() override; - bool IsSpeaking() const override; - void StopSpeaking() override; -#endif // defined(OS_MACOSX) - - // content::RenderWidgetHostViewBase: - void OnSwapCompositorFrame(uint32_t, std::unique_ptr) - override; - void ClearCompositorFrame(void) override; - void InitAsPopup(content::RenderWidgetHostView *rwhv, const gfx::Rect& rect) - override; - void InitAsFullscreen(content::RenderWidgetHostView *) override; - void UpdateCursor(const content::WebCursor &) override; - void SetIsLoading(bool is_loading) override; - void TextInputStateChanged(const content::TextInputState& params) override; - void ImeCancelComposition(void) override; - void RenderProcessGone(base::TerminationStatus, int) override; - void Destroy(void) override; - void SetTooltipText(const base::string16 &) override; -#if defined(OS_MACOSX) - void SelectionChanged(const base::string16& text, - size_t offset, - const gfx::Range& range) override; -#endif - void SelectionBoundsChanged(const ViewHostMsg_SelectionBounds_Params &) - override; - void CopyFromCompositingSurface(const gfx::Rect &, - const gfx::Size &, - const content::ReadbackRequestCallback &, - const SkColorType) override; - void CopyFromCompositingSurfaceToVideoFrame( - const gfx::Rect &, - const scoped_refptr &, - const base::Callback &) override; - bool CanCopyToVideoFrame(void) const override; - void BeginFrameSubscription( - std::unique_ptr) override; - void EndFrameSubscription() override; - bool HasAcceleratedSurface(const gfx::Size &) override; - void GetScreenInfo(blink::WebScreenInfo *) override; - bool GetScreenColorProfile(blink::WebVector*); - gfx::Rect GetBoundsInRootWindow(void) override; - void LockCompositingSurface(void) override; - void UnlockCompositingSurface(void) override; - void ImeCompositionRangeChanged( - const gfx::Range &, const std::vector&) override; - gfx::Size GetPhysicalBackingSize() const override; - gfx::Size GetRequestedRendererSize() const override; - - // content::DelegatedFrameHostClient: - int DelegatedFrameHostGetGpuMemoryBufferClientId(void) const; - ui::Layer *DelegatedFrameHostGetLayer(void) const override; - bool DelegatedFrameHostIsVisible(void) const override; - SkColor DelegatedFrameHostGetGutterColor(SkColor) const override; - gfx::Size DelegatedFrameHostDesiredSizeInDIP(void) const override; - bool DelegatedFrameCanCreateResizeLock(void) const override; - std::unique_ptr DelegatedFrameHostCreateResizeLock( - bool defer_compositor_lock) override; - void DelegatedFrameHostResizeLockWasReleased(void) override; - void DelegatedFrameHostSendCompositorSwapAck( - int, const cc::CompositorFrameAck &) override; - void DelegatedFrameHostSendReclaimCompositorResources( - int, const cc::CompositorFrameAck &) override; - void DelegatedFrameHostOnLostCompositorResources(void) override; - void DelegatedFrameHostUpdateVSyncParameters( - const base::TimeTicks &, const base::TimeDelta &) override; - void SetBeginFrameSource(cc::BeginFrameSource* source) override; - - // ui::CompositorDelegate: - std::unique_ptr CreateSoftwareOutputDevice( - ui::Compositor* compositor) override; - - bool InstallTransparency(); - bool IsAutoResizeEnabled() const; - void OnSetNeedsBeginFrames(bool enabled); - -#if defined(OS_MACOSX) - // ui::AcceleratedWidgetMacNSView: - NSView* AcceleratedWidgetGetNSView() const override; - void AcceleratedWidgetGetVSyncParameters( - base::TimeTicks* timebase, base::TimeDelta* interval) const override; - void AcceleratedWidgetSwapCompleted() override; -#endif // defined(OS_MACOSX) - - void OnBeginFrameTimerTick(); - void SendBeginFrame(base::TimeTicks frame_time, - base::TimeDelta vsync_period); - -#if defined(OS_MACOSX) - void CreatePlatformWidget(); - void DestroyPlatformWidget(); -#endif - - void OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap); - - void SetPainting(bool painting); - bool IsPainting() const; - - void SetFrameRate(int frame_rate); - int GetFrameRate() const; - - ui::Compositor* compositor() const { return compositor_.get(); } - content::RenderWidgetHostImpl* render_widget_host() const - { return render_widget_host_; } - - private: - void SetupFrameRate(bool force); - void ResizeRootLayer(); - - // Weak ptrs. - content::RenderWidgetHostImpl* render_widget_host_; - NativeWindow* native_window_; - OffScreenOutputDevice* software_output_device_; - - const bool transparent_; - OnPaintCallback callback_; - - int frame_rate_; - int frame_rate_threshold_ms_; - - base::Time last_time_; - - float scale_factor_; - bool is_showing_; - gfx::Vector2dF last_scroll_offset_; - gfx::Size size_; - bool painting_; - - std::unique_ptr root_layer_; - std::unique_ptr compositor_; - std::unique_ptr delegated_frame_host_; - - std::unique_ptr copy_frame_generator_; - std::unique_ptr begin_frame_timer_; - -#if defined(OS_MACOSX) - NSWindow* window_; - CALayer* background_layer_; - std::unique_ptr browser_compositor_; - - // Selected text on the renderer. - std::string selected_text_; -#endif - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(OffScreenRenderWidgetHostView); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_OSR_OSR_RENDER_WIDGET_HOST_VIEW_H_ diff --git a/atom/browser/osr/osr_render_widget_host_view_mac.mm b/atom/browser/osr/osr_render_widget_host_view_mac.mm deleted file mode 100644 index 511012f5db234..0000000000000 --- a/atom/browser/osr/osr_render_widget_host_view_mac.mm +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/osr/osr_render_widget_host_view.h" - -#import - -#include "base/strings/utf_string_conversions.h" -#include "ui/accelerated_widget_mac/accelerated_widget_mac.h" - -ui::AcceleratedWidgetMac* -atom::OffScreenRenderWidgetHostView::GetAcceleratedWidgetMac() const { - if (browser_compositor_) - return browser_compositor_->accelerated_widget_mac(); - return nullptr; -} - -NSView* atom::OffScreenRenderWidgetHostView::AcceleratedWidgetGetNSView() - const { - return [window_ contentView]; -} - -void atom::OffScreenRenderWidgetHostView::AcceleratedWidgetGetVSyncParameters( - base::TimeTicks* timebase, base::TimeDelta* interval) const { - *timebase = base::TimeTicks(); - *interval = base::TimeDelta(); -} - -void atom::OffScreenRenderWidgetHostView::AcceleratedWidgetSwapCompleted() { -} - -void atom::OffScreenRenderWidgetHostView::SetActive(bool active) { -} - -void atom::OffScreenRenderWidgetHostView::ShowDefinitionForSelection() { -} - -bool atom::OffScreenRenderWidgetHostView::SupportsSpeech() const { - return false; -} - -void atom::OffScreenRenderWidgetHostView::SpeakSelection() { -} - -bool atom::OffScreenRenderWidgetHostView::IsSpeaking() const { - return false; -} - -void atom::OffScreenRenderWidgetHostView::StopSpeaking() { -} - -void atom::OffScreenRenderWidgetHostView::SelectionChanged( - const base::string16& text, - size_t offset, - const gfx::Range& range) { - if (range.is_empty() || text.empty()) { - selected_text_.clear(); - } else { - size_t pos = range.GetMin() - offset; - size_t n = range.length(); - - DCHECK(pos + n <= text.length()) << "The text can not fully cover range."; - if (pos >= text.length()) { - DCHECK(false) << "The text can not cover range."; - return; - } - selected_text_ = base::UTF16ToUTF8(text.substr(pos, n)); - } - - RenderWidgetHostViewBase::SelectionChanged(text, offset, range); -} - -void atom::OffScreenRenderWidgetHostView::CreatePlatformWidget() { - window_ = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1, 1) - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - - background_layer_ = [[[CALayer alloc] init] retain]; - [background_layer_ setBackgroundColor:CGColorGetConstantColor(kCGColorClear)]; - NSView* content_view = [window_ contentView]; - [content_view setLayer:background_layer_]; - [content_view setWantsLayer:YES]; - - browser_compositor_ = content::BrowserCompositorMac::Create(); - - compositor_.reset(browser_compositor_->compositor()); - compositor_->SetRootLayer(root_layer_.get()); - browser_compositor_->accelerated_widget_mac()->SetNSView(this); - browser_compositor_->compositor()->SetVisible(true); - - compositor_->SetLocksWillTimeOut(true); - browser_compositor_->Unsuspend(); -} - -void atom::OffScreenRenderWidgetHostView::DestroyPlatformWidget() { - DCHECK(window_); - - ui::Compositor* compositor = compositor_.release(); - ALLOW_UNUSED_LOCAL(compositor); - - [window_ close]; - window_ = nil; - [background_layer_ release]; - background_layer_ = nil; - - browser_compositor_->accelerated_widget_mac()->ResetNSView(); - browser_compositor_->compositor()->SetVisible(false); - browser_compositor_->compositor()->SetScaleAndSize(1.0, gfx::Size(0, 0)); - browser_compositor_->compositor()->SetRootLayer(NULL); - content::BrowserCompositorMac::Recycle(std::move(browser_compositor_)); -} diff --git a/atom/browser/osr/osr_web_contents_view.cc b/atom/browser/osr/osr_web_contents_view.cc deleted file mode 100644 index 35aa7dcc3a7a6..0000000000000 --- a/atom/browser/osr/osr_web_contents_view.cc +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/osr/osr_web_contents_view.h" - -namespace atom { - -OffScreenWebContentsView::OffScreenWebContentsView( - bool transparent, const OnPaintCallback& callback) - : transparent_(transparent), - callback_(callback), - web_contents_(nullptr) { -#if defined(OS_MACOSX) - PlatformCreate(); -#endif -} - -OffScreenWebContentsView::~OffScreenWebContentsView() { -#if defined(OS_MACOSX) - PlatformDestroy(); -#endif -} - -void OffScreenWebContentsView::SetWebContents( - content::WebContents* web_contents) { - web_contents_ = web_contents; -} - -#if !defined(OS_MACOSX) -gfx::NativeView OffScreenWebContentsView::GetNativeView() const { - return gfx::NativeView(); -} - -gfx::NativeView OffScreenWebContentsView::GetContentNativeView() const { - return gfx::NativeView(); -} - -gfx::NativeWindow OffScreenWebContentsView::GetTopLevelNativeWindow() const { - return gfx::NativeWindow(); -} -#endif - -void OffScreenWebContentsView::GetContainerBounds(gfx::Rect* out) const { - *out = GetViewBounds(); -} - -void OffScreenWebContentsView::SizeContents(const gfx::Size& size) { -} - -void OffScreenWebContentsView::Focus() { -} - -void OffScreenWebContentsView::SetInitialFocus() { -} - -void OffScreenWebContentsView::StoreFocus() { -} - -void OffScreenWebContentsView::RestoreFocus() { -} - -content::DropData* OffScreenWebContentsView::GetDropData() const { - return nullptr; -} - -gfx::Rect OffScreenWebContentsView::GetViewBounds() const { - return view_ ? view_->GetViewBounds() : gfx::Rect(); -} - -void OffScreenWebContentsView::CreateView(const gfx::Size& initial_size, - gfx::NativeView context) { -} - -content::RenderWidgetHostViewBase* - OffScreenWebContentsView::CreateViewForWidget( - content::RenderWidgetHost* render_widget_host, bool is_guest_view_hack) { - auto relay = NativeWindowRelay::FromWebContents(web_contents_); - view_ = new OffScreenRenderWidgetHostView( - transparent_, callback_, render_widget_host, relay->window.get()); - return view_; -} - -content::RenderWidgetHostViewBase* - OffScreenWebContentsView::CreateViewForPopupWidget( - content::RenderWidgetHost* render_widget_host) { - auto relay = NativeWindowRelay::FromWebContents(web_contents_); - view_ = new OffScreenRenderWidgetHostView( - transparent_, callback_, render_widget_host, relay->window.get()); - return view_; -} - -void OffScreenWebContentsView::SetPageTitle(const base::string16& title) { -} - -void OffScreenWebContentsView::RenderViewCreated( - content::RenderViewHost* host) { - if (view_) - view_->InstallTransparency(); -} - -void OffScreenWebContentsView::RenderViewSwappedIn( - content::RenderViewHost* host) { -} - -void OffScreenWebContentsView::SetOverscrollControllerEnabled(bool enabled) { -} - -#if defined(OS_MACOSX) -void OffScreenWebContentsView::SetAllowOtherViews(bool allow) { -} - -bool OffScreenWebContentsView::GetAllowOtherViews() const { - return false; -} - -bool OffScreenWebContentsView::IsEventTracking() const { - return false; -} - -void OffScreenWebContentsView::CloseTabAfterEventTracking() { -} -#endif // defined(OS_MACOSX) - -void OffScreenWebContentsView::StartDragging( - const content::DropData& drop_data, - blink::WebDragOperationsMask allowed_ops, - const gfx::ImageSkia& image, - const gfx::Vector2d& image_offset, - const content::DragEventSourceInfo& event_info) { - if (web_contents_) - web_contents_->SystemDragEnded(); -} - -void OffScreenWebContentsView::UpdateDragCursor( - blink::WebDragOperation operation) { -} - -} // namespace atom diff --git a/atom/browser/osr/osr_web_contents_view.h b/atom/browser/osr/osr_web_contents_view.h deleted file mode 100644 index d47f71b1e90a1..0000000000000 --- a/atom/browser/osr/osr_web_contents_view.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_OSR_OSR_WEB_CONTENTS_VIEW_H_ -#define ATOM_BROWSER_OSR_OSR_WEB_CONTENTS_VIEW_H_ - -#include "atom/browser/osr/osr_render_widget_host_view.h" -#include "content/browser/renderer_host/render_view_host_delegate_view.h" -#include "content/browser/web_contents/web_contents_view.h" -#include "content/public/browser/web_contents.h" - -#if defined(OS_MACOSX) -#ifdef __OBJC__ -@class OffScreenView; -#else -class OffScreenView; -#endif -#endif - -namespace atom { - -class OffScreenWebContentsView : public content::WebContentsView, - public content::RenderViewHostDelegateView { - public: - OffScreenWebContentsView(bool transparent, const OnPaintCallback& callback); - ~OffScreenWebContentsView(); - - void SetWebContents(content::WebContents*); - - // content::WebContentsView: - gfx::NativeView GetNativeView() const override; - gfx::NativeView GetContentNativeView() const override; - gfx::NativeWindow GetTopLevelNativeWindow() const override; - void GetContainerBounds(gfx::Rect* out) const override; - void SizeContents(const gfx::Size& size) override; - void Focus() override; - void SetInitialFocus() override; - void StoreFocus() override; - void RestoreFocus() override; - content::DropData* GetDropData() const override; - gfx::Rect GetViewBounds() const override; - void CreateView( - const gfx::Size& initial_size, gfx::NativeView context) override; - content::RenderWidgetHostViewBase* CreateViewForWidget( - content::RenderWidgetHost* render_widget_host, - bool is_guest_view_hack) override; - content::RenderWidgetHostViewBase* CreateViewForPopupWidget( - content::RenderWidgetHost* render_widget_host) override; - void SetPageTitle(const base::string16& title) override; - void RenderViewCreated(content::RenderViewHost* host) override; - void RenderViewSwappedIn(content::RenderViewHost* host) override; - void SetOverscrollControllerEnabled(bool enabled) override; - -#if defined(OS_MACOSX) - void SetAllowOtherViews(bool allow) override; - bool GetAllowOtherViews() const override; - bool IsEventTracking() const override; - void CloseTabAfterEventTracking() override; -#endif - - // content::RenderViewHostDelegateView - void StartDragging( - const content::DropData& drop_data, - blink::WebDragOperationsMask allowed_ops, - const gfx::ImageSkia& image, - const gfx::Vector2d& image_offset, - const content::DragEventSourceInfo& event_info) override; - void UpdateDragCursor(blink::WebDragOperation operation) override; - - private: -#if defined(OS_MACOSX) - void PlatformCreate(); - void PlatformDestroy(); -#endif - - const bool transparent_; - OnPaintCallback callback_; - - // Weak refs. - OffScreenRenderWidgetHostView* view_; - content::WebContents* web_contents_; - -#if defined(OS_MACOSX) - OffScreenView* offScreenView_; -#endif -}; - -} // namespace atom - -#endif // ATOM_BROWSER_OSR_OSR_WEB_CONTENTS_VIEW_H_ diff --git a/atom/browser/osr/osr_web_contents_view_mac.mm b/atom/browser/osr/osr_web_contents_view_mac.mm deleted file mode 100644 index ba99c0cb959c9..0000000000000 --- a/atom/browser/osr/osr_web_contents_view_mac.mm +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/osr/osr_web_contents_view.h" - -@interface OffScreenView : NSView -@end - -@implementation OffScreenView - -- (void)drawRect:(NSRect)dirtyRect { - NSString* str = @"No content under offscreen mode"; - NSMutableParagraphStyle* paragraphStyle = - [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease]; - [paragraphStyle setAlignment:NSCenterTextAlignment]; - NSDictionary* attributes = [NSDictionary - dictionaryWithObject:paragraphStyle - forKey:NSParagraphStyleAttributeName]; - NSAttributedString* text = - [[[NSAttributedString alloc] initWithString:str - attributes:attributes] autorelease]; - NSRect frame = NSMakeRect(0, (self.frame.size.height - text.size.height) / 2, - self.frame.size.width, text.size.height); - [str drawInRect:frame withAttributes:attributes]; -} - -@end - -namespace atom { - -gfx::NativeView OffScreenWebContentsView::GetNativeView() const { - return offScreenView_; -} - -gfx::NativeView OffScreenWebContentsView::GetContentNativeView() const { - return offScreenView_; -} - -gfx::NativeWindow OffScreenWebContentsView::GetTopLevelNativeWindow() const { - return [offScreenView_ window]; -} - -void OffScreenWebContentsView::PlatformCreate() { - offScreenView_ = [[OffScreenView alloc] init]; -} - -void OffScreenWebContentsView::PlatformDestroy() { - [offScreenView_ release]; -} - -} // namespace atom diff --git a/atom/browser/relauncher.cc b/atom/browser/relauncher.cc deleted file mode 100644 index 9610d80693b16..0000000000000 --- a/atom/browser/relauncher.cc +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/relauncher.h" - -#include -#include - -#include "atom/common/atom_command_line.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "base/process/launch.h" -#include "content/public/common/content_paths.h" -#include "content/public/common/content_switches.h" -#include "content/public/common/main_function_params.h" - -#if defined(OS_POSIX) -#include "base/posix/eintr_wrapper.h" -#endif - -namespace relauncher { - -namespace internal { - -#if defined(OS_POSIX) -const int kRelauncherSyncFD = STDERR_FILENO + 1; -#endif - -const CharType* kRelauncherTypeArg = FILE_PATH_LITERAL("--type=relauncher"); -const CharType* kRelauncherArgSeparator = FILE_PATH_LITERAL("---"); - -} // namespace internal - -bool RelaunchApp(const StringVector& argv) { - // Use the currently-running application's helper process. The automatic - // update feature is careful to leave the currently-running version alone, - // so this is safe even if the relaunch is the result of an update having - // been applied. In fact, it's safer than using the updated version of the - // helper process, because there's no guarantee that the updated version's - // relauncher implementation will be compatible with the running version's. - base::FilePath child_path; - if (!PathService::Get(content::CHILD_PROCESS_EXE, &child_path)) { - LOG(ERROR) << "No CHILD_PROCESS_EXE"; - return false; - } - - StringVector relauncher_args; - return RelaunchAppWithHelper(child_path, relauncher_args, argv); -} - -bool RelaunchAppWithHelper(const base::FilePath& helper, - const StringVector& relauncher_args, - const StringVector& argv) { - StringVector relaunch_argv; - relaunch_argv.push_back(helper.value()); - relaunch_argv.push_back(internal::kRelauncherTypeArg); - - relaunch_argv.insert(relaunch_argv.end(), - relauncher_args.begin(), relauncher_args.end()); - - relaunch_argv.push_back(internal::kRelauncherArgSeparator); - - relaunch_argv.insert(relaunch_argv.end(), argv.begin(), argv.end()); - -#if defined(OS_POSIX) - int pipe_fds[2]; - if (HANDLE_EINTR(pipe(pipe_fds)) != 0) { - PLOG(ERROR) << "pipe"; - return false; - } - - // The parent process will only use pipe_read_fd as the read side of the - // pipe. It can close the write side as soon as the relauncher process has - // forked off. The relauncher process will only use pipe_write_fd as the - // write side of the pipe. In that process, the read side will be closed by - // base::LaunchApp because it won't be present in fd_map, and the write side - // will be remapped to kRelauncherSyncFD by fd_map. - base::ScopedFD pipe_read_fd(pipe_fds[0]); - base::ScopedFD pipe_write_fd(pipe_fds[1]); - - // Make sure kRelauncherSyncFD is a safe value. base::LaunchProcess will - // preserve these three FDs in forked processes, so kRelauncherSyncFD should - // not conflict with them. - static_assert(internal::kRelauncherSyncFD != STDIN_FILENO && - internal::kRelauncherSyncFD != STDOUT_FILENO && - internal::kRelauncherSyncFD != STDERR_FILENO, - "kRelauncherSyncFD must not conflict with stdio fds"); - - base::FileHandleMappingVector fd_map; - fd_map.push_back( - std::make_pair(pipe_write_fd.get(), internal::kRelauncherSyncFD)); -#endif - - base::LaunchOptions options; -#if defined(OS_POSIX) - options.fds_to_remap = &fd_map; - base::Process process = base::LaunchProcess(relaunch_argv, options); -#elif defined(OS_WIN) - base::Process process = base::LaunchProcess( - internal::ArgvToCommandLineString(relaunch_argv), options); -#endif - if (!process.IsValid()) { - LOG(ERROR) << "base::LaunchProcess failed"; - return false; - } - - // The relauncher process is now starting up, or has started up. The - // original parent process continues. - -#if defined(OS_WIN) - // Synchronize with the relauncher process. - StringType name = internal::GetWaitEventName(process.Pid()); - HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, name.c_str()); - if (wait_event != NULL) { - WaitForSingleObject(wait_event, 1000); - CloseHandle(wait_event); - } -#elif defined(OS_POSIX) - pipe_write_fd.reset(); // close(pipe_fds[1]); - - // Synchronize with the relauncher process. - char read_char; - int read_result = HANDLE_EINTR(read(pipe_read_fd.get(), &read_char, 1)); - if (read_result != 1) { - if (read_result < 0) { - PLOG(ERROR) << "read"; - } else { - LOG(ERROR) << "read: unexpected result " << read_result; - } - return false; - } - - // Since a byte has been successfully read from the relauncher process, it's - // guaranteed to have set up its kqueue monitoring this process for exit. - // It's safe to exit now. -#endif - return true; -} - -int RelauncherMain(const content::MainFunctionParams& main_parameters) { -#if defined(OS_WIN) - const StringVector& argv = atom::AtomCommandLine::wargv(); -#else - const StringVector& argv = atom::AtomCommandLine::argv(); -#endif - - if (argv.size() < 4 || argv[1] != internal::kRelauncherTypeArg) { - LOG(ERROR) << "relauncher process invoked with unexpected arguments"; - return 1; - } - - internal::RelauncherSynchronizeWithParent(); - - // Figure out what to execute, what arguments to pass it, and whether to - // start it in the background. - bool in_relauncher_args = false; - StringType relaunch_executable; - StringVector relauncher_args; - StringVector launch_argv; - for (size_t argv_index = 2; argv_index < argv.size(); ++argv_index) { - const StringType& arg(argv[argv_index]); - if (!in_relauncher_args) { - if (arg == internal::kRelauncherArgSeparator) { - in_relauncher_args = true; - } else { - relauncher_args.push_back(arg); - } - } else { - launch_argv.push_back(arg); - } - } - - if (launch_argv.empty()) { - LOG(ERROR) << "nothing to relaunch"; - return 1; - } - - if (internal::LaunchProgram(relauncher_args, launch_argv) != 0) { - LOG(ERROR) << "failed to launch program"; - return 1; - } - - // The application should have relaunched (or is in the process of - // relaunching). From this point on, only clean-up tasks should occur, and - // failures are tolerable. - - return 0; -} - -} // namespace relauncher diff --git a/atom/browser/relauncher_linux.cc b/atom/browser/relauncher_linux.cc deleted file mode 100644 index 6d60b072f6d92..0000000000000 --- a/atom/browser/relauncher_linux.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/relauncher.h" - -#include -#include -#include -#include - -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" -#include "base/process/launch.h" - -namespace relauncher { - -namespace internal { - -void RelauncherSynchronizeWithParent() { - base::ScopedFD relauncher_sync_fd(kRelauncherSyncFD); - - // Don't execute signal handlers of SIGUSR2. - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGUSR2); - if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { - PLOG(ERROR) << "sigprocmask"; - return; - } - - // Create a signalfd that watches for SIGUSR2. - int usr2_fd = signalfd(-1, &mask, 0); - if (usr2_fd < 0) { - PLOG(ERROR) << "signalfd"; - return; - } - - // Send SIGUSR2 to current process when parent process ends. - if (HANDLE_EINTR(prctl(PR_SET_PDEATHSIG, SIGUSR2)) != 0) { - PLOG(ERROR) << "prctl"; - return; - } - - // Write a '\0' character to the pipe. - if (HANDLE_EINTR(write(relauncher_sync_fd.get(), "", 1)) != 1) { - PLOG(ERROR) << "write"; - return; - } - - // Wait the SIGUSR2 signal to happen. - struct signalfd_siginfo si; - HANDLE_EINTR(read(usr2_fd, &si, sizeof(si))); -} - -int LaunchProgram(const StringVector& relauncher_args, - const StringVector& argv) { - // Redirect the stdout of child process to /dev/null, otherwise after - // relaunch the child process will raise exception when writing to stdout. - base::ScopedFD devnull(HANDLE_EINTR(open("/dev/null", O_WRONLY))); - base::FileHandleMappingVector no_stdout; - no_stdout.push_back(std::make_pair(devnull.get(), STDERR_FILENO)); - no_stdout.push_back(std::make_pair(devnull.get(), STDOUT_FILENO)); - - base::LaunchOptions options; - options.allow_new_privs = true; - options.new_process_group = true; // detach - options.fds_to_remap = &no_stdout; - base::Process process = base::LaunchProcess(argv, options); - return process.IsValid() ? 0 : 1; -} - -} // namespace internal - -} // namespace relauncher diff --git a/atom/browser/relauncher_win.cc b/atom/browser/relauncher_win.cc deleted file mode 100644 index 1aebb515ecf0f..0000000000000 --- a/atom/browser/relauncher_win.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/relauncher.h" - -#include - -#include "base/process/launch.h" -#include "base/strings/stringprintf.h" -#include "base/win/scoped_handle.h" -#include "sandbox/win/src/nt_internals.h" -#include "sandbox/win/src/win_utils.h" -#include "ui/base/win/shell.h" - -namespace relauncher { - -namespace internal { - -namespace { - -const CharType* kWaitEventName = L"ElectronRelauncherWaitEvent"; - -HANDLE GetParentProcessHandle(base::ProcessHandle handle) { - NtQueryInformationProcessFunction NtQueryInformationProcess = nullptr; - ResolveNTFunctionPtr("NtQueryInformationProcess", &NtQueryInformationProcess); - if (!NtQueryInformationProcess) { - LOG(ERROR) << "Unable to get NtQueryInformationProcess"; - return NULL; - } - - PROCESS_BASIC_INFORMATION pbi; - LONG status = NtQueryInformationProcess( - handle, ProcessBasicInformation, - &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL); - if (!NT_SUCCESS(status)) { - LOG(ERROR) << "NtQueryInformationProcess failed"; - return NULL; - } - - return ::OpenProcess(PROCESS_ALL_ACCESS, TRUE, - pbi.InheritedFromUniqueProcessId); -} - -StringType AddQuoteForArg(const StringType& arg) { - // We follow the quoting rules of CommandLineToArgvW. - // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx - std::wstring quotable_chars(L" \\\""); - if (arg.find_first_of(quotable_chars) == std::wstring::npos) { - // No quoting necessary. - return arg; - } - - std::wstring out; - out.push_back(L'"'); - for (size_t i = 0; i < arg.size(); ++i) { - if (arg[i] == '\\') { - // Find the extent of this run of backslashes. - size_t start = i, end = start + 1; - for (; end < arg.size() && arg[end] == '\\'; ++end) {} - size_t backslash_count = end - start; - - // Backslashes are escapes only if the run is followed by a double quote. - // Since we also will end the string with a double quote, we escape for - // either a double quote or the end of the string. - if (end == arg.size() || arg[end] == '"') { - // To quote, we need to output 2x as many backslashes. - backslash_count *= 2; - } - for (size_t j = 0; j < backslash_count; ++j) - out.push_back('\\'); - - // Advance i to one before the end to balance i++ in loop. - i = end - 1; - } else if (arg[i] == '"') { - out.push_back('\\'); - out.push_back('"'); - } else { - out.push_back(arg[i]); - } - } - out.push_back('"'); - - return out; -} - -} // namespace - -StringType GetWaitEventName(base::ProcessId pid) { - return base::StringPrintf(L"%s-%d", kWaitEventName, static_cast(pid)); -} - -StringType ArgvToCommandLineString(const StringVector& argv) { - StringType command_line; - for (const StringType& arg : argv) { - if (!command_line.empty()) - command_line += L' '; - command_line += AddQuoteForArg(arg); - } - return command_line; -} - -void RelauncherSynchronizeWithParent() { - base::Process process = base::Process::Current(); - base::win::ScopedHandle parent_process( - GetParentProcessHandle(process.Handle())); - - // Notify the parent process that it can quit now. - StringType name = internal::GetWaitEventName(process.Pid()); - base::win::ScopedHandle wait_event( - ::CreateEventW(NULL, TRUE, FALSE, name.c_str())); - ::SetEvent(wait_event.Get()); - - // Wait for parent process to quit. - WaitForSingleObject(parent_process.Get(), INFINITE); -} - -int LaunchProgram(const StringVector& relauncher_args, - const StringVector& argv) { - base::LaunchOptions options; - base::Process process = - base::LaunchProcess(ArgvToCommandLineString(argv), options); - return process.IsValid() ? 0 : 1; -} - -} // namespace internal - -} // namespace relauncher diff --git a/atom/browser/render_process_preferences.cc b/atom/browser/render_process_preferences.cc deleted file mode 100644 index d109c8714f708..0000000000000 --- a/atom/browser/render_process_preferences.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/render_process_preferences.h" - -#include "atom/common/api/api_messages.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_types.h" -#include "content/public/browser/render_process_host.h" - -namespace atom { - -RenderProcessPreferences::RenderProcessPreferences(const Predicate& predicate) - : predicate_(predicate), - next_id_(0), - cache_needs_update_(true) { - registrar_.Add(this, - content::NOTIFICATION_RENDERER_PROCESS_CREATED, - content::NotificationService::AllBrowserContextsAndSources()); -} - -RenderProcessPreferences::~RenderProcessPreferences() { -} - -int RenderProcessPreferences::AddEntry(const base::DictionaryValue& entry) { - int id = ++next_id_; - entries_[id] = entry.CreateDeepCopy(); - cache_needs_update_ = true; - return id; -} - -void RenderProcessPreferences::RemoveEntry(int id) { - cache_needs_update_ = true; - entries_.erase(id); -} - -void RenderProcessPreferences::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_EQ(type, content::NOTIFICATION_RENDERER_PROCESS_CREATED); - content::RenderProcessHost* process = - content::Source(source).ptr(); - - if (!predicate_.Run(process)) - return; - - UpdateCache(); - process->Send(new AtomMsg_UpdatePreferences(cached_entries_)); -} - -void RenderProcessPreferences::UpdateCache() { - if (!cache_needs_update_) - return; - - cached_entries_.Clear(); - for (const auto& iter : entries_) - cached_entries_.Append(iter.second->CreateDeepCopy()); - cache_needs_update_ = false; -} - -} // namespace atom diff --git a/atom/browser/render_process_preferences.h b/atom/browser/render_process_preferences.h deleted file mode 100644 index 77bf176f492ca..0000000000000 --- a/atom/browser/render_process_preferences.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_RENDER_PROCESS_PREFERENCES_H_ -#define ATOM_BROWSER_RENDER_PROCESS_PREFERENCES_H_ - -#include -#include - -#include "base/callback.h" -#include "base/values.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" - -namespace content { -class RenderProcessHost; -} - -namespace atom { - -// Sets user preferences for render processes. -class RenderProcessPreferences : public content::NotificationObserver { - public: - using Predicate = base::Callback; - - // The |predicate| is used to determine whether to set preferences for a - // render process. - explicit RenderProcessPreferences(const Predicate& predicate); - virtual ~RenderProcessPreferences(); - - int AddEntry(const base::DictionaryValue& entry); - void RemoveEntry(int id); - - private: - // content::NotificationObserver: - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - void UpdateCache(); - - // Manages our notification registrations. - content::NotificationRegistrar registrar_; - - Predicate predicate_; - - int next_id_; - std::unordered_map> entries_; - - // We need to convert the |entries_| to ListValue for multiple times, this - // caches is only updated when we are sending messages. - bool cache_needs_update_; - base::ListValue cached_entries_; - - DISALLOW_COPY_AND_ASSIGN(RenderProcessPreferences); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_RENDER_PROCESS_PREFERENCES_H_ diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist deleted file mode 100644 index 5e3f2063ea4a3..0000000000000 --- a/atom/browser/resources/mac/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDisplayName - ${PRODUCT_NAME} - CFBundleExecutable - ${PRODUCT_NAME} - CFBundleIdentifier - ${ATOM_BUNDLE_ID} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - CFBundleIconFile - electron.icns - CFBundleVersion - 1.3.2 - CFBundleShortVersionString - 1.3.2 - LSApplicationCategoryType - public.app-category.developer-tools - LSMinimumSystemVersion - 10.9.0 - NSMainNibFile - MainMenu - NSPrincipalClass - AtomApplication - NSSupportsAutomaticGraphicsSwitching - - NSHighResolutionCapable - - - diff --git a/atom/browser/resources/mac/electron.icns b/atom/browser/resources/mac/electron.icns deleted file mode 100644 index dac213ed9d8c0..0000000000000 Binary files a/atom/browser/resources/mac/electron.icns and /dev/null differ diff --git a/atom/browser/resources/win/atom.ico b/atom/browser/resources/win/atom.ico deleted file mode 100644 index 004176004f740..0000000000000 Binary files a/atom/browser/resources/win/atom.ico and /dev/null differ diff --git a/atom/browser/resources/win/atom.manifest b/atom/browser/resources/win/atom.manifest deleted file mode 100644 index 64c07ded17b09..0000000000000 --- a/atom/browser/resources/win/atom.manifest +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - true - - - - diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc deleted file mode 100644 index c96b9ef4a83dd..0000000000000 --- a/atom/browser/resources/win/atom.rc +++ /dev/null @@ -1,139 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "grit\\ui_unscaled_resources.h" -#include "resource.h" -#include -#ifdef IDC_STATIC -#undef IDC_STATIC -#endif -#define IDC_STATIC (-1) - -#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 1,3,2,0 - PRODUCTVERSION 1,3,2,0 - 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", "1.3.2" - VALUE "InternalName", "electron.exe" - VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." - VALUE "OriginalFilename", "electron.exe" - VALUE "ProductName", "Electron" - VALUE "ProductVersion", "1.3.2" - 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 "atom.ico" -///////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////// -// -// Cursors -// -IDC_ALIAS CURSOR "ui\\resources\\cursors\\aliasb.cur" -IDC_CELL CURSOR "ui\\resources\\cursors\\cell.cur" -IDC_COLRESIZE CURSOR "ui\\resources\\cursors\\col_resize.cur" -IDC_COPYCUR CURSOR "ui\\resources\\cursors\\copy.cur" -IDC_CURSOR_NONE CURSOR "ui\\resources\\cursors\\none.cur" -IDC_HAND_GRAB CURSOR "ui\\resources\\cursors\\hand_grab.cur" -IDC_HAND_GRABBING CURSOR "ui\\resources\\cursors\\hand_grabbing.cur" -IDC_PAN_EAST CURSOR "ui\\resources\\cursors\\pan_east.cur" -IDC_PAN_MIDDLE CURSOR "ui\\resources\\cursors\\pan_middle.cur" -IDC_PAN_NORTH CURSOR "ui\\resources\\cursors\\pan_north.cur" -IDC_PAN_NORTH_EAST CURSOR "ui\\resources\\cursors\\pan_north_east.cur" -IDC_PAN_NORTH_WEST CURSOR "ui\\resources\\cursors\\pan_north_west.cur" -IDC_PAN_SOUTH CURSOR "ui\\resources\\cursors\\pan_south.cur" -IDC_PAN_SOUTH_EAST CURSOR "ui\\resources\\cursors\\pan_south_east.cur" -IDC_PAN_SOUTH_WEST CURSOR "ui\\resources\\cursors\\pan_south_west.cur" -IDC_PAN_WEST CURSOR "ui\\resources\\cursors\\pan_west.cur" -IDC_ROWRESIZE CURSOR "ui\\resources\\cursors\\row_resize.cur" -IDC_VERTICALTEXT CURSOR "ui\\resources\\cursors\\vertical_text.cur" -IDC_ZOOMIN CURSOR "ui\\resources\\cursors\\zoom_in.cur" -IDC_ZOOMOUT CURSOR "ui\\resources\\cursors\\zoom_out.cur" -///////////////////////////////////////////////////////////////////////////// diff --git a/atom/browser/resources/win/resource.h b/atom/browser/resources/win/resource.h deleted file mode 100644 index d35e16d082e6d..0000000000000 --- a/atom/browser/resources/win/resource.h +++ /dev/null @@ -1,15 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. - -#define IDR_MAINFRAME 1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/atom/browser/ui/accelerator_util.cc b/atom/browser/ui/accelerator_util.cc deleted file mode 100644 index eb89bf0c35f53..0000000000000 --- a/atom/browser/ui/accelerator_util.cc +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/accelerator_util.h" - -#include - -#include -#include - -#include "atom/common/keyboard_util.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" - -namespace accelerator_util { - -bool StringToAccelerator(const std::string& shortcut, - ui::Accelerator* accelerator) { - if (!base::IsStringASCII(shortcut)) { - LOG(ERROR) << "The accelerator string can only contain ASCII characters"; - return false; - } - - std::vector tokens = base::SplitString( - shortcut, "+", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - - // Now, parse it into an accelerator. - int modifiers = ui::EF_NONE; - ui::KeyboardCode key = ui::VKEY_UNKNOWN; - for (const auto& token : tokens) { - bool shifted = false; - ui::KeyboardCode code = atom::KeyboardCodeFromStr(token, &shifted); - if (shifted) - modifiers |= ui::EF_SHIFT_DOWN; - switch (code) { - // The token can be a modifier. - case ui::VKEY_SHIFT: - modifiers |= ui::EF_SHIFT_DOWN; - break; - case ui::VKEY_CONTROL: - modifiers |= ui::EF_CONTROL_DOWN; - break; - case ui::VKEY_MENU: - modifiers |= ui::EF_ALT_DOWN; - break; - case ui::VKEY_COMMAND: - modifiers |= ui::EF_COMMAND_DOWN; - break; - case ui::VKEY_ALTGR: - modifiers |= ui::EF_ALTGR_DOWN; - break; - // Or it is a normal key. - default: - key = code; - } - } - - if (key == ui::VKEY_UNKNOWN) { - LOG(WARNING) << shortcut << " doesn't contain a valid key"; - return false; - } - - *accelerator = ui::Accelerator(key, modifiers); - SetPlatformAccelerator(accelerator); - return true; -} - -void GenerateAcceleratorTable(AcceleratorTable* table, - atom::AtomMenuModel* model) { - int count = model->GetItemCount(); - for (int i = 0; i < count; ++i) { - atom::AtomMenuModel::ItemType type = model->GetTypeAt(i); - if (type == atom::AtomMenuModel::TYPE_SUBMENU) { - auto submodel = model->GetSubmenuModelAt(i); - GenerateAcceleratorTable(table, submodel); - } else { - ui::Accelerator accelerator; - if (model->GetAcceleratorAtWithParams(i, true, &accelerator)) { - MenuItem item = { i, model }; - (*table)[accelerator] = item; - } - } - } -} - -bool TriggerAcceleratorTableCommand(AcceleratorTable* table, - const ui::Accelerator& accelerator) { - if (ContainsKey(*table, accelerator)) { - const accelerator_util::MenuItem& item = (*table)[accelerator]; - item.model->ActivatedAt(item.position); - return true; - } else { - return false; - } -} - -} // namespace accelerator_util diff --git a/atom/browser/ui/accelerator_util.h b/atom/browser/ui/accelerator_util.h deleted file mode 100644 index 38f206f5376d3..0000000000000 --- a/atom/browser/ui/accelerator_util.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_ACCELERATOR_UTIL_H_ -#define ATOM_BROWSER_UI_ACCELERATOR_UTIL_H_ - -#include -#include - -#include "atom/browser/ui/atom_menu_model.h" -#include "ui/base/accelerators/accelerator.h" - -namespace accelerator_util { - -typedef struct { int position; atom::AtomMenuModel* model; } MenuItem; -typedef std::map AcceleratorTable; - -// Parse a string as an accelerator. -bool StringToAccelerator(const std::string& description, - ui::Accelerator* accelerator); - -// Set platform accelerator for the Accelerator. -void SetPlatformAccelerator(ui::Accelerator* accelerator); - -// Generate a table that contains memu model's accelerators and command ids. -void GenerateAcceleratorTable(AcceleratorTable* table, - atom::AtomMenuModel* model); - -// Trigger command from the accelerators table. -bool TriggerAcceleratorTableCommand(AcceleratorTable* table, - const ui::Accelerator& accelerator); - -} // namespace accelerator_util - -#endif // ATOM_BROWSER_UI_ACCELERATOR_UTIL_H_ diff --git a/atom/browser/ui/accelerator_util_mac.mm b/atom/browser/ui/accelerator_util_mac.mm deleted file mode 100644 index cf1d3de4d2126..0000000000000 --- a/atom/browser/ui/accelerator_util_mac.mm +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/accelerator_util.h" - -#include "ui/base/accelerators/accelerator.h" -#import "ui/base/accelerators/platform_accelerator_cocoa.h" -#import "ui/events/keycodes/keyboard_code_conversion_mac.h" - -namespace accelerator_util { - -void SetPlatformAccelerator(ui::Accelerator* accelerator) { - unichar character; - unichar characterIgnoringModifiers; - - NSUInteger modifiers = - (accelerator->IsCtrlDown() ? NSControlKeyMask : 0) | - (accelerator->IsCmdDown() ? NSCommandKeyMask : 0) | - (accelerator->IsAltDown() ? NSAlternateKeyMask : 0) | - (accelerator->IsShiftDown() ? NSShiftKeyMask : 0); - - ui::MacKeyCodeForWindowsKeyCode(accelerator->key_code(), - modifiers, - &character, - &characterIgnoringModifiers); - - if (character != characterIgnoringModifiers) { - modifiers ^= NSShiftKeyMask; - } - - if (character == NSDeleteFunctionKey) { - character = NSDeleteCharacter; - } - - NSString* characters = - [[[NSString alloc] initWithCharacters:&character length:1] autorelease]; - - std::unique_ptr platform_accelerator( - new ui::PlatformAcceleratorCocoa(characters, modifiers)); - accelerator->set_platform_accelerator(std::move(platform_accelerator)); -} - -} // namespace accelerator_util diff --git a/atom/browser/ui/accelerator_util_views.cc b/atom/browser/ui/accelerator_util_views.cc deleted file mode 100644 index f8d994f82ada2..0000000000000 --- a/atom/browser/ui/accelerator_util_views.cc +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/accelerator_util.h" - -#include "ui/base/accelerators/accelerator.h" - -namespace accelerator_util { - -void SetPlatformAccelerator(ui::Accelerator* accelerator) { -} - -} // namespace accelerator_util diff --git a/atom/browser/ui/atom_menu_model.cc b/atom/browser/ui/atom_menu_model.cc deleted file mode 100644 index de3465e8ab080..0000000000000 --- a/atom/browser/ui/atom_menu_model.cc +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/atom_menu_model.h" - -#include "base/stl_util.h" - -namespace atom { - -AtomMenuModel::AtomMenuModel(Delegate* delegate) - : ui::SimpleMenuModel(delegate), - delegate_(delegate) { -} - -AtomMenuModel::~AtomMenuModel() { -} - -void AtomMenuModel::SetRole(int index, const base::string16& role) { - int command_id = GetCommandIdAt(index); - roles_[command_id] = role; -} - -base::string16 AtomMenuModel::GetRoleAt(int index) { - int command_id = GetCommandIdAt(index); - if (ContainsKey(roles_, command_id)) - return roles_[command_id]; - else - return base::string16(); -} - -bool AtomMenuModel::GetAcceleratorAtWithParams( - int index, - bool use_default_accelerator, - ui::Accelerator* accelerator) const { - if (delegate_) { - return delegate_->GetAcceleratorForCommandIdWithParams( - GetCommandIdAt(index), use_default_accelerator, accelerator); - } - return false; -} - -void AtomMenuModel::MenuClosed() { - ui::SimpleMenuModel::MenuClosed(); - FOR_EACH_OBSERVER(Observer, observers_, MenuClosed()); -} - -AtomMenuModel* AtomMenuModel::GetSubmenuModelAt(int index) { - return static_cast( - ui::SimpleMenuModel::GetSubmenuModelAt(index)); -} - -} // namespace atom diff --git a/atom/browser/ui/atom_menu_model.h b/atom/browser/ui/atom_menu_model.h deleted file mode 100644 index 887f6123bccaf..0000000000000 --- a/atom/browser/ui/atom_menu_model.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_ -#define ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_ - -#include - -#include "base/observer_list.h" -#include "ui/base/models/simple_menu_model.h" - -namespace atom { - -class AtomMenuModel : public ui::SimpleMenuModel { - public: - class Delegate : public ui::SimpleMenuModel::Delegate { - public: - virtual ~Delegate() {} - - virtual bool GetAcceleratorForCommandIdWithParams( - int command_id, - bool use_default_accelerator, - ui::Accelerator* accelerator) const = 0; - - private: - // ui::SimpleMenuModel::Delegate: - bool GetAcceleratorForCommandId(int command_id, - ui::Accelerator* accelerator) { - return GetAcceleratorForCommandIdWithParams( - command_id, false, accelerator); - } - }; - - class Observer { - public: - virtual ~Observer() {} - - // Notifies the menu has been closed. - virtual void MenuClosed() {} - }; - - explicit AtomMenuModel(Delegate* delegate); - virtual ~AtomMenuModel(); - - void AddObserver(Observer* obs) { observers_.AddObserver(obs); } - void RemoveObserver(Observer* obs) { observers_.RemoveObserver(obs); } - - void SetRole(int index, const base::string16& role); - base::string16 GetRoleAt(int index); - bool GetAcceleratorAtWithParams(int index, - bool use_default_accelerator, - ui::Accelerator* accelerator) const; - - // ui::SimpleMenuModel: - void MenuClosed() override; - - using SimpleMenuModel::GetSubmenuModelAt; - AtomMenuModel* GetSubmenuModelAt(int index); - - private: - Delegate* delegate_; // weak ref. - - std::map roles_; // command id -> role - base::ObserverList observers_; - - DISALLOW_COPY_AND_ASSIGN(AtomMenuModel); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_ATOM_MENU_MODEL_H_ diff --git a/atom/browser/ui/cocoa/atom_menu_controller.h b/atom/browser/ui/cocoa/atom_menu_controller.h deleted file mode 100644 index af0b27696185c..0000000000000 --- a/atom/browser/ui/cocoa/atom_menu_controller.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_COCOA_ATOM_MENU_CONTROLLER_H_ -#define ATOM_BROWSER_UI_COCOA_ATOM_MENU_CONTROLLER_H_ - -#import - -#include "base/mac/scoped_nsobject.h" -#include "base/strings/string16.h" - -namespace atom { -class AtomMenuModel; -} - -// A controller for the cross-platform menu model. The menu that's created -// has the tag and represented object set for each menu item. The object is a -// NSValue holding a pointer to the model for that level of the menu (to -// allow for hierarchical menus). The tag is the index into that model for -// that particular item. It is important that the model outlives this object -// as it only maintains weak references. -@interface AtomMenuController : NSObject { - @protected - atom::AtomMenuModel* model_; // weak - base::scoped_nsobject menu_; - BOOL isMenuOpen_; - BOOL useDefaultAccelerator_; -} - -@property(nonatomic, assign) atom::AtomMenuModel* model; - -// Builds a NSMenu from the pre-built model (must not be nil). Changes made -// to the contents of the model after calling this will not be noticed. -- (id)initWithModel:(atom::AtomMenuModel*)model useDefaultAccelerator:(BOOL)use; - -// Populate current NSMenu with |model|. -- (void)populateWithModel:(atom::AtomMenuModel*)model; - -// Programmatically close the constructed menu. -- (void)cancel; - -// Access to the constructed menu if the complex initializer was used. If the -// default initializer was used, then this will create the menu on first call. -- (NSMenu*)menu; - -// Whether the menu is currently open. -- (BOOL)isMenuOpen; - -// NSMenuDelegate methods this class implements. Subclasses should call super -// if extending the behavior. -- (void)menuWillOpen:(NSMenu*)menu; -- (void)menuDidClose:(NSMenu*)menu; - -@end - -#endif // ATOM_BROWSER_UI_COCOA_ATOM_MENU_CONTROLLER_H_ diff --git a/atom/browser/ui/cocoa/atom_menu_controller.mm b/atom/browser/ui/cocoa/atom_menu_controller.mm deleted file mode 100644 index 3efd1611516fc..0000000000000 --- a/atom/browser/ui/cocoa/atom_menu_controller.mm +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#import "atom/browser/ui/cocoa/atom_menu_controller.h" - -#include "atom/browser/ui/atom_menu_model.h" -#include "base/logging.h" -#include "base/strings/sys_string_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/base/accelerators/platform_accelerator_cocoa.h" -#include "ui/base/l10n/l10n_util_mac.h" -#include "ui/events/cocoa/cocoa_event_utils.h" -#include "ui/gfx/image/image.h" - -namespace { - -struct Role { - SEL selector; - const char* role; -}; -Role kRolesMap[] = { - { @selector(orderFrontStandardAboutPanel:), "about" }, - { @selector(hide:), "hide" }, - { @selector(hideOtherApplications:), "hideothers" }, - { @selector(unhideAllApplications:), "unhide" }, - { @selector(arrangeInFront:), "front" }, - { @selector(undo:), "undo" }, - { @selector(redo:), "redo" }, - { @selector(cut:), "cut" }, - { @selector(copy:), "copy" }, - { @selector(paste:), "paste" }, - { @selector(delete:), "delete" }, - { @selector(pasteAndMatchStyle:), "pasteandmatchstyle" }, - { @selector(selectAll:), "selectall" }, - { @selector(performMiniaturize:), "minimize" }, - { @selector(performClose:), "close" }, - { @selector(performZoom:), "zoom" }, - { @selector(terminate:), "quit" }, - { @selector(toggleFullScreen:), "togglefullscreen" }, -}; - -} // namespace - -@implementation AtomMenuController - -@synthesize model = model_; - -- (id)initWithModel:(atom::AtomMenuModel*)model useDefaultAccelerator:(BOOL)use { - if ((self = [super init])) { - model_ = model; - isMenuOpen_ = NO; - useDefaultAccelerator_ = use; - [self menu]; - } - return self; -} - -- (void)dealloc { - [menu_ setDelegate:nil]; - - // Close the menu if it is still open. This could happen if a tab gets closed - // while its context menu is still open. - [self cancel]; - - model_ = NULL; - [super dealloc]; -} - -- (void)populateWithModel:(atom::AtomMenuModel*)model { - if (!menu_) - return; - - model_ = model; - [menu_ removeAllItems]; - - const int count = model->GetItemCount(); - for (int index = 0; index < count; index++) { - if (model->GetTypeAt(index) == atom::AtomMenuModel::TYPE_SEPARATOR) - [self addSeparatorToMenu:menu_ atIndex:index]; - else - [self addItemToMenu:menu_ atIndex:index fromModel:model]; - } -} - -- (void)cancel { - if (isMenuOpen_) { - [menu_ cancelTracking]; - model_->MenuClosed(); - isMenuOpen_ = NO; - } -} - -// Creates a NSMenu from the given model. If the model has submenus, this can -// be invoked recursively. -- (NSMenu*)menuFromModel:(atom::AtomMenuModel*)model { - NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; - - const int count = model->GetItemCount(); - for (int index = 0; index < count; index++) { - if (model->GetTypeAt(index) == atom::AtomMenuModel::TYPE_SEPARATOR) - [self addSeparatorToMenu:menu atIndex:index]; - else - [self addItemToMenu:menu atIndex:index fromModel:model]; - } - - return menu; -} - -// Adds a separator item at the given index. As the separator doesn't need -// anything from the model, this method doesn't need the model index as the -// other method below does. -- (void)addSeparatorToMenu:(NSMenu*)menu - atIndex:(int)index { - NSMenuItem* separator = [NSMenuItem separatorItem]; - [menu insertItem:separator atIndex:index]; -} - -// Adds an item or a hierarchical menu to the item at the |index|, -// associated with the entry in the model identified by |modelIndex|. -- (void)addItemToMenu:(NSMenu*)menu - atIndex:(NSInteger)index - fromModel:(atom::AtomMenuModel*)model { - base::string16 label16 = model->GetLabelAt(index); - NSString* label = l10n_util::FixUpWindowsStyleLabel(label16); - base::scoped_nsobject item( - [[NSMenuItem alloc] initWithTitle:label - action:@selector(itemSelected:) - keyEquivalent:@""]); - - // If the menu item has an icon, set it. - gfx::Image icon; - if (model->GetIconAt(index, &icon) && !icon.IsEmpty()) - [item setImage:icon.ToNSImage()]; - - atom::AtomMenuModel::ItemType type = model->GetTypeAt(index); - if (type == atom::AtomMenuModel::TYPE_SUBMENU) { - // Recursively build a submenu from the sub-model at this index. - [item setTarget:nil]; - [item setAction:nil]; - atom::AtomMenuModel* submenuModel = static_cast( - model->GetSubmenuModelAt(index)); - NSMenu* submenu = [self menuFromModel:submenuModel]; - [submenu setTitle:[item title]]; - [item setSubmenu:submenu]; - - // Set submenu's role. - base::string16 role = model->GetRoleAt(index); - if (role == base::ASCIIToUTF16("window") && [submenu numberOfItems]) - [NSApp setWindowsMenu:submenu]; - else if (role == base::ASCIIToUTF16("help")) - [NSApp setHelpMenu:submenu]; - - if (role == base::ASCIIToUTF16("services")) - [NSApp setServicesMenu:submenu]; - } else { - // The MenuModel works on indexes so we can't just set the command id as the - // tag like we do in other menus. Also set the represented object to be - // the model so hierarchical menus check the correct index in the correct - // model. Setting the target to |self| allows this class to participate - // in validation of the menu items. - [item setTag:index]; - NSValue* modelObject = [NSValue valueWithPointer:model]; - [item setRepresentedObject:modelObject]; // Retains |modelObject|. - ui::Accelerator accelerator; - if (model->GetAcceleratorAtWithParams( - index, useDefaultAccelerator_, &accelerator)) { - const ui::PlatformAcceleratorCocoa* platformAccelerator = - static_cast( - accelerator.platform_accelerator()); - if (platformAccelerator) { - [item setKeyEquivalent:platformAccelerator->characters()]; - [item setKeyEquivalentModifierMask: - platformAccelerator->modifier_mask()]; - } - } - - // Set menu item's role. - base::string16 role = model->GetRoleAt(index); - if (role.empty()) { - [item setTarget:self]; - } else { - for (const Role& pair : kRolesMap) { - if (role == base::ASCIIToUTF16(pair.role)) { - [item setAction:pair.selector]; - break; - } - } - } - } - [menu insertItem:item atIndex:index]; -} - -// Called before the menu is to be displayed to update the state (enabled, -// radio, etc) of each item in the menu. Also will update the title if -// the item is marked as "dynamic". -- (BOOL)validateUserInterfaceItem:(id)item { - SEL action = [item action]; - if (action != @selector(itemSelected:)) - return NO; - - NSInteger modelIndex = [item tag]; - atom::AtomMenuModel* model = - static_cast( - [[(id)item representedObject] pointerValue]); - DCHECK(model); - if (model) { - BOOL checked = model->IsItemCheckedAt(modelIndex); - DCHECK([(id)item isKindOfClass:[NSMenuItem class]]); - [(id)item setState:(checked ? NSOnState : NSOffState)]; - [(id)item setHidden:(!model->IsVisibleAt(modelIndex))]; - if (model->IsItemDynamicAt(modelIndex)) { - // Update the label and the icon. - NSString* label = - l10n_util::FixUpWindowsStyleLabel(model->GetLabelAt(modelIndex)); - [(id)item setTitle:label]; - - gfx::Image icon; - model->GetIconAt(modelIndex, &icon); - [(id)item setImage:icon.IsEmpty() ? nil : icon.ToNSImage()]; - } - return model->IsEnabledAt(modelIndex); - } - return NO; -} - -// Called when the user chooses a particular menu item. |sender| is the menu -// item chosen. -- (void)itemSelected:(id)sender { - NSInteger modelIndex = [sender tag]; - atom::AtomMenuModel* model = - static_cast( - [[sender representedObject] pointerValue]); - DCHECK(model); - if (model) { - NSEvent* event = [NSApp currentEvent]; - model->ActivatedAt(modelIndex, - ui::EventFlagsFromModifiers([event modifierFlags])); - } -} - -- (NSMenu*)menu { - if (menu_) - return menu_.get(); - - menu_.reset([[NSMenu alloc] initWithTitle:@""]); - [menu_ setDelegate:self]; - if (model_) - [self populateWithModel:model_]; - return menu_.get(); -} - -- (BOOL)isMenuOpen { - return isMenuOpen_; -} - -- (void)menuWillOpen:(NSMenu*)menu { - isMenuOpen_ = YES; - model_->MenuWillShow(); -} - -- (void)menuDidClose:(NSMenu*)menu { - if (isMenuOpen_) { - model_->MenuClosed(); - isMenuOpen_ = NO; - } -} - -@end diff --git a/atom/browser/ui/drag_util.h b/atom/browser/ui/drag_util.h deleted file mode 100644 index df5303c65e45d..0000000000000 --- a/atom/browser/ui/drag_util.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_DRAG_UTIL_H_ -#define ATOM_BROWSER_UI_DRAG_UTIL_H_ - -#include - -#include "ui/gfx/image/image.h" - -namespace base { -class FilePath; -} - -namespace atom { - -void DragFileItems(const std::vector& files, - const gfx::Image& icon, - gfx::NativeView view); - -} // namespace atom - -#endif // ATOM_BROWSER_UI_DRAG_UTIL_H_ diff --git a/atom/browser/ui/drag_util_mac.mm b/atom/browser/ui/drag_util_mac.mm deleted file mode 100644 index 7197e79af68c9..0000000000000 --- a/atom/browser/ui/drag_util_mac.mm +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#import - -#include "atom/browser/ui/drag_util.h" -#include "base/files/file_path.h" -#include "base/strings/sys_string_conversions.h" - -namespace atom { - -namespace { - -// Write information about the file being dragged to the pasteboard. -void AddFilesToPasteboard(NSPasteboard* pasteboard, - const std::vector& files) { - NSMutableArray* fileList = [NSMutableArray array]; - for (const base::FilePath& file : files) - [fileList addObject:base::SysUTF8ToNSString(file.value())]; - [pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] - owner:nil]; - [pasteboard setPropertyList:fileList forType:NSFilenamesPboardType]; -} - -} // namespace - -void DragFileItems(const std::vector& files, - const gfx::Image& icon, - gfx::NativeView view) { - NSPasteboard* pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - AddFilesToPasteboard(pasteboard, files); - - // Synthesize a drag event, since we don't have access to the actual event - // that initiated a drag (possibly consumed by the Web UI, for example). - NSPoint position = [[view window] mouseLocationOutsideOfEventStream]; - NSTimeInterval eventTime = [[NSApp currentEvent] timestamp]; - NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged - location:position - modifierFlags:NSLeftMouseDraggedMask - timestamp:eventTime - windowNumber:[[view window] windowNumber] - context:nil - eventNumber:0 - clickCount:1 - pressure:1.0]; - - // Run the drag operation. - [[view window] dragImage:icon.ToNSImage() - at:position - offset:NSZeroSize - event:dragEvent - pasteboard:pasteboard - source:view - slideBack:YES]; -} - -} // namespace atom diff --git a/atom/browser/ui/drag_util_views.cc b/atom/browser/ui/drag_util_views.cc deleted file mode 100644 index 9a035bf08272b..0000000000000 --- a/atom/browser/ui/drag_util_views.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/drag_util.h" - -#include "ui/aura/window.h" -#include "ui/base/dragdrop/drag_drop_types.h" -#include "ui/base/dragdrop/drag_utils.h" -#include "ui/base/dragdrop/file_info.h" -#include "ui/base/dragdrop/os_exchange_data.h" -#include "ui/gfx/geometry/point.h" -#include "ui/display/screen.h" -#include "ui/views/widget/widget.h" -#include "ui/wm/public/drag_drop_client.h" - -namespace atom { - -void DragFileItems(const std::vector& files, - const gfx::Image& icon, - gfx::NativeView view) { - // Set up our OLE machinery - ui::OSExchangeData data; - - drag_utils::CreateDragImageForFile(files[0], icon.AsImageSkia(), &data); - - std::vector file_infos; - for (const base::FilePath& file : files) { - file_infos.push_back(ui::FileInfo(file, base::FilePath())); - } - data.SetFilenames(file_infos); - - aura::Window* root_window = view->GetRootWindow(); - if (!root_window || !aura::client::GetDragDropClient(root_window)) - return; - - gfx::Point location = display::Screen::GetScreen()->GetCursorScreenPoint(); - // TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below. - aura::client::GetDragDropClient(root_window)->StartDragAndDrop( - data, - root_window, - view, - location, - ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK, - ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE); -} - -} // namespace atom diff --git a/atom/browser/ui/file_dialog.h b/atom/browser/ui/file_dialog.h deleted file mode 100644 index f65204c10e47f..0000000000000 --- a/atom/browser/ui/file_dialog.h +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_FILE_DIALOG_H_ -#define ATOM_BROWSER_UI_FILE_DIALOG_H_ - -#include -#include -#include - -#include "base/callback_forward.h" -#include "base/files/file_path.h" - -namespace atom { -class NativeWindow; -} - -namespace file_dialog { - -// -typedef std::pair > Filter; -typedef std::vector Filters; - -enum FileDialogProperty { - FILE_DIALOG_OPEN_FILE = 1 << 0, - FILE_DIALOG_OPEN_DIRECTORY = 1 << 1, - FILE_DIALOG_MULTI_SELECTIONS = 1 << 2, - FILE_DIALOG_CREATE_DIRECTORY = 1 << 3, - FILE_DIALOG_SHOW_HIDDEN_FILES = 1 << 4, -}; - -typedef base::Callback& paths)> OpenDialogCallback; - -typedef base::Callback SaveDialogCallback; - -bool ShowOpenDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - int properties, - std::vector* paths); - -void ShowOpenDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - int properties, - const OpenDialogCallback& callback); - -bool ShowSaveDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - base::FilePath* path); - -void ShowSaveDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - const SaveDialogCallback& callback); - -} // namespace file_dialog - -#endif // ATOM_BROWSER_UI_FILE_DIALOG_H_ diff --git a/atom/browser/ui/file_dialog_gtk.cc b/atom/browser/ui/file_dialog_gtk.cc deleted file mode 100644 index b6233d2054c84..0000000000000 --- a/atom/browser/ui/file_dialog_gtk.cc +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/file_dialog.h" - -#include "atom/browser/native_window_views.h" -#include "atom/browser/unresponsive_suppressor.h" -#include "base/callback.h" -#include "base/files/file_util.h" -#include "base/strings/string_util.h" -#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" -#include "chrome/browser/ui/libgtk2ui/gtk2_util.h" -#include "ui/views/widget/desktop_aura/x11_desktop_handler.h" - -namespace file_dialog { - -namespace { - -// Makes sure that .jpg also shows .JPG. -gboolean FileFilterCaseInsensitive(const GtkFileFilterInfo* file_info, - std::string* file_extension) { - // Makes .* file extension matches all file types. - if (*file_extension == ".*") - return true; - return base::EndsWith( - file_info->filename, - *file_extension, base::CompareCase::INSENSITIVE_ASCII); -} - -// Deletes |data| when gtk_file_filter_add_custom() is done with it. -void OnFileFilterDataDestroyed(std::string* file_extension) { - delete file_extension; -} - -class FileChooserDialog { - public: - FileChooserDialog(GtkFileChooserAction action, - atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters) - : parent_(static_cast(parent_window)), - filters_(filters) { - const char* confirm_text = GTK_STOCK_OK; - - if (!button_label.empty()) - confirm_text = button_label.c_str(); - else if (action == GTK_FILE_CHOOSER_ACTION_SAVE) - confirm_text = GTK_STOCK_SAVE; - else if (action == GTK_FILE_CHOOSER_ACTION_OPEN) - confirm_text = GTK_STOCK_OPEN; - - dialog_ = gtk_file_chooser_dialog_new( - title.c_str(), - NULL, - action, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - confirm_text, GTK_RESPONSE_ACCEPT, - NULL); - if (parent_) { - parent_->SetEnabled(false); - libgtk2ui::SetGtkTransientForAura(dialog_, parent_->GetNativeWindow()); - gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE); - } - - if (action == GTK_FILE_CHOOSER_ACTION_SAVE) - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog_), - TRUE); - if (action != GTK_FILE_CHOOSER_ACTION_OPEN) - gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog_), TRUE); - - if (!default_path.empty()) { - if (base::DirectoryExists(default_path)) { - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_), - default_path.value().c_str()); - } else { - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog_), - default_path.DirName().value().c_str()); - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog_), - default_path.BaseName().value().c_str()); - } - } - - if (!filters.empty()) - AddFilters(filters); - } - - ~FileChooserDialog() { - gtk_widget_destroy(dialog_); - if (parent_) - parent_->SetEnabled(true); - } - - void SetupProperties(int properties) { - if (properties & FILE_DIALOG_MULTI_SELECTIONS) - gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog()), TRUE); - if (properties & FILE_DIALOG_SHOW_HIDDEN_FILES) - g_object_set(dialog(), "show-hidden", TRUE, NULL); - } - - void RunAsynchronous() { - g_signal_connect(dialog_, "delete-event", - G_CALLBACK(gtk_widget_hide_on_delete), NULL); - g_signal_connect(dialog_, "response", - G_CALLBACK(OnFileDialogResponseThunk), this); - gtk_widget_show_all(dialog_); - - // We need to call gtk_window_present after making the widgets visible to - // make sure window gets correctly raised and gets focus. - int time = views::X11DesktopHandler::get()->wm_user_time_ms(); - gtk_window_present_with_time(GTK_WINDOW(dialog_), time); - } - - void RunSaveAsynchronous(const SaveDialogCallback& callback) { - save_callback_ = callback; - RunAsynchronous(); - } - - void RunOpenAsynchronous(const OpenDialogCallback& callback) { - open_callback_ = callback; - RunAsynchronous(); - } - - base::FilePath GetFileName() const { - gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog_)); - base::FilePath path = AddExtensionForFilename(filename); - g_free(filename); - return path; - } - - std::vector GetFileNames() const { - std::vector paths; - GSList* filenames = gtk_file_chooser_get_filenames( - GTK_FILE_CHOOSER(dialog_)); - for (GSList* iter = filenames; iter != NULL; iter = g_slist_next(iter)) { - base::FilePath path = AddExtensionForFilename( - static_cast(iter->data)); - g_free(iter->data); - paths.push_back(path); - } - g_slist_free(filenames); - return paths; - } - - CHROMEGTK_CALLBACK_1(FileChooserDialog, void, OnFileDialogResponse, int); - - GtkWidget* dialog() const { return dialog_; } - - private: - void AddFilters(const Filters& filters); - base::FilePath AddExtensionForFilename(const gchar* filename) const; - - atom::NativeWindowViews* parent_; - atom::UnresponsiveSuppressor unresponsive_suppressor_; - - GtkWidget* dialog_; - - Filters filters_; - SaveDialogCallback save_callback_; - OpenDialogCallback open_callback_; - - DISALLOW_COPY_AND_ASSIGN(FileChooserDialog); -}; - -void FileChooserDialog::OnFileDialogResponse(GtkWidget* widget, int response) { - gtk_widget_hide(dialog_); - - if (!save_callback_.is_null()) { - if (response == GTK_RESPONSE_ACCEPT) - save_callback_.Run(true, GetFileName()); - else - save_callback_.Run(false, base::FilePath()); - } else if (!open_callback_.is_null()) { - if (response == GTK_RESPONSE_ACCEPT) - open_callback_.Run(true, GetFileNames()); - else - open_callback_.Run(false, std::vector()); - } - delete this; -} - -void FileChooserDialog::AddFilters(const Filters& filters) { - for (size_t i = 0; i < filters.size(); ++i) { - const Filter& filter = filters[i]; - GtkFileFilter* gtk_filter = gtk_file_filter_new(); - - for (size_t j = 0; j < filter.second.size(); ++j) { - std::unique_ptr file_extension( - new std::string("." + filter.second[j])); - gtk_file_filter_add_custom( - gtk_filter, - GTK_FILE_FILTER_FILENAME, - reinterpret_cast(FileFilterCaseInsensitive), - file_extension.release(), - reinterpret_cast(OnFileFilterDataDestroyed)); - } - - gtk_file_filter_set_name(gtk_filter, filter.first.c_str()); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog_), gtk_filter); - } -} - -base::FilePath FileChooserDialog::AddExtensionForFilename( - const gchar* filename) const { - base::FilePath path(filename); - GtkFileFilter* selected_filter = - gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog_)); - if (!selected_filter) - return path; - - GSList* filters = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog_)); - int i = g_slist_index(filters, selected_filter); - g_slist_free(filters); - if (i >= filters_.size()) - return path; - - const auto& extensions = filters_[i].second; - for (const auto& extension : extensions) { - if (extension == "*" || - base::EndsWith(path.value(), "." + extension, - base::CompareCase::INSENSITIVE_ASCII)) - return path; - } - - return path.ReplaceExtension(extensions[0]); -} - - -} // namespace - -bool ShowOpenDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - int properties, - std::vector* paths) { - GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; - if (properties & FILE_DIALOG_OPEN_DIRECTORY) - action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; - FileChooserDialog open_dialog(action, parent_window, title, button_label, - default_path, filters); - open_dialog.SetupProperties(properties); - - gtk_widget_show_all(open_dialog.dialog()); - int response = gtk_dialog_run(GTK_DIALOG(open_dialog.dialog())); - if (response == GTK_RESPONSE_ACCEPT) { - *paths = open_dialog.GetFileNames(); - return true; - } else { - return false; - } -} - -void ShowOpenDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - int properties, - const OpenDialogCallback& callback) { - GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; - if (properties & FILE_DIALOG_OPEN_DIRECTORY) - action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; - FileChooserDialog* open_dialog = new FileChooserDialog( - action, parent_window, title, button_label, default_path, filters); - open_dialog->SetupProperties(properties); - open_dialog->RunOpenAsynchronous(callback); -} - -bool ShowSaveDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - base::FilePath* path) { - FileChooserDialog save_dialog(GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, - title, button_label, default_path, filters); - gtk_widget_show_all(save_dialog.dialog()); - int response = gtk_dialog_run(GTK_DIALOG(save_dialog.dialog())); - if (response == GTK_RESPONSE_ACCEPT) { - *path = save_dialog.GetFileName(); - return true; - } else { - return false; - } -} - -void ShowSaveDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - const SaveDialogCallback& callback) { - FileChooserDialog* save_dialog = new FileChooserDialog( - GTK_FILE_CHOOSER_ACTION_SAVE, parent_window, title, button_label, - default_path, filters); - save_dialog->RunSaveAsynchronous(callback); -} - -} // namespace file_dialog diff --git a/atom/browser/ui/file_dialog_mac.mm b/atom/browser/ui/file_dialog_mac.mm deleted file mode 100644 index 398357b0b125c..0000000000000 --- a/atom/browser/ui/file_dialog_mac.mm +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/file_dialog.h" - -#import -#import - -#include "atom/browser/native_window.h" -#include "base/files/file_util.h" -#include "base/mac/foundation_util.h" -#include "base/mac/mac_util.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/strings/sys_string_conversions.h" - -namespace file_dialog { - -namespace { - -void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) { - NSMutableSet* file_type_set = [NSMutableSet set]; - for (size_t i = 0; i < filters.size(); ++i) { - const Filter& filter = filters[i]; - for (size_t j = 0; j < filter.second.size(); ++j) { - // If we meet a '*' file extension, we allow all the file types and no - // need to set the specified file types. - if (filter.second[j] == "*") { - [dialog setAllowsOtherFileTypes:YES]; - return; - } - base::ScopedCFTypeRef ext_cf( - base::SysUTF8ToCFStringRef(filter.second[j])); - [file_type_set addObject:base::mac::CFToNSCast(ext_cf.get())]; - } - } - - // Passing empty array to setAllowedFileTypes will cause exception. - NSArray* file_types = nil; - if ([file_type_set count]) - file_types = [file_type_set allObjects]; - - [dialog setAllowedFileTypes:file_types]; -} - -void SetupDialog(NSSavePanel* dialog, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters) { - if (!title.empty()) - [dialog setTitle:base::SysUTF8ToNSString(title)]; - - if (!button_label.empty()) - [dialog setPrompt:base::SysUTF8ToNSString(button_label)]; - - NSString* default_dir = nil; - NSString* default_filename = nil; - if (!default_path.empty()) { - if (base::DirectoryExists(default_path)) { - default_dir = base::SysUTF8ToNSString(default_path.value()); - } else { - default_dir = base::SysUTF8ToNSString(default_path.DirName().value()); - default_filename = - base::SysUTF8ToNSString(default_path.BaseName().value()); - } - } - - if (default_dir) - [dialog setDirectoryURL:[NSURL fileURLWithPath:default_dir]]; - if (default_filename) - [dialog setNameFieldStringValue:default_filename]; - - [dialog setCanSelectHiddenExtension:YES]; - if (filters.empty()) - [dialog setAllowsOtherFileTypes:YES]; - else - SetAllowedFileTypes(dialog, filters); -} - -void SetupDialogForProperties(NSOpenPanel* dialog, int properties) { - [dialog setCanChooseFiles:(properties & FILE_DIALOG_OPEN_FILE)]; - if (properties & FILE_DIALOG_OPEN_DIRECTORY) - [dialog setCanChooseDirectories:YES]; - if (properties & FILE_DIALOG_CREATE_DIRECTORY) - [dialog setCanCreateDirectories:YES]; - if (properties & FILE_DIALOG_MULTI_SELECTIONS) - [dialog setAllowsMultipleSelection:YES]; - if (properties & FILE_DIALOG_SHOW_HIDDEN_FILES) - [dialog setShowsHiddenFiles:YES]; -} - -// Run modal dialog with parent window and return user's choice. -int RunModalDialog(NSSavePanel* dialog, atom::NativeWindow* parent_window) { - __block int chosen = NSFileHandlingPanelCancelButton; - if (!parent_window || !parent_window->GetNativeWindow()) { - chosen = [dialog runModal]; - } else { - NSWindow* window = parent_window->GetNativeWindow(); - - [dialog beginSheetModalForWindow:window - completionHandler:^(NSInteger c) { - chosen = c; - [NSApp stopModal]; - }]; - [NSApp runModalForWindow:window]; - } - - return chosen; -} - -void ReadDialogPaths(NSOpenPanel* dialog, std::vector* paths) { - NSArray* urls = [dialog URLs]; - for (NSURL* url in urls) - if ([url isFileURL]) - paths->push_back(base::FilePath(base::SysNSStringToUTF8([url path]))); -} - -} // namespace - -bool ShowOpenDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - int properties, - std::vector* paths) { - DCHECK(paths); - NSOpenPanel* dialog = [NSOpenPanel openPanel]; - - SetupDialog(dialog, title, button_label, default_path, filters); - SetupDialogForProperties(dialog, properties); - - int chosen = RunModalDialog(dialog, parent_window); - if (chosen == NSFileHandlingPanelCancelButton) - return false; - - ReadDialogPaths(dialog, paths); - return true; -} - -void ShowOpenDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - int properties, - const OpenDialogCallback& c) { - NSOpenPanel* dialog = [NSOpenPanel openPanel]; - - SetupDialog(dialog, title, button_label, default_path, filters); - SetupDialogForProperties(dialog, properties); - - // Duplicate the callback object here since c is a reference and gcd would - // only store the pointer, by duplication we can force gcd to store a copy. - __block OpenDialogCallback callback = c; - - NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL; - [dialog beginSheetModalForWindow:window - completionHandler:^(NSInteger chosen) { - if (chosen == NSFileHandlingPanelCancelButton) { - callback.Run(false, std::vector()); - } else { - std::vector paths; - ReadDialogPaths(dialog, &paths); - callback.Run(true, paths); - } - }]; -} - -bool ShowSaveDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - base::FilePath* path) { - DCHECK(path); - NSSavePanel* dialog = [NSSavePanel savePanel]; - - SetupDialog(dialog, title, button_label, default_path, filters); - - int chosen = RunModalDialog(dialog, parent_window); - if (chosen == NSFileHandlingPanelCancelButton || ![[dialog URL] isFileURL]) - return false; - - *path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path])); - return true; -} - -void ShowSaveDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - const SaveDialogCallback& c) { - NSSavePanel* dialog = [NSSavePanel savePanel]; - - SetupDialog(dialog, title, button_label, default_path, filters); - - __block SaveDialogCallback callback = c; - - NSWindow* window = parent_window ? parent_window->GetNativeWindow() : NULL; - [dialog beginSheetModalForWindow:window - completionHandler:^(NSInteger chosen) { - if (chosen == NSFileHandlingPanelCancelButton) { - callback.Run(false, base::FilePath()); - } else { - std::string path = base::SysNSStringToUTF8([[dialog URL] path]); - callback.Run(true, base::FilePath(path)); - } - }]; -} - -} // namespace file_dialog diff --git a/atom/browser/ui/file_dialog_win.cc b/atom/browser/ui/file_dialog_win.cc deleted file mode 100644 index ff7d8f97235b9..0000000000000 --- a/atom/browser/ui/file_dialog_win.cc +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/file_dialog.h" - -#include -#include -#include -#include - -#include "atom/browser/native_window_views.h" -#include "atom/browser/unresponsive_suppressor.h" -#include "base/files/file_util.h" -#include "base/i18n/case_conversion.h" -#include "base/strings/string_util.h" -#include "base/strings/string_split.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread.h" -#include "base/win/registry.h" -#include "third_party/wtl/include/atlapp.h" -#include "third_party/wtl/include/atldlgs.h" - -namespace file_dialog { - -namespace { - -// Distinguish directories from regular files. -bool IsDirectory(const base::FilePath& path) { - base::File::Info file_info; - return base::GetFileInfo(path, &file_info) ? - file_info.is_directory : path.EndsWithSeparator(); -} - -void ConvertFilters(const Filters& filters, - std::vector* buffer, - std::vector* filterspec) { - if (filters.empty()) { - COMDLG_FILTERSPEC spec = { L"All Files (*.*)", L"*.*" }; - filterspec->push_back(spec); - return; - } - - buffer->reserve(filters.size() * 2); - for (size_t i = 0; i < filters.size(); ++i) { - const Filter& filter = filters[i]; - - COMDLG_FILTERSPEC spec; - buffer->push_back(base::UTF8ToWide(filter.first)); - spec.pszName = buffer->back().c_str(); - - std::vector extensions(filter.second); - for (size_t j = 0; j < extensions.size(); ++j) - extensions[j].insert(0, "*."); - buffer->push_back(base::UTF8ToWide(base::JoinString(extensions, ";"))); - spec.pszSpec = buffer->back().c_str(); - - filterspec->push_back(spec); - } -} - -// Generic class to delegate common open/save dialog's behaviours, users need to -// call interface methods via GetPtr(). -template -class FileDialog { - public: - FileDialog(const base::FilePath& default_path, - const std::string& title, - const std::string& button_label, - const Filters& filters, int options) { - std::wstring file_part; - if (!IsDirectory(default_path)) - file_part = default_path.BaseName().value(); - - std::vector buffer; - std::vector filterspec; - ConvertFilters(filters, &buffer, &filterspec); - - dialog_.reset(new T(file_part.c_str(), options, NULL, - filterspec.data(), filterspec.size())); - - if (!title.empty()) - GetPtr()->SetTitle(base::UTF8ToUTF16(title).c_str()); - - if (!button_label.empty()) - GetPtr()->SetOkButtonLabel(base::UTF8ToUTF16(button_label).c_str()); - - // By default, *.* will be added to the file name if file type is "*.*". In - // Electron, we disable it to make a better experience. - // - // From MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/ - // bb775970(v=vs.85).aspx - // - // If SetDefaultExtension is not called, the dialog will not update - // automatically when user choose a new file type in the file dialog. - // - // We set file extension to the first none-wildcard extension to make - // sure the dialog will update file extension automatically. - for (size_t i = 0; i < filterspec.size(); ++i) { - if (std::wstring(filterspec[i].pszSpec) != L"*.*") { - // SetFileTypeIndex is regarded as one-based index. - GetPtr()->SetFileTypeIndex(i+1); - GetPtr()->SetDefaultExtension(filterspec[i].pszSpec); - break; - } - } - - SetDefaultFolder(default_path); - } - - bool Show(atom::NativeWindow* parent_window) { - atom::UnresponsiveSuppressor suppressor; - HWND window = parent_window ? static_cast( - parent_window)->GetAcceleratedWidget() : - NULL; - return dialog_->DoModal(window) == IDOK; - } - - T* GetDialog() { return dialog_.get(); } - - IFileDialog* GetPtr() const { return dialog_->GetPtr(); } - - private: - // Set up the initial directory for the dialog. - void SetDefaultFolder(const base::FilePath file_path) { - std::wstring directory = IsDirectory(file_path) ? - file_path.value() : - file_path.DirName().value(); - - ATL::CComPtr folder_item; - HRESULT hr = SHCreateItemFromParsingName(directory.c_str(), - NULL, - IID_PPV_ARGS(&folder_item)); - if (SUCCEEDED(hr)) - GetPtr()->SetFolder(folder_item); - } - - std::unique_ptr dialog_; - - DISALLOW_COPY_AND_ASSIGN(FileDialog); -}; - -struct RunState { - base::Thread* dialog_thread; - base::MessageLoop* ui_message_loop; -}; - -bool CreateDialogThread(RunState* run_state) { - std::unique_ptr thread( - new base::Thread(ATOM_PRODUCT_NAME "FileDialogThread")); - thread->init_com_with_mta(false); - if (!thread->Start()) - return false; - - run_state->dialog_thread = thread.release(); - run_state->ui_message_loop = base::MessageLoop::current(); - return true; -} - -void RunOpenDialogInNewThread(const RunState& run_state, - atom::NativeWindow* parent, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - int properties, - const OpenDialogCallback& callback) { - std::vector paths; - bool result = ShowOpenDialog(parent, title, button_label, default_path, - filters, properties, &paths); - run_state.ui_message_loop->PostTask(FROM_HERE, - base::Bind(callback, result, paths)); - run_state.ui_message_loop->DeleteSoon(FROM_HERE, run_state.dialog_thread); -} - -void RunSaveDialogInNewThread(const RunState& run_state, - atom::NativeWindow* parent, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - const SaveDialogCallback& callback) { - base::FilePath path; - bool result = ShowSaveDialog(parent, title, button_label, default_path, - filters, &path); - run_state.ui_message_loop->PostTask(FROM_HERE, - base::Bind(callback, result, path)); - run_state.ui_message_loop->DeleteSoon(FROM_HERE, run_state.dialog_thread); -} - -} // namespace - -bool ShowOpenDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - int properties, - std::vector* paths) { - int options = FOS_FORCEFILESYSTEM | FOS_FILEMUSTEXIST; - if (properties & FILE_DIALOG_OPEN_DIRECTORY) - options |= FOS_PICKFOLDERS; - if (properties & FILE_DIALOG_MULTI_SELECTIONS) - options |= FOS_ALLOWMULTISELECT; - if (properties & FILE_DIALOG_SHOW_HIDDEN_FILES) - options |= FOS_FORCESHOWHIDDEN; - - FileDialog open_dialog( - default_path, title, button_label, filters, options); - if (!open_dialog.Show(parent_window)) - return false; - - ATL::CComPtr items; - HRESULT hr = static_cast(open_dialog.GetPtr())->GetResults( - &items); - if (FAILED(hr)) - return false; - - ATL::CComPtr item; - DWORD count = 0; - hr = items->GetCount(&count); - if (FAILED(hr)) - return false; - - paths->reserve(count); - for (DWORD i = 0; i < count; ++i) { - hr = items->GetItemAt(i, &item); - if (FAILED(hr)) - return false; - - wchar_t file_name[MAX_PATH]; - hr = CShellFileOpenDialog::GetFileNameFromShellItem( - item, SIGDN_FILESYSPATH, file_name, MAX_PATH); - if (FAILED(hr)) - return false; - - paths->push_back(base::FilePath(file_name)); - } - - return true; -} - -void ShowOpenDialog(atom::NativeWindow* parent, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - int properties, - const OpenDialogCallback& callback) { - RunState run_state; - if (!CreateDialogThread(&run_state)) { - callback.Run(false, std::vector()); - return; - } - - run_state.dialog_thread->message_loop()->PostTask( - FROM_HERE, - base::Bind(&RunOpenDialogInNewThread, run_state, parent, title, - button_label, default_path, filters, properties, callback)); -} - -bool ShowSaveDialog(atom::NativeWindow* parent_window, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - base::FilePath* path) { - FileDialog save_dialog( - default_path, title, button_label, filters, - FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT); - if (!save_dialog.Show(parent_window)) - return false; - - wchar_t buffer[MAX_PATH]; - HRESULT hr = save_dialog.GetDialog()->GetFilePath(buffer, MAX_PATH); - if (FAILED(hr)) - return false; - - *path = base::FilePath(buffer); - return true; -} - -void ShowSaveDialog(atom::NativeWindow* parent, - const std::string& title, - const std::string& button_label, - const base::FilePath& default_path, - const Filters& filters, - const SaveDialogCallback& callback) { - RunState run_state; - if (!CreateDialogThread(&run_state)) { - callback.Run(false, base::FilePath()); - return; - } - - run_state.dialog_thread->message_loop()->PostTask( - FROM_HERE, - base::Bind(&RunSaveDialogInNewThread, run_state, parent, title, - button_label, default_path, filters, callback)); -} - -} // namespace file_dialog diff --git a/atom/browser/ui/message_box.h b/atom/browser/ui/message_box.h deleted file mode 100644 index d2eb70bcd9389..0000000000000 --- a/atom/browser/ui/message_box.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_MESSAGE_BOX_H_ -#define ATOM_BROWSER_UI_MESSAGE_BOX_H_ - -#include -#include - -#include "base/callback_forward.h" -#include "base/strings/string16.h" - -namespace gfx { -class ImageSkia; -} - -namespace atom { - -class NativeWindow; - -enum MessageBoxType { - MESSAGE_BOX_TYPE_NONE = 0, - MESSAGE_BOX_TYPE_INFORMATION, - MESSAGE_BOX_TYPE_WARNING, - MESSAGE_BOX_TYPE_ERROR, - MESSAGE_BOX_TYPE_QUESTION, -}; - -enum MessageBoxOptions { - MESSAGE_BOX_NONE = 0, - MESSAGE_BOX_NO_LINK = 1 << 0, -}; - -typedef base::Callback MessageBoxCallback; - -int ShowMessageBox(NativeWindow* parent_window, - MessageBoxType type, - const std::vector& buttons, - int cancel_id, - int default_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon); - -void ShowMessageBox(NativeWindow* parent_window, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon, - const MessageBoxCallback& callback); - -// Like ShowMessageBox with simplest settings, but safe to call at very early -// stage of application. -void ShowErrorBox(const base::string16& title, const base::string16& content); - -} // namespace atom - -#endif // ATOM_BROWSER_UI_MESSAGE_BOX_H_ diff --git a/atom/browser/ui/message_box_gtk.cc b/atom/browser/ui/message_box_gtk.cc deleted file mode 100644 index 8f11c94b7d3cb..0000000000000 --- a/atom/browser/ui/message_box_gtk.cc +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/message_box.h" - -#include "atom/browser/browser.h" -#include "atom/browser/native_window_views.h" -#include "atom/browser/unresponsive_suppressor.h" -#include "base/callback.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" -#include "chrome/browser/ui/libgtk2ui/gtk2_util.h" -#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" -#include "ui/views/widget/desktop_aura/x11_desktop_handler.h" - -#define ANSI_FOREGROUND_RED "\x1b[31m" -#define ANSI_FOREGROUND_BLACK "\x1b[30m" -#define ANSI_TEXT_BOLD "\x1b[1m" -#define ANSI_BACKGROUND_GRAY "\x1b[47m" -#define ANSI_RESET "\x1b[0m" - -namespace atom { - -namespace { - -class GtkMessageBox { - public: - GtkMessageBox(NativeWindow* parent_window, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon) - : cancel_id_(cancel_id), - parent_(static_cast(parent_window)) { - // Create dialog. - dialog_ = gtk_message_dialog_new( - nullptr, // parent - static_cast(0), // no flags - GetMessageType(type), // type - GTK_BUTTONS_NONE, // no buttons - "%s", message.c_str()); - if (!detail.empty()) - gtk_message_dialog_format_secondary_text( - GTK_MESSAGE_DIALOG(dialog_), "%s", detail.c_str()); - if (!title.empty()) - gtk_window_set_title(GTK_WINDOW(dialog_), title.c_str()); - - // Set dialog's icon. - if (!icon.isNull()) { - GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(*icon.bitmap()); - GtkIconSource* iconsource = gtk_icon_source_new(); - GtkIconSet* iconset = gtk_icon_set_new(); - gtk_icon_source_set_pixbuf(iconsource, pixbuf); - gtk_icon_set_add_source(iconset, iconsource); - GtkWidget* image = gtk_image_new_from_icon_set(iconset, - GTK_ICON_SIZE_DIALOG); - gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(dialog_), image); - gtk_widget_show(image); - gtk_icon_source_free(iconsource); - gtk_icon_set_unref(iconset); - g_object_unref(pixbuf); - } - - // Add buttons. - for (size_t i = 0; i < buttons.size(); ++i) { - GtkWidget* button = gtk_dialog_add_button( - GTK_DIALOG(dialog_), TranslateToStock(i, buttons[i]), i); - if (static_cast(i) == default_id) - gtk_widget_grab_focus(button); - } - - // Parent window. - if (parent_) { - parent_->SetEnabled(false); - libgtk2ui::SetGtkTransientForAura(dialog_, parent_->GetNativeWindow()); - gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE); - } - } - - ~GtkMessageBox() { - gtk_widget_destroy(dialog_); - if (parent_) - parent_->SetEnabled(true); - } - - GtkMessageType GetMessageType(MessageBoxType type) { - switch (type) { - case MESSAGE_BOX_TYPE_INFORMATION: - return GTK_MESSAGE_INFO; - case MESSAGE_BOX_TYPE_WARNING: - return GTK_MESSAGE_WARNING; - case MESSAGE_BOX_TYPE_QUESTION: - return GTK_MESSAGE_QUESTION; - case MESSAGE_BOX_TYPE_ERROR: - return GTK_MESSAGE_ERROR; - default: - return GTK_MESSAGE_OTHER; - } - } - - const char* TranslateToStock(int id, const std::string& text) { - std::string lower = base::ToLowerASCII(text); - if (lower == "cancel") - return GTK_STOCK_CANCEL; - else if (lower == "no") - return GTK_STOCK_NO; - else if (lower == "ok") - return GTK_STOCK_OK; - else if (lower == "yes") - return GTK_STOCK_YES; - else - return text.c_str(); - } - - void Show() { - gtk_widget_show_all(dialog_); - // We need to call gtk_window_present after making the widgets visible to - // make sure window gets correctly raised and gets focus. - int time = views::X11DesktopHandler::get()->wm_user_time_ms(); - gtk_window_present_with_time(GTK_WINDOW(dialog_), time); - } - - int RunSynchronous() { - Show(); - int response = gtk_dialog_run(GTK_DIALOG(dialog_)); - if (response < 0) - return cancel_id_; - else - return response; - } - - void RunAsynchronous(const MessageBoxCallback& callback) { - callback_ = callback; - g_signal_connect(dialog_, "delete-event", - G_CALLBACK(gtk_widget_hide_on_delete), nullptr); - g_signal_connect(dialog_, "response", - G_CALLBACK(OnResponseDialogThunk), this); - Show(); - } - - CHROMEGTK_CALLBACK_1(GtkMessageBox, void, OnResponseDialog, int); - - private: - atom::UnresponsiveSuppressor unresponsive_suppressor_; - - // The id to return when the dialog is closed without pressing buttons. - int cancel_id_; - - NativeWindowViews* parent_; - GtkWidget* dialog_; - MessageBoxCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(GtkMessageBox); -}; - -void GtkMessageBox::OnResponseDialog(GtkWidget* widget, int response) { - gtk_widget_hide(dialog_); - - if (response < 0) - callback_.Run(cancel_id_); - else - callback_.Run(response); - delete this; -} - -} // namespace - -int ShowMessageBox(NativeWindow* parent, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon) { - return GtkMessageBox(parent, type, buttons, default_id, cancel_id, - title, message, detail, icon).RunSynchronous(); -} - -void ShowMessageBox(NativeWindow* parent, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon, - const MessageBoxCallback& callback) { - (new GtkMessageBox(parent, type, buttons, default_id, cancel_id, - title, message, detail, icon))->RunAsynchronous(callback); -} - -void ShowErrorBox(const base::string16& title, const base::string16& content) { - if (Browser::Get()->is_ready()) { - GtkMessageBox(nullptr, MESSAGE_BOX_TYPE_ERROR, { "OK" }, -1, 0, "Error", - base::UTF16ToUTF8(title).c_str(), - base::UTF16ToUTF8(content).c_str(), - gfx::ImageSkia()).RunSynchronous(); - } else { - fprintf(stderr, - ANSI_TEXT_BOLD ANSI_BACKGROUND_GRAY - ANSI_FOREGROUND_RED "%s\n" - ANSI_FOREGROUND_BLACK "%s" - ANSI_RESET "\n", - base::UTF16ToUTF8(title).c_str(), - base::UTF16ToUTF8(content).c_str()); - } -} - -} // namespace atom diff --git a/atom/browser/ui/message_box_mac.mm b/atom/browser/ui/message_box_mac.mm deleted file mode 100644 index 8fd28e2446304..0000000000000 --- a/atom/browser/ui/message_box_mac.mm +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/message_box.h" - -#import - -#include "atom/browser/native_window.h" -#include "base/callback.h" -#include "base/mac/mac_util.h" -#include "base/strings/sys_string_conversions.h" -#include "skia/ext/skia_utils_mac.h" - -@interface ModalDelegate : NSObject { - @private - atom::MessageBoxCallback callback_; - NSAlert* alert_; - bool callEndModal_; -} -- (id)initWithCallback:(const atom::MessageBoxCallback&)callback - andAlert:(NSAlert*)alert - callEndModal:(bool)flag; -@end - -@implementation ModalDelegate - -- (id)initWithCallback:(const atom::MessageBoxCallback&)callback - andAlert:(NSAlert*)alert - callEndModal:(bool)flag { - if ((self = [super init])) { - callback_ = callback; - alert_ = alert; - callEndModal_ = flag; - } - return self; -} - -- (void)alertDidEnd:(NSAlert*)alert - returnCode:(NSInteger)returnCode - contextInfo:(void*)contextInfo { - callback_.Run(returnCode); - [alert_ release]; - [self release]; - - if (callEndModal_) - [NSApp stopModal]; -} - -@end - -namespace atom { - -namespace { - -NSAlert* CreateNSAlert(NativeWindow* parent_window, - MessageBoxType type, - const std::vector& buttons, - int default_id, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon) { - // Ignore the title; it's the window title on other platforms and ignorable. - NSAlert* alert = [[NSAlert alloc] init]; - [alert setMessageText:base::SysUTF8ToNSString(message)]; - [alert setInformativeText:base::SysUTF8ToNSString(detail)]; - - switch (type) { - case MESSAGE_BOX_TYPE_INFORMATION: - [alert setAlertStyle:NSInformationalAlertStyle]; - break; - case MESSAGE_BOX_TYPE_WARNING: - [alert setAlertStyle:NSWarningAlertStyle]; - break; - default: - break; - } - - for (size_t i = 0; i < buttons.size(); ++i) { - NSString* title = base::SysUTF8ToNSString(buttons[i]); - // An empty title causes crash on macOS. - if (buttons[i].empty()) - title = @"(empty)"; - NSButton* button = [alert addButtonWithTitle:title]; - [button setTag:i]; - } - - NSArray* ns_buttons = [alert buttons]; - if (default_id >= 0 && default_id < static_cast([ns_buttons count])) { - // Focus the button at default_id if the user opted to do so. - // The first button added gets set as the default selected. - // So remove that default, and make the requested button the default. - [[ns_buttons objectAtIndex:0] setKeyEquivalent:@""]; - [[ns_buttons objectAtIndex:default_id] setKeyEquivalent:@"\r"]; - } - - if (!icon.isNull()) { - NSImage* image = skia::SkBitmapToNSImageWithColorSpace( - *icon.bitmap(), base::mac::GetGenericRGBColorSpace()); - [alert setIcon:image]; - } - - return alert; -} - -void SetReturnCode(int* ret_code, int result) { - *ret_code = result; -} - -} // namespace - -int ShowMessageBox(NativeWindow* parent_window, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon) { - NSAlert* alert = CreateNSAlert( - parent_window, type, buttons, default_id, title, message, - detail, icon); - - // Use runModal for synchronous alert without parent, since we don't have a - // window to wait for. - if (!parent_window || !parent_window->GetNativeWindow()) - return [[alert autorelease] runModal]; - - int ret_code = -1; - ModalDelegate* delegate = [[ModalDelegate alloc] - initWithCallback:base::Bind(&SetReturnCode, &ret_code) - andAlert:alert - callEndModal:true]; - - NSWindow* window = parent_window->GetNativeWindow(); - [alert beginSheetModalForWindow:window - modalDelegate:delegate - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; - - [NSApp runModalForWindow:window]; - return ret_code; -} - -void ShowMessageBox(NativeWindow* parent_window, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon, - const MessageBoxCallback& callback) { - NSAlert* alert = CreateNSAlert( - parent_window, type, buttons, default_id, title, message, - detail, icon); - ModalDelegate* delegate = [[ModalDelegate alloc] initWithCallback:callback - andAlert:alert - callEndModal:false]; - - NSWindow* window = parent_window ? parent_window->GetNativeWindow() : nil; - [alert beginSheetModalForWindow:window - modalDelegate:delegate - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; -} - -void ShowErrorBox(const base::string16& title, const base::string16& content) { - NSAlert* alert = [[NSAlert alloc] init]; - [alert setMessageText:base::SysUTF16ToNSString(title)]; - [alert setInformativeText:base::SysUTF16ToNSString(content)]; - [alert setAlertStyle:NSWarningAlertStyle]; - [alert runModal]; - [alert release]; -} - -} // namespace atom diff --git a/atom/browser/ui/message_box_win.cc b/atom/browser/ui/message_box_win.cc deleted file mode 100644 index e5615fb1fc11f..0000000000000 --- a/atom/browser/ui/message_box_win.cc +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/message_box.h" - -#include -#include - -#include -#include - -#include "atom/browser/browser.h" -#include "atom/browser/native_window_views.h" -#include "atom/browser/unresponsive_suppressor.h" -#include "base/callback.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/thread.h" -#include "base/win/scoped_gdi_object.h" -#include "content/public/browser/browser_thread.h" -#include "ui/gfx/icon_util.h" - -namespace atom { - -namespace { - -// Small command ID values are already taken by Windows, we have to start from -// a large number to avoid conflicts with Windows. -const int kIDStart = 100; - -// Get the common ID from button's name. -struct CommonButtonID { - int button; - int id; -}; -CommonButtonID GetCommonID(const base::string16& button) { - base::string16 lower = base::ToLowerASCII(button); - if (lower == L"ok") - return { TDCBF_OK_BUTTON, IDOK }; - else if (lower == L"yes") - return { TDCBF_YES_BUTTON, IDYES }; - else if (lower == L"no") - return { TDCBF_NO_BUTTON, IDNO }; - else if (lower == L"cancel") - return { TDCBF_CANCEL_BUTTON, IDCANCEL }; - else if (lower == L"retry") - return { TDCBF_RETRY_BUTTON, IDRETRY }; - else if (lower == L"close") - return { TDCBF_CLOSE_BUTTON, IDCLOSE }; - return { -1, -1 }; -} - -// Determine whether the buttons are common buttons, if so map common ID -// to button ID. -void MapToCommonID(const std::vector& buttons, - std::map* id_map, - TASKDIALOG_COMMON_BUTTON_FLAGS* button_flags, - std::vector* dialog_buttons) { - for (size_t i = 0; i < buttons.size(); ++i) { - auto common = GetCommonID(buttons[i]); - if (common.button != -1) { - // It is a common button. - (*id_map)[common.id] = i; - (*button_flags) |= common.button; - } else { - // It is a custom button. - dialog_buttons->push_back( - {static_cast(i + kIDStart), buttons[i].c_str()}); - } - } -} - -int ShowMessageBoxUTF16(HWND parent, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const base::string16& title, - const base::string16& message, - const base::string16& detail, - const gfx::ImageSkia& icon) { - TASKDIALOG_FLAGS flags = - TDF_SIZE_TO_CONTENT | // Show all content. - TDF_ALLOW_DIALOG_CANCELLATION; // Allow canceling the dialog. - - TASKDIALOGCONFIG config = { 0 }; - config.cbSize = sizeof(config); - config.hwndParent = parent; - config.hInstance = GetModuleHandle(NULL); - config.dwFlags = flags; - - if (default_id > 0) - config.nDefaultButton = kIDStart + default_id; - - // TaskDialogIndirect doesn't allow empty name, if we set empty title it - // will show "electron.exe" in title. - base::string16 app_name = base::UTF8ToUTF16(Browser::Get()->GetName()); - if (title.empty()) - config.pszWindowTitle = app_name.c_str(); - else - config.pszWindowTitle = title.c_str(); - - base::win::ScopedHICON hicon; - if (!icon.isNull()) { - hicon = IconUtil::CreateHICONFromSkBitmap(*icon.bitmap()); - config.dwFlags |= TDF_USE_HICON_MAIN; - config.hMainIcon = hicon.get(); - } else { - // Show icon according to dialog's type. - switch (type) { - case MESSAGE_BOX_TYPE_INFORMATION: - case MESSAGE_BOX_TYPE_QUESTION: - config.pszMainIcon = TD_INFORMATION_ICON; - break; - case MESSAGE_BOX_TYPE_WARNING: - config.pszMainIcon = TD_WARNING_ICON; - break; - case MESSAGE_BOX_TYPE_ERROR: - config.pszMainIcon = TD_ERROR_ICON; - break; - } - } - - // If "detail" is empty then don't make message hilighted. - if (detail.empty()) { - config.pszContent = message.c_str(); - } else { - config.pszMainInstruction = message.c_str(); - config.pszContent = detail.c_str(); - } - - // Iterate through the buttons, put common buttons in dwCommonButtons - // and custom buttons in pButtons. - std::map id_map; - std::vector dialog_buttons; - if (options & MESSAGE_BOX_NO_LINK) { - for (size_t i = 0; i < buttons.size(); ++i) - dialog_buttons.push_back( - {static_cast(i + kIDStart), buttons[i].c_str()}); - } else { - MapToCommonID(buttons, &id_map, &config.dwCommonButtons, &dialog_buttons); - } - if (dialog_buttons.size() > 0) { - config.pButtons = &dialog_buttons.front(); - config.cButtons = dialog_buttons.size(); - if (!(options & MESSAGE_BOX_NO_LINK)) - config.dwFlags |= TDF_USE_COMMAND_LINKS; // custom buttons as links. - } - - int id = 0; - TaskDialogIndirect(&config, &id, NULL, NULL); - if (id_map.find(id) != id_map.end()) // common button. - return id_map[id]; - else if (id >= kIDStart) // custom button. - return id - kIDStart; - else - return cancel_id; -} - -void RunMessageBoxInNewThread(base::Thread* thread, - NativeWindow* parent, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon, - const MessageBoxCallback& callback) { - int result = ShowMessageBox(parent, type, buttons, default_id, - cancel_id, options, title, message, detail, icon); - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, base::Bind(callback, result)); - content::BrowserThread::DeleteSoon( - content::BrowserThread::UI, FROM_HERE, thread); -} - -} // namespace - -int ShowMessageBox(NativeWindow* parent, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon) { - std::vector utf16_buttons; - for (const auto& button : buttons) - utf16_buttons.push_back(base::UTF8ToUTF16(button)); - - HWND hwnd_parent = parent ? - static_cast(parent)->GetAcceleratedWidget() : - NULL; - - atom::UnresponsiveSuppressor suppressor; - return ShowMessageBoxUTF16(hwnd_parent, - type, - utf16_buttons, - default_id, - cancel_id, - options, - base::UTF8ToUTF16(title), - base::UTF8ToUTF16(message), - base::UTF8ToUTF16(detail), - icon); -} - -void ShowMessageBox(NativeWindow* parent, - MessageBoxType type, - const std::vector& buttons, - int default_id, - int cancel_id, - int options, - const std::string& title, - const std::string& message, - const std::string& detail, - const gfx::ImageSkia& icon, - const MessageBoxCallback& callback) { - std::unique_ptr thread( - new base::Thread(ATOM_PRODUCT_NAME "MessageBoxThread")); - thread->init_com_with_mta(false); - if (!thread->Start()) { - callback.Run(cancel_id); - return; - } - - base::Thread* unretained = thread.release(); - unretained->message_loop()->PostTask( - FROM_HERE, - base::Bind(&RunMessageBoxInNewThread, base::Unretained(unretained), - parent, type, buttons, default_id, cancel_id, options, title, - message, detail, icon, callback)); -} - -void ShowErrorBox(const base::string16& title, const base::string16& content) { - atom::UnresponsiveSuppressor suppressor; - ShowMessageBoxUTF16(NULL, MESSAGE_BOX_TYPE_ERROR, {}, -1, 0, 0, L"Error", - title, content, gfx::ImageSkia()); -} - -} // namespace atom diff --git a/atom/browser/ui/tray_icon.cc b/atom/browser/ui/tray_icon.cc deleted file mode 100644 index 273f5c0843916..0000000000000 --- a/atom/browser/ui/tray_icon.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/tray_icon.h" - -namespace atom { - -TrayIcon::TrayIcon() { -} - -TrayIcon::~TrayIcon() { -} - -void TrayIcon::SetPressedImage(ImageType image) { -} - -void TrayIcon::SetTitle(const std::string& title) { -} - -void TrayIcon::SetHighlightMode(TrayIcon::HighlightMode mode) { -} - -void TrayIcon::DisplayBalloon(ImageType icon, - const base::string16& title, - const base::string16& contents) { -} - -void TrayIcon::PopUpContextMenu(const gfx::Point& pos, - AtomMenuModel* menu_model) { -} - -gfx::Rect TrayIcon::GetBounds() { - return gfx::Rect(); -} - -void TrayIcon::NotifyClicked(const gfx::Rect& bounds, int modifiers) { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnClicked(bounds, modifiers)); -} - -void TrayIcon::NotifyDoubleClicked(const gfx::Rect& bounds, int modifiers) { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, - OnDoubleClicked(bounds, modifiers)); -} - -void TrayIcon::NotifyBalloonShow() { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonShow()); -} - -void TrayIcon::NotifyBalloonClicked() { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonClicked()); -} - -void TrayIcon::NotifyBalloonClosed() { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnBalloonClosed()); -} - -void TrayIcon::NotifyRightClicked(const gfx::Rect& bounds, int modifiers) { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, - OnRightClicked(bounds, modifiers)); -} - -void TrayIcon::NotifyDrop() { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDrop()); -} - -void TrayIcon::NotifyDropFiles(const std::vector& files) { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDropFiles(files)); -} - -void TrayIcon::NotifyDropText(const std::string& text) { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDropText(text)); -} - -void TrayIcon::NotifyDragEntered() { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDragEntered()); -} - -void TrayIcon::NotifyDragExited() { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDragExited()); -} - -void TrayIcon::NotifyDragEnded() { - FOR_EACH_OBSERVER(TrayIconObserver, observers_, OnDragEnded()); -} - -} // namespace atom diff --git a/atom/browser/ui/tray_icon.h b/atom/browser/ui/tray_icon.h deleted file mode 100644 index 90e81657aae20..0000000000000 --- a/atom/browser/ui/tray_icon.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_TRAY_ICON_H_ -#define ATOM_BROWSER_UI_TRAY_ICON_H_ - -#include -#include - -#include "atom/browser/ui/atom_menu_model.h" -#include "atom/browser/ui/tray_icon_observer.h" -#include "base/observer_list.h" -#include "ui/gfx/geometry/rect.h" - -namespace atom { - -class TrayIcon { - public: - static TrayIcon* Create(); - -#if defined(OS_WIN) - using ImageType = HICON; -#else - using ImageType = const gfx::Image&; -#endif - - virtual ~TrayIcon(); - - // Sets the image associated with this status icon. - virtual void SetImage(ImageType image) = 0; - - // Sets the image associated with this status icon when pressed. - virtual void SetPressedImage(ImageType image); - - // Sets the hover text for this status icon. This is also used as the label - // for the menu item which is created as a replacement for the status icon - // click action on platforms that do not support custom click actions for the - // status icon (e.g. Ubuntu Unity). - virtual void SetToolTip(const std::string& tool_tip) = 0; - - // Sets the title displayed aside of the status icon in the status bar. This - // only works on macOS. - virtual void SetTitle(const std::string& title); - - // Sets the status icon highlight mode. This only works on macOS. - enum HighlightMode { - ALWAYS, // Always highlight the tray icon - NEVER, // Never highlight the tray icon - SELECTION // Highlight the tray icon when clicked or the menu is opened - }; - virtual void SetHighlightMode(HighlightMode mode); - - // Displays a notification balloon with the specified contents. - // Depending on the platform it might not appear by the icon tray. - virtual void DisplayBalloon(ImageType icon, - const base::string16& title, - const base::string16& contents); - - // Popups the menu. - virtual void PopUpContextMenu(const gfx::Point& pos, - AtomMenuModel* menu_model); - - // Set the context menu for this icon. - virtual void SetContextMenu(AtomMenuModel* menu_model) = 0; - - // Returns the bounds of tray icon. - virtual gfx::Rect GetBounds(); - - void AddObserver(TrayIconObserver* obs) { observers_.AddObserver(obs); } - void RemoveObserver(TrayIconObserver* obs) { observers_.RemoveObserver(obs); } - - void NotifyClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0); - void NotifyDoubleClicked(const gfx::Rect& = gfx::Rect(), int modifiers = 0); - void NotifyBalloonShow(); - void NotifyBalloonClicked(); - void NotifyBalloonClosed(); - void NotifyRightClicked(const gfx::Rect& bounds = gfx::Rect(), - int modifiers = 0); - void NotifyDrop(); - void NotifyDropFiles(const std::vector& files); - void NotifyDropText(const std::string& text); - void NotifyDragEntered(); - void NotifyDragExited(); - void NotifyDragEnded(); - - protected: - TrayIcon(); - - private: - base::ObserverList observers_; - - DISALLOW_COPY_AND_ASSIGN(TrayIcon); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_TRAY_ICON_H_ diff --git a/atom/browser/ui/tray_icon_cocoa.h b/atom/browser/ui/tray_icon_cocoa.h deleted file mode 100644 index fb66a6b3f1477..0000000000000 --- a/atom/browser/ui/tray_icon_cocoa.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_TRAY_ICON_COCOA_H_ -#define ATOM_BROWSER_UI_TRAY_ICON_COCOA_H_ - -#import - -#include - -#include "atom/browser/ui/tray_icon.h" -#include "base/mac/scoped_nsobject.h" - -@class AtomMenuController; -@class StatusItemView; - -namespace atom { - -class TrayIconCocoa : public TrayIcon, - public AtomMenuModel::Observer { - public: - TrayIconCocoa(); - virtual ~TrayIconCocoa(); - - void SetImage(const gfx::Image& image) override; - void SetPressedImage(const gfx::Image& image) override; - void SetToolTip(const std::string& tool_tip) override; - void SetTitle(const std::string& title) override; - void SetHighlightMode(TrayIcon::HighlightMode mode) override; - void PopUpContextMenu(const gfx::Point& pos, - AtomMenuModel* menu_model) override; - void SetContextMenu(AtomMenuModel* menu_model) override; - gfx::Rect GetBounds() override; - - protected: - // AtomMenuModel::Observer: - void MenuClosed() override; - - private: - // Atom custom view for NSStatusItem. - base::scoped_nsobject status_item_view_; - - // Status menu shown when right-clicking the system icon. - base::scoped_nsobject menu_; - - // Used for unregistering observer. - AtomMenuModel* menu_model_; // weak ref. - - DISALLOW_COPY_AND_ASSIGN(TrayIconCocoa); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_TRAY_ICON_COCOA_H_ diff --git a/atom/browser/ui/tray_icon_cocoa.mm b/atom/browser/ui/tray_icon_cocoa.mm deleted file mode 100644 index 5ac9050b622cb..0000000000000 --- a/atom/browser/ui/tray_icon_cocoa.mm +++ /dev/null @@ -1,417 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/tray_icon_cocoa.h" - -#include "atom/browser/ui/cocoa/atom_menu_controller.h" -#include "base/strings/sys_string_conversions.h" -#include "ui/events/cocoa/cocoa_event_utils.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/mac/coordinate_conversion.h" -#include "ui/display/screen.h" - -namespace { - -// By default, macOS sets 4px to tray image as left and right padding margin. -const CGFloat kHorizontalMargin = 4; -// macOS tends to make the title 2px lower. -const CGFloat kVerticalTitleMargin = 2; - -} // namespace - -@interface StatusItemView : NSView { - atom::TrayIconCocoa* trayIcon_; // weak - AtomMenuController* menuController_; // weak - atom::TrayIcon::HighlightMode highlight_mode_; - BOOL forceHighlight_; - BOOL inMouseEventSequence_; - base::scoped_nsobject image_; - base::scoped_nsobject alternateImage_; - base::scoped_nsobject title_; - base::scoped_nsobject statusItem_; -} - -@end // @interface StatusItemView - -@implementation StatusItemView - -- (id)initWithImage:(NSImage*)image icon:(atom::TrayIconCocoa*)icon { - image_.reset([image copy]); - trayIcon_ = icon; - highlight_mode_ = atom::TrayIcon::HighlightMode::SELECTION; - forceHighlight_ = NO; - inMouseEventSequence_ = NO; - - if ((self = [super initWithFrame: CGRectZero])) { - [self registerForDraggedTypes: @[ - NSFilenamesPboardType, - NSStringPboardType, - ]]; - - // Create the status item. - NSStatusItem * item = [[NSStatusBar systemStatusBar] - statusItemWithLength:NSVariableStatusItemLength]; - statusItem_.reset([item retain]); - [statusItem_ setView:self]; - - // Finalize setup by sizing our views - [self updateDimensions]; - } - return self; -} - -- (void)updateDimensions { - NSStatusBar * bar = [NSStatusBar systemStatusBar]; - [self setFrame: NSMakeRect(0, 0, [self fullWidth], [bar thickness])]; - [self setNeedsDisplay:YES]; -} - -- (void)removeItem { - [[NSStatusBar systemStatusBar] removeStatusItem:statusItem_]; - statusItem_.reset(); -} - -- (void)drawRect:(NSRect)dirtyRect { - // Draw the tray icon and title that align with NSStatusItem, layout: - // ---------------- - // | icon | title | - /// ---------------- - - BOOL highlight = [self shouldHighlight]; - BOOL highlightContent = highlight | [self isDarkMode]; - CGFloat thickness = [[statusItem_ statusBar] thickness]; - - // Draw the system bar background. - [statusItem_ drawStatusBarBackgroundInRect:self.bounds withHighlight:highlight]; - - // Determine which image to use. - NSImage* image = image_.get(); - if (inMouseEventSequence_ && alternateImage_) { - image = alternateImage_.get(); - } - // Apply the higlight color if the image is a template image. When this moves - // to using the new [NSStatusItem button] API, this should work automagically. - if ([image isTemplate] == YES) { - NSImage* imageWithColor = [[image copy] autorelease]; - [imageWithColor lockFocus]; - [[self colorWithHighlight: highlightContent] set]; - CGRect imageBounds = CGRectMake(0,0, image.size.width, image.size.height); - NSRectFillUsingOperation(imageBounds, NSCompositeSourceAtop); - [imageWithColor unlockFocus]; - image = imageWithColor; - } - - // Draw the image - [image drawInRect: CGRectMake( - roundf(([self iconWidth] - image.size.width) / 2), - roundf((thickness - image.size.height) / 2), - image.size.width, - image.size.height - )]; - - if (title_) { - // Draw title. - NSRect titleDrawRect = NSMakeRect( - [self iconWidth], -kVerticalTitleMargin, [self titleWidth], thickness); - [title_ drawInRect:titleDrawRect - withAttributes:[self titleAttributesWithHighlight:highlightContent]]; - } -} - -- (BOOL)isDarkMode { - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - NSString* mode = [defaults stringForKey:@"AppleInterfaceStyle"]; - return mode && [mode isEqualToString:@"Dark"]; -} - -// The width of the full status item. -- (CGFloat)fullWidth { - if (title_) - return [self iconWidth] + [self titleWidth] + kHorizontalMargin; - else - return [self iconWidth]; -} - -// The width of the icon. -- (CGFloat)iconWidth { - CGFloat thickness = [[NSStatusBar systemStatusBar] thickness]; - CGFloat imageHeight = [image_ size].height; - CGFloat imageWidth = [image_ size].width; - CGFloat iconWidth = imageWidth; - if (imageWidth < thickness) { - // Image's width must be larger than menu bar's height. - iconWidth = thickness; - } else { - CGFloat verticalMargin = thickness - imageHeight; - // Image must have same horizontal vertical margin. - if (verticalMargin > 0 && imageWidth != imageHeight) - iconWidth = imageWidth + verticalMargin; - CGFloat horizontalMargin = thickness - imageWidth; - // Image must have at least kHorizontalMargin horizontal margin on each - // side. - if (horizontalMargin < 2 * kHorizontalMargin) - iconWidth = imageWidth + 2 * kHorizontalMargin; - } - return iconWidth; -} - -// The width of the title. -- (CGFloat)titleWidth { - if (!title_) - return 0; - base::scoped_nsobject attributes( - [[NSAttributedString alloc] initWithString:title_ - attributes:[self titleAttributes]]); - return [attributes size].width; -} - -- (NSColor*)colorWithHighlight:(BOOL)highlight { - return highlight ? - [NSColor whiteColor] : - [NSColor colorWithRed:0.265625 green:0.25390625 blue:0.234375 alpha:1.0]; -} - -- (NSDictionary*)titleAttributesWithHighlight:(BOOL)highlight { - return @{ - NSFontAttributeName:[NSFont menuBarFontOfSize:0], - NSForegroundColorAttributeName:[self colorWithHighlight: highlight] - }; -} - -- (NSDictionary*)titleAttributes { - return [self titleAttributesWithHighlight:[self isDarkMode]]; -} - -- (void)setImage:(NSImage*)image { - image_.reset([image copy]); - [self updateDimensions]; -} - -- (void)setAlternateImage:(NSImage*)image { - alternateImage_.reset([image copy]); -} - -- (void)setHighlight:(atom::TrayIcon::HighlightMode)mode { - highlight_mode_ = mode; - [self setNeedsDisplay:YES]; -} - -- (void)setTitle:(NSString*)title { - if (title.length > 0) { - title_.reset([title copy]); - } else { - title_.reset(); - } - [self updateDimensions]; -} - -- (void)setMenuController:(AtomMenuController*)menu { - menuController_ = menu; -} - -- (void)mouseDown:(NSEvent*)event { - inMouseEventSequence_ = YES; - [self setNeedsDisplay:YES]; -} - -- (void)mouseUp:(NSEvent*)event { - if (!inMouseEventSequence_) { - // If the menu is showing, when user clicked the tray icon, the `mouseDown` - // event will be dissmissed, we need to close the menu at this time. - [self setNeedsDisplay:YES]; - return; - } - inMouseEventSequence_ = NO; - - // Show menu when there is a context menu. - // NB(hokein): Make tray's behavior more like official one's. - // When the tray icon gets clicked quickly multiple times, the - // event.clickCount doesn't always return 1. Instead, it returns a value that - // counts the clicked times. - // So we don't check the clickCount here, just pop up the menu for each click - // event. - if (menuController_) - [statusItem_ popUpStatusItemMenu:[menuController_ menu]]; - - // Don't emit click events when menu is showing. - if (menuController_) - return; - - // Single click event. - if (event.clickCount == 1) - trayIcon_->NotifyClicked( - gfx::ScreenRectFromNSRect(event.window.frame), - ui::EventFlagsFromModifiers([event modifierFlags])); - - // Double click event. - if (event.clickCount == 2) - trayIcon_->NotifyDoubleClicked( - gfx::ScreenRectFromNSRect(event.window.frame), - ui::EventFlagsFromModifiers([event modifierFlags])); - - [self setNeedsDisplay:YES]; -} - -- (void)popUpContextMenu:(atom::AtomMenuModel*)menu_model { - // Show a custom menu. - if (menu_model) { - base::scoped_nsobject menuController( - [[AtomMenuController alloc] initWithModel:menu_model - useDefaultAccelerator:NO]); - forceHighlight_ = YES; // Should highlight when showing menu. - [self setNeedsDisplay:YES]; - [statusItem_ popUpStatusItemMenu:[menuController menu]]; - forceHighlight_ = NO; - [self setNeedsDisplay:YES]; - return; - } - - if (menuController_ && ![menuController_ isMenuOpen]) { - // Redraw the tray icon to show highlight if it is enabled. - [self setNeedsDisplay:YES]; - [statusItem_ popUpStatusItemMenu:[menuController_ menu]]; - // The popUpStatusItemMenu returns only after the showing menu is closed. - // When it returns, we need to redraw the tray icon to not show highlight. - [self setNeedsDisplay:YES]; - } -} - -- (void)rightMouseUp:(NSEvent*)event { - trayIcon_->NotifyRightClicked( - gfx::ScreenRectFromNSRect(event.window.frame), - ui::EventFlagsFromModifiers([event modifierFlags])); -} - -- (NSDragOperation)draggingEntered:(id )sender { - trayIcon_->NotifyDragEntered(); - return NSDragOperationCopy; -} - -- (void)draggingExited:(id )sender { - trayIcon_->NotifyDragExited(); -} - -- (void)draggingEnded:(id )sender { - trayIcon_->NotifyDragEnded(); - - if (NSPointInRect([sender draggingLocation], self.frame)) { - trayIcon_->NotifyDrop(); - [self handleDrop:sender]; - } -} - -- (BOOL)handleDrop:(id )sender { - NSPasteboard* pboard = [sender draggingPasteboard]; - - if ([[pboard types] containsObject:NSFilenamesPboardType]) { - std::vector dropFiles; - NSArray* files = [pboard propertyListForType:NSFilenamesPboardType]; - for (NSString* file in files) - dropFiles.push_back(base::SysNSStringToUTF8(file)); - trayIcon_->NotifyDropFiles(dropFiles); - return YES; - } else if ([[pboard types] containsObject:NSStringPboardType]) { - NSString* dropText = [pboard stringForType:NSStringPboardType]; - trayIcon_->NotifyDropText(base::SysNSStringToUTF8(dropText)); - return YES; - } - - return NO; -} - -- (BOOL)prepareForDragOperation:(id )sender { - return YES; -} - -- (BOOL)performDragOperation:(id )sender { - return YES; -} - -- (BOOL)shouldHighlight { - switch (highlight_mode_) { - case atom::TrayIcon::HighlightMode::ALWAYS: - return true; - case atom::TrayIcon::HighlightMode::NEVER: - return false; - case atom::TrayIcon::HighlightMode::SELECTION: - BOOL isMenuOpen = menuController_ && [menuController_ isMenuOpen]; - return forceHighlight_ || inMouseEventSequence_ || isMenuOpen; - } -} - -@end - -namespace atom { - -TrayIconCocoa::TrayIconCocoa() : menu_model_(nullptr) { -} - -TrayIconCocoa::~TrayIconCocoa() { - [status_item_view_ removeItem]; - if (menu_model_) - menu_model_->RemoveObserver(this); -} - -void TrayIconCocoa::SetImage(const gfx::Image& image) { - if (status_item_view_) { - [status_item_view_ setImage:image.AsNSImage()]; - } else { - status_item_view_.reset( - [[StatusItemView alloc] initWithImage:image.AsNSImage() - icon:this]); - } -} - -void TrayIconCocoa::SetPressedImage(const gfx::Image& image) { - [status_item_view_ setAlternateImage:image.AsNSImage()]; -} - -void TrayIconCocoa::SetToolTip(const std::string& tool_tip) { - [status_item_view_ setToolTip:base::SysUTF8ToNSString(tool_tip)]; -} - -void TrayIconCocoa::SetTitle(const std::string& title) { - [status_item_view_ setTitle:base::SysUTF8ToNSString(title)]; -} - -void TrayIconCocoa::SetHighlightMode(TrayIcon::HighlightMode mode) { - [status_item_view_ setHighlight:mode]; -} - -void TrayIconCocoa::PopUpContextMenu(const gfx::Point& pos, - AtomMenuModel* menu_model) { - [status_item_view_ popUpContextMenu:menu_model]; -} - -void TrayIconCocoa::SetContextMenu(AtomMenuModel* menu_model) { - // Substribe to MenuClosed event. - if (menu_model_) - menu_model_->RemoveObserver(this); - menu_model->AddObserver(this); - - // Create native menu. - menu_.reset([[AtomMenuController alloc] initWithModel:menu_model - useDefaultAccelerator:NO]); - [status_item_view_ setMenuController:menu_.get()]; -} - -gfx::Rect TrayIconCocoa::GetBounds() { - auto bounds = gfx::ScreenRectFromNSRect([status_item_view_ window].frame); - // Calling [window frame] immediately after the view gets created will have - // negative |y| sometimes. - if (bounds.y() < 0) - bounds.set_y(0); - return bounds; -} - -void TrayIconCocoa::MenuClosed() { - [status_item_view_ setNeedsDisplay:YES]; -} - -// static -TrayIcon* TrayIcon::Create() { - return new TrayIconCocoa; -} - -} // namespace atom diff --git a/atom/browser/ui/tray_icon_gtk.cc b/atom/browser/ui/tray_icon_gtk.cc deleted file mode 100644 index 3286a95a7c993..0000000000000 --- a/atom/browser/ui/tray_icon_gtk.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/tray_icon_gtk.h" - -#include "atom/browser/browser.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/ui/libgtk2ui/app_indicator_icon.h" -#include "chrome/browser/ui/libgtk2ui/gtk2_status_icon.h" -#include "ui/gfx/image/image.h" - -namespace atom { - -namespace { - -// Number of app indicators used (used as part of app-indicator id). -int indicators_count; - -} // namespace - -TrayIconGtk::TrayIconGtk() { -} - -TrayIconGtk::~TrayIconGtk() { -} - -void TrayIconGtk::SetImage(const gfx::Image& image) { - if (icon_) { - icon_->SetImage(image.AsImageSkia()); - return; - } - - base::string16 empty; - if (libgtk2ui::AppIndicatorIcon::CouldOpen()) { - ++indicators_count; - icon_.reset(new libgtk2ui::AppIndicatorIcon( - base::StringPrintf( - "%s%d", Browser::Get()->GetName().c_str(), indicators_count), - image.AsImageSkia(), - empty)); - } else { - icon_.reset(new libgtk2ui::Gtk2StatusIcon(image.AsImageSkia(), empty)); - } - icon_->set_delegate(this); -} - -void TrayIconGtk::SetToolTip(const std::string& tool_tip) { - icon_->SetToolTip(base::UTF8ToUTF16(tool_tip)); -} - -void TrayIconGtk::SetContextMenu(AtomMenuModel* menu_model) { - icon_->UpdatePlatformContextMenu(menu_model); -} - -void TrayIconGtk::OnClick() { - NotifyClicked(); -} - -bool TrayIconGtk::HasClickAction() { - return false; -} - -// static -TrayIcon* TrayIcon::Create() { - return new TrayIconGtk; -} - -} // namespace atom diff --git a/atom/browser/ui/tray_icon_gtk.h b/atom/browser/ui/tray_icon_gtk.h deleted file mode 100644 index 8cb00363f08a7..0000000000000 --- a/atom/browser/ui/tray_icon_gtk.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_TRAY_ICON_GTK_H_ -#define ATOM_BROWSER_UI_TRAY_ICON_GTK_H_ - -#include - -#include "atom/browser/ui/tray_icon.h" -#include "ui/views/linux_ui/status_icon_linux.h" - -namespace views { -class StatusIconLinux; -} - -namespace atom { - -class TrayIconGtk : public TrayIcon, - public views::StatusIconLinux::Delegate { - public: - TrayIconGtk(); - virtual ~TrayIconGtk(); - - // TrayIcon: - void SetImage(const gfx::Image& image) override; - void SetToolTip(const std::string& tool_tip) override; - void SetContextMenu(AtomMenuModel* menu_model) override; - - private: - // views::StatusIconLinux::Delegate: - void OnClick() override; - bool HasClickAction() override; - - std::unique_ptr icon_; - - DISALLOW_COPY_AND_ASSIGN(TrayIconGtk); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_TRAY_ICON_GTK_H_ diff --git a/atom/browser/ui/tray_icon_observer.h b/atom/browser/ui/tray_icon_observer.h deleted file mode 100644 index 1782e913d5417..0000000000000 --- a/atom/browser/ui/tray_icon_observer.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_ -#define ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_ - -#include -#include - -namespace gfx { -class Rect; -} - -namespace atom { - -class TrayIconObserver { - public: - virtual void OnClicked(const gfx::Rect& bounds, int modifiers) {} - virtual void OnDoubleClicked(const gfx::Rect& bounds, int modifiers) {} - virtual void OnBalloonShow() {} - virtual void OnBalloonClicked() {} - virtual void OnBalloonClosed() {} - virtual void OnRightClicked(const gfx::Rect& bounds, int modifiers) {} - virtual void OnDrop() {} - virtual void OnDropFiles(const std::vector& files) {} - virtual void OnDropText(const std::string& text) {} - virtual void OnDragEntered() {} - virtual void OnDragExited() {} - virtual void OnDragEnded() {} - - protected: - virtual ~TrayIconObserver() {} -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_TRAY_ICON_OBSERVER_H_ diff --git a/atom/browser/ui/tray_icon_win.cc b/atom/browser/ui/tray_icon_win.cc deleted file mode 100644 index 82550013ef7a2..0000000000000 --- a/atom/browser/ui/tray_icon_win.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/win/notify_icon.h" -#include "atom/browser/ui/win/notify_icon_host.h" - -namespace atom { - -// static -TrayIcon* TrayIcon::Create() { - static NotifyIconHost host; - return host.CreateNotifyIcon(); -} - -} // namespace atom diff --git a/atom/browser/ui/views/frameless_view.cc b/atom/browser/ui/views/frameless_view.cc deleted file mode 100644 index 2ec4459f6b45b..0000000000000 --- a/atom/browser/ui/views/frameless_view.cc +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/frameless_view.h" - -#include "atom/browser/native_window_views.h" -#include "ui/aura/window.h" -#include "ui/base/hit_test.h" -#include "ui/views/widget/widget.h" -#include "ui/views/widget/widget_delegate.h" - -namespace atom { - -namespace { - -const int kResizeInsideBoundsSize = 5; -const int kResizeAreaCornerSize = 16; - -const char kViewClassName[] = "FramelessView"; - -} // namespace - -FramelessView::FramelessView() : window_(NULL), frame_(NULL) { -} - -FramelessView::~FramelessView() { -} - -void FramelessView::Init(NativeWindowViews* window, views::Widget* frame) { - window_ = window; - frame_ = frame; -} - -int FramelessView::ResizingBorderHitTest(const gfx::Point& point) { - // Check the frame first, as we allow a small area overlapping the contents - // to be used for resize handles. - bool can_ever_resize = frame_->widget_delegate() ? - frame_->widget_delegate()->CanResize() : - false; - // Don't allow overlapping resize handles when the window is maximized or - // fullscreen, as it can't be resized in those states. - int resize_border = - frame_->IsMaximized() || frame_->IsFullscreen() ? 0 : - kResizeInsideBoundsSize; - return GetHTComponentForFrame(point, resize_border, resize_border, - kResizeAreaCornerSize, kResizeAreaCornerSize, can_ever_resize); -} - -gfx::Rect FramelessView::GetBoundsForClientView() const { - return bounds(); -} - -gfx::Rect FramelessView::GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const { - gfx::Rect window_bounds = client_bounds; - // Enforce minimum size (1, 1) in case that client_bounds is passed with - // empty size. This could occur when the frameless window is being - // initialized. - if (window_bounds.IsEmpty()) { - window_bounds.set_width(1); - window_bounds.set_height(1); - } - return window_bounds; -} - -int FramelessView::NonClientHitTest(const gfx::Point& cursor) { - if (frame_->IsFullscreen()) - return HTCLIENT; - - // Check for possible draggable region in the client area for the frameless - // window. - SkRegion* draggable_region = window_->draggable_region(); - if (draggable_region && draggable_region->contains(cursor.x(), cursor.y())) - return HTCAPTION; - - // Support resizing frameless window by dragging the border. - int frame_component = ResizingBorderHitTest(cursor); - if (frame_component != HTNOWHERE) - return frame_component; - - return HTCLIENT; -} - -void FramelessView::GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) { -} - -void FramelessView::ResetWindowControls() { -} - -void FramelessView::UpdateWindowIcon() { -} - -void FramelessView::UpdateWindowTitle() { -} - -void FramelessView::SizeConstraintsChanged() { -} - -gfx::Size FramelessView::GetPreferredSize() const { - return frame_->non_client_view()->GetWindowBoundsForClientBounds( - gfx::Rect(frame_->client_view()->GetPreferredSize())).size(); -} - -gfx::Size FramelessView::GetMinimumSize() const { - return window_->GetContentSizeConstraints().GetMinimumSize(); -} - -gfx::Size FramelessView::GetMaximumSize() const { - return window_->GetContentSizeConstraints().GetMaximumSize(); -} - -const char* FramelessView::GetClassName() const { - return kViewClassName; -} - -} // namespace atom diff --git a/atom/browser/ui/views/frameless_view.h b/atom/browser/ui/views/frameless_view.h deleted file mode 100644 index 54dc3285fabc0..0000000000000 --- a/atom/browser/ui/views/frameless_view.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_ -#define ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_ - -#include "ui/views/window/non_client_view.h" - -namespace views { -class Widget; -} - -namespace atom { - -class NativeWindowViews; - -class FramelessView : public views::NonClientFrameView { - public: - FramelessView(); - virtual ~FramelessView(); - - virtual void Init(NativeWindowViews* window, views::Widget* frame); - - // Returns whether the |point| is on frameless window's resizing border. - int ResizingBorderHitTest(const gfx::Point& point); - - protected: - // views::NonClientFrameView: - gfx::Rect GetBoundsForClientView() const override; - gfx::Rect GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const override; - int NonClientHitTest(const gfx::Point& point) override; - void GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) override; - void ResetWindowControls() override; - void UpdateWindowIcon() override; - void UpdateWindowTitle() override; - void SizeConstraintsChanged() override; - - // Overridden from View: - gfx::Size GetPreferredSize() const override; - gfx::Size GetMinimumSize() const override; - gfx::Size GetMaximumSize() const override; - const char* GetClassName() const override; - - // Not owned. - NativeWindowViews* window_; - views::Widget* frame_; - - private: - DISALLOW_COPY_AND_ASSIGN(FramelessView); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_FRAMELESS_VIEW_H_ diff --git a/atom/browser/ui/views/global_menu_bar_x11.cc b/atom/browser/ui/views/global_menu_bar_x11.cc deleted file mode 100644 index 266d10b96db9b..0000000000000 --- a/atom/browser/ui/views/global_menu_bar_x11.cc +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/global_menu_bar_x11.h" - -#include - -// This conflicts with mate::Converter, -#undef True -#undef False -// and V8. -#undef None - -#include -#include - -#include "atom/browser/native_window_views.h" -#include "atom/browser/ui/atom_menu_model.h" -#include "base/logging.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h" -#include "ui/aura/window.h" -#include "ui/aura/window_tree_host.h" -#include "ui/base/accelerators/menu_label_accelerator_util_linux.h" -#include "ui/events/keycodes/keyboard_code_conversion_x.h" - -// libdbusmenu-glib types -typedef struct _DbusmenuMenuitem DbusmenuMenuitem; -typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_func)(); -typedef DbusmenuMenuitem* (*dbusmenu_menuitem_new_with_id_func)(int id); - -typedef int (*dbusmenu_menuitem_get_id_func)(DbusmenuMenuitem* item); -typedef GList* (*dbusmenu_menuitem_get_children_func)(DbusmenuMenuitem* item); -typedef DbusmenuMenuitem* (*dbusmenu_menuitem_child_append_func)( - DbusmenuMenuitem* parent, - DbusmenuMenuitem* child); -typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_func)( - DbusmenuMenuitem* item, - const char* property, - const char* value); -typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_variant_func)( - DbusmenuMenuitem* item, - const char* property, - GVariant* value); -typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_bool_func)( - DbusmenuMenuitem* item, - const char* property, - bool value); -typedef DbusmenuMenuitem* (*dbusmenu_menuitem_property_set_int_func)( - DbusmenuMenuitem* item, - const char* property, - int value); - -typedef struct _DbusmenuServer DbusmenuServer; -typedef DbusmenuServer* (*dbusmenu_server_new_func)(const char* object); -typedef void (*dbusmenu_server_set_root_func)(DbusmenuServer* self, - DbusmenuMenuitem* root); - -namespace atom { - -namespace { - -// Retrieved functions from libdbusmenu-glib. - -// DbusmenuMenuItem methods: -dbusmenu_menuitem_new_func menuitem_new = NULL; -dbusmenu_menuitem_new_with_id_func menuitem_new_with_id = NULL; -dbusmenu_menuitem_get_id_func menuitem_get_id = NULL; -dbusmenu_menuitem_get_children_func menuitem_get_children = NULL; -dbusmenu_menuitem_get_children_func menuitem_take_children = NULL; -dbusmenu_menuitem_child_append_func menuitem_child_append = NULL; -dbusmenu_menuitem_property_set_func menuitem_property_set = NULL; -dbusmenu_menuitem_property_set_variant_func menuitem_property_set_variant = - NULL; -dbusmenu_menuitem_property_set_bool_func menuitem_property_set_bool = NULL; -dbusmenu_menuitem_property_set_int_func menuitem_property_set_int = NULL; - -// DbusmenuServer methods: -dbusmenu_server_new_func server_new = NULL; -dbusmenu_server_set_root_func server_set_root = NULL; - -// Properties that we set on menu items: -const char kPropertyEnabled[] = "enabled"; -const char kPropertyLabel[] = "label"; -const char kPropertyShortcut[] = "shortcut"; -const char kPropertyType[] = "type"; -const char kPropertyToggleType[] = "toggle-type"; -const char kPropertyToggleState[] = "toggle-state"; -const char kPropertyVisible[] = "visible"; -const char kPropertyChildrenDisplay[] = "children-display"; - -const char kToggleCheck[] = "checkmark"; -const char kToggleRadio[] = "radio"; -const char kTypeSeparator[] = "separator"; -const char kDisplaySubmenu[] = "submenu"; - -void EnsureMethodsLoaded() { - static bool attempted_load = false; - if (attempted_load) - return; - attempted_load = true; - - void* dbusmenu_lib = dlopen("libdbusmenu-glib.so", RTLD_LAZY); - if (!dbusmenu_lib) - dbusmenu_lib = dlopen("libdbusmenu-glib.so.4", RTLD_LAZY); - if (!dbusmenu_lib) - return; - - // DbusmenuMenuItem methods. - menuitem_new = reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_new")); - menuitem_new_with_id = reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_new_with_id")); - menuitem_get_id = reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_id")); - menuitem_get_children = reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_get_children")); - menuitem_take_children = - reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_take_children")); - menuitem_child_append = reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_child_append")); - menuitem_property_set = reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set")); - menuitem_property_set_variant = - reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_variant")); - menuitem_property_set_bool = - reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_bool")); - menuitem_property_set_int = - reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_menuitem_property_set_int")); - - // DbusmenuServer methods. - server_new = reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_server_new")); - server_set_root = reinterpret_cast( - dlsym(dbusmenu_lib, "dbusmenu_server_set_root")); -} - -AtomMenuModel* ModelForMenuItem(DbusmenuMenuitem* item) { - return reinterpret_cast( - g_object_get_data(G_OBJECT(item), "model")); -} - -bool GetMenuItemID(DbusmenuMenuitem* item, int *id) { - gpointer id_ptr = g_object_get_data(G_OBJECT(item), "menu-id"); - if (id_ptr != NULL) { - *id = GPOINTER_TO_INT(id_ptr) - 1; - return true; - } - - return false; -} - -void SetMenuItemID(DbusmenuMenuitem* item, int id) { - DCHECK_GE(id, 0); - - // Add 1 to the menu_id to avoid setting zero (null) to "menu-id". - g_object_set_data(G_OBJECT(item), "menu-id", GINT_TO_POINTER(id + 1)); -} - -} // namespace - -GlobalMenuBarX11::GlobalMenuBarX11(NativeWindowViews* window) - : window_(window), - xid_(window_->GetNativeWindow()->GetHost()->GetAcceleratedWidget()), - server_(NULL) { - EnsureMethodsLoaded(); - if (server_new) - InitServer(xid_); - - GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid_); -} - -GlobalMenuBarX11::~GlobalMenuBarX11() { - if (IsServerStarted()) - g_object_unref(server_); - - GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid_); -} - -// static -std::string GlobalMenuBarX11::GetPathForWindow(gfx::AcceleratedWidget xid) { - return base::StringPrintf("/com/canonical/menu/%lX", xid); -} - -void GlobalMenuBarX11::SetMenu(AtomMenuModel* menu_model) { - if (!IsServerStarted()) - return; - - DbusmenuMenuitem* root_item = menuitem_new(); - menuitem_property_set(root_item, kPropertyLabel, "Root"); - menuitem_property_set_bool(root_item, kPropertyVisible, true); - BuildMenuFromModel(menu_model, root_item); - - server_set_root(server_, root_item); - g_object_unref(root_item); -} - -bool GlobalMenuBarX11::IsServerStarted() const { - return server_; -} - -void GlobalMenuBarX11::InitServer(gfx::AcceleratedWidget xid) { - std::string path = GetPathForWindow(xid); - server_ = server_new(path.c_str()); -} - -void GlobalMenuBarX11::OnWindowMapped() { - GlobalMenuBarRegistrarX11::GetInstance()->OnWindowMapped(xid_); -} - -void GlobalMenuBarX11::OnWindowUnmapped() { - GlobalMenuBarRegistrarX11::GetInstance()->OnWindowUnmapped(xid_); -} - -void GlobalMenuBarX11::BuildMenuFromModel(AtomMenuModel* model, - DbusmenuMenuitem* parent) { - for (int i = 0; i < model->GetItemCount(); ++i) { - DbusmenuMenuitem* item = menuitem_new(); - menuitem_property_set_bool(item, kPropertyVisible, model->IsVisibleAt(i)); - - AtomMenuModel::ItemType type = model->GetTypeAt(i); - if (type == AtomMenuModel::TYPE_SEPARATOR) { - menuitem_property_set(item, kPropertyType, kTypeSeparator); - } else { - std::string label = ui::ConvertAcceleratorsFromWindowsStyle( - base::UTF16ToUTF8(model->GetLabelAt(i))); - menuitem_property_set(item, kPropertyLabel, label.c_str()); - menuitem_property_set_bool(item, kPropertyEnabled, model->IsEnabledAt(i)); - - g_object_set_data(G_OBJECT(item), "model", model); - SetMenuItemID(item, i); - - if (type == AtomMenuModel::TYPE_SUBMENU) { - menuitem_property_set(item, kPropertyChildrenDisplay, kDisplaySubmenu); - g_signal_connect(item, "about-to-show", - G_CALLBACK(OnSubMenuShowThunk), this); - } else { - ui::Accelerator accelerator; - if (model->GetAcceleratorAtWithParams(i, true, &accelerator)) - RegisterAccelerator(item, accelerator); - - g_signal_connect(item, "item-activated", - G_CALLBACK(OnItemActivatedThunk), this); - - if (type == AtomMenuModel::TYPE_CHECK || - type == AtomMenuModel::TYPE_RADIO) { - menuitem_property_set(item, kPropertyToggleType, - type == AtomMenuModel::TYPE_CHECK ? kToggleCheck : kToggleRadio); - menuitem_property_set_int(item, kPropertyToggleState, - model->IsItemCheckedAt(i)); - } - } - } - - menuitem_child_append(parent, item); - g_object_unref(item); - } -} - -void GlobalMenuBarX11::RegisterAccelerator(DbusmenuMenuitem* item, - const ui::Accelerator& accelerator) { - // A translation of libdbusmenu-gtk's menuitem_property_set_shortcut() - // translated from GDK types to ui::Accelerator types. - GVariantBuilder builder; - g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); - - if (accelerator.IsCtrlDown()) - g_variant_builder_add(&builder, "s", "Control"); - if (accelerator.IsAltDown()) - g_variant_builder_add(&builder, "s", "Alt"); - if (accelerator.IsShiftDown()) - g_variant_builder_add(&builder, "s", "Shift"); - - char* name = XKeysymToString(XKeysymForWindowsKeyCode( - accelerator.key_code(), false)); - if (!name) { - NOTIMPLEMENTED(); - return; - } - g_variant_builder_add(&builder, "s", name); - - GVariant* inside_array = g_variant_builder_end(&builder); - g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); - g_variant_builder_add_value(&builder, inside_array); - GVariant* outside_array = g_variant_builder_end(&builder); - - menuitem_property_set_variant(item, kPropertyShortcut, outside_array); -} - -void GlobalMenuBarX11::OnItemActivated(DbusmenuMenuitem* item, - unsigned int timestamp) { - int id; - AtomMenuModel* model = ModelForMenuItem(item); - if (model && GetMenuItemID(item, &id)) - model->ActivatedAt(id, 0); -} - -void GlobalMenuBarX11::OnSubMenuShow(DbusmenuMenuitem* item) { - int id; - AtomMenuModel* model = ModelForMenuItem(item); - if (!model || !GetMenuItemID(item, &id)) - return; - - // Clear children. - GList *children = menuitem_take_children(item); - g_list_foreach(children, reinterpret_cast(g_object_unref), NULL); - g_list_free(children); - - // Build children. - BuildMenuFromModel(model->GetSubmenuModelAt(id), item); -} - -} // namespace atom diff --git a/atom/browser/ui/views/global_menu_bar_x11.h b/atom/browser/ui/views/global_menu_bar_x11.h deleted file mode 100644 index 9bb4dd338559e..0000000000000 --- a/atom/browser/ui/views/global_menu_bar_x11.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_GLOBAL_MENU_BAR_X11_H_ -#define ATOM_BROWSER_UI_VIEWS_GLOBAL_MENU_BAR_X11_H_ - -#include - -#include "atom/browser/ui/atom_menu_model.h" -#include "base/macros.h" -#include "base/compiler_specific.h" -#include "ui/base/glib/glib_signal.h" -#include "ui/gfx/native_widget_types.h" - -typedef struct _DbusmenuMenuitem DbusmenuMenuitem; -typedef struct _DbusmenuServer DbusmenuServer; - -namespace ui { -class Accelerator; -} - -namespace atom { - -class NativeWindowViews; - -// Controls the Mac style menu bar on Unity. -// -// Unity has an Apple-like menu bar at the top of the screen that changes -// depending on the active window. In the GTK port, we had a hidden GtkMenuBar -// object in each GtkWindow which existed only to be scrapped by the -// libdbusmenu-gtk code. Since we don't have GtkWindows anymore, we need to -// interface directly with the lower level libdbusmenu-glib, which we -// opportunistically dlopen() since not everyone is running Ubuntu. -// -// This class is like the chrome's corresponding one, but it generates the menu -// from menu models instead, and it is also per-window specific. -class GlobalMenuBarX11 { - public: - explicit GlobalMenuBarX11(NativeWindowViews* window); - virtual ~GlobalMenuBarX11(); - - // Creates the object path for DbusmenuServer which is attached to |xid|. - static std::string GetPathForWindow(gfx::AcceleratedWidget xid); - - void SetMenu(AtomMenuModel* menu_model); - bool IsServerStarted() const; - - // Called by NativeWindow when it show/hides. - void OnWindowMapped(); - void OnWindowUnmapped(); - - private: - // Creates a DbusmenuServer. - void InitServer(gfx::AcceleratedWidget xid); - - // Create a menu from menu model. - void BuildMenuFromModel(AtomMenuModel* model, DbusmenuMenuitem* parent); - - // Sets the accelerator for |item|. - void RegisterAccelerator(DbusmenuMenuitem* item, - const ui::Accelerator& accelerator); - - CHROMEG_CALLBACK_1(GlobalMenuBarX11, void, OnItemActivated, DbusmenuMenuitem*, - unsigned int); - CHROMEG_CALLBACK_0(GlobalMenuBarX11, void, OnSubMenuShow, DbusmenuMenuitem*); - - NativeWindowViews* window_; - gfx::AcceleratedWidget xid_; - - DbusmenuServer* server_; - - DISALLOW_COPY_AND_ASSIGN(GlobalMenuBarX11); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_GLOBAL_MENU_BAR_X11_H_ diff --git a/atom/browser/ui/views/menu_bar.cc b/atom/browser/ui/views/menu_bar.cc deleted file mode 100644 index cb7af509cc8a0..0000000000000 --- a/atom/browser/ui/views/menu_bar.cc +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/menu_bar.h" - -#if defined(USE_X11) -#include "gtk/gtk.h" -#endif - -#include "atom/browser/ui/views/menu_delegate.h" -#include "atom/browser/ui/views/submenu_button.h" -#include "ui/base/models/menu_model.h" -#include "ui/views/background.h" -#include "ui/views/layout/box_layout.h" - -#if defined(OS_WIN) -#include "ui/gfx/color_utils.h" -#elif defined(USE_X11) -#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" -#endif - -namespace atom { - -namespace { - -const char kViewClassName[] = "ElectronMenuBar"; - -// Default color of the menu bar. -const SkColor kDefaultColor = SkColorSetARGB(255, 233, 233, 233); - -#if defined(USE_X11) -void GetMenuBarColor(SkColor* enabled, SkColor* disabled, SkColor* highlight, - SkColor* hover, SkColor* background) { - GtkWidget* menu_bar = gtk_menu_bar_new(); - - GtkStyle* style = gtk_rc_get_style(menu_bar); - *enabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_NORMAL]); - *disabled = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_INSENSITIVE]); - *highlight = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_SELECTED]); - *hover = libgtk2ui::GdkColorToSkColor(style->fg[GTK_STATE_PRELIGHT]); - *background = libgtk2ui::GdkColorToSkColor(style->bg[GTK_STATE_NORMAL]); - - gtk_widget_destroy(menu_bar); -} -#endif - -} // namespace - -MenuBar::MenuBar() - : background_color_(kDefaultColor), - menu_model_(NULL) { - UpdateMenuBarColor(); - SetLayoutManager(new views::BoxLayout( - views::BoxLayout::kHorizontal, 0, 0, 0)); -} - -MenuBar::~MenuBar() { -} - -void MenuBar::SetMenu(AtomMenuModel* model) { - menu_model_ = model; - RemoveAllChildViews(true); - - for (int i = 0; i < model->GetItemCount(); ++i) { - SubmenuButton* button = new SubmenuButton(this, model->GetLabelAt(i), this); - button->set_tag(i); - -#if defined(USE_X11) - button->SetTextColor(views::Button::STATE_NORMAL, enabled_color_); - button->SetTextColor(views::Button::STATE_DISABLED, disabled_color_); - button->SetTextColor(views::Button::STATE_PRESSED, highlight_color_); - button->SetTextColor(views::Button::STATE_HOVERED, hover_color_); - button->SetUnderlineColor(enabled_color_); -#elif defined(OS_WIN) - button->SetUnderlineColor(color_utils::GetSysSkColor(COLOR_GRAYTEXT)); -#endif - - AddChildView(button); - } -} - -void MenuBar::SetAcceleratorVisibility(bool visible) { - for (int i = 0; i < child_count(); ++i) - static_cast(child_at(i))->SetAcceleratorVisibility(visible); -} - -int MenuBar::GetAcceleratorIndex(base::char16 key) { - for (int i = 0; i < child_count(); ++i) { - SubmenuButton* button = static_cast(child_at(i)); - if (button->accelerator() == key) - return i; - } - return -1; -} - -void MenuBar::ActivateAccelerator(base::char16 key) { - int i = GetAcceleratorIndex(key); - if (i != -1) - static_cast(child_at(i))->Activate(nullptr); -} - -int MenuBar::GetItemCount() const { - return menu_model_->GetItemCount(); -} - -bool MenuBar::GetMenuButtonFromScreenPoint(const gfx::Point& point, - AtomMenuModel** menu_model, - views::MenuButton** button) { - gfx::Point location(point); - views::View::ConvertPointFromScreen(this, &location); - - if (location.x() < 0 || location.x() >= width() || location.y() < 0 || - location.y() >= height()) - return false; - - for (int i = 0; i < child_count(); ++i) { - views::View* view = child_at(i); - if (view->bounds().Contains(location) && - (menu_model_->GetTypeAt(i) == AtomMenuModel::TYPE_SUBMENU)) { - *menu_model = menu_model_->GetSubmenuModelAt(i); - *button = static_cast(view); - return true; - } - } - - return false; -} - -const char* MenuBar::GetClassName() const { - return kViewClassName; -} - -void MenuBar::ButtonPressed(views::Button* sender, const ui::Event& event) { -} - -void MenuBar::OnMenuButtonClicked(views::MenuButton* source, - const gfx::Point& point, - const ui::Event* event) { - // Hide the accelerator when a submenu is activated. - SetAcceleratorVisibility(false); - - if (!menu_model_) - return; - - int id = source->tag(); - AtomMenuModel::ItemType type = menu_model_->GetTypeAt(id); - if (type != AtomMenuModel::TYPE_SUBMENU) { - menu_model_->ActivatedAt(id, 0); - return; - } - - MenuDelegate menu_delegate(this); - menu_delegate.RunMenu(menu_model_->GetSubmenuModelAt(id), source); -} - -void MenuBar::OnNativeThemeChanged(const ui::NativeTheme* theme) { - UpdateMenuBarColor(); -} - -void MenuBar::UpdateMenuBarColor() { -#if defined(OS_WIN) - background_color_ = color_utils::GetSysSkColor(COLOR_MENUBAR); -#elif defined(USE_X11) - GetMenuBarColor(&enabled_color_, &disabled_color_, &highlight_color_, - &hover_color_, &background_color_); -#endif - set_background(views::Background::CreateSolidBackground(background_color_)); -} - -} // namespace atom diff --git a/atom/browser/ui/views/menu_bar.h b/atom/browser/ui/views/menu_bar.h deleted file mode 100644 index 5b86e292c887c..0000000000000 --- a/atom/browser/ui/views/menu_bar.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_MENU_BAR_H_ -#define ATOM_BROWSER_UI_VIEWS_MENU_BAR_H_ - -#include "atom/browser/ui/atom_menu_model.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/menu_button_listener.h" -#include "ui/views/view.h" - -namespace views { -class MenuButton; -} - -namespace atom { - -class MenuDelegate; - -class MenuBar : public views::View, - public views::ButtonListener, - public views::MenuButtonListener { - public: - MenuBar(); - virtual ~MenuBar(); - - // Replaces current menu with a new one. - void SetMenu(AtomMenuModel* menu_model); - - // Shows underline under accelerators. - void SetAcceleratorVisibility(bool visible); - - // Returns which submenu has accelerator |key|, -1 would be returned when - // there is no matching submenu. - int GetAcceleratorIndex(base::char16 key); - - // Shows the submenu whose accelerator is |key|. - void ActivateAccelerator(base::char16 key); - - // Returns there are how many items in the root menu. - int GetItemCount() const; - - // Get the menu under specified screen point. - bool GetMenuButtonFromScreenPoint(const gfx::Point& point, - AtomMenuModel** menu_model, - views::MenuButton** button); - - protected: - // views::View: - const char* GetClassName() const override; - - // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override; - - // views::MenuButtonListener: - void OnMenuButtonClicked(views::MenuButton* source, - const gfx::Point& point, - const ui::Event* event) override; - void OnNativeThemeChanged(const ui::NativeTheme* theme) override; - - private: - void UpdateMenuBarColor(); - - SkColor background_color_; - -#if defined(USE_X11) - SkColor enabled_color_; - SkColor disabled_color_; - SkColor highlight_color_; - SkColor hover_color_; -#endif - - AtomMenuModel* menu_model_; - - DISALLOW_COPY_AND_ASSIGN(MenuBar); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_MENU_BAR_H_ diff --git a/atom/browser/ui/views/menu_delegate.cc b/atom/browser/ui/views/menu_delegate.cc deleted file mode 100644 index 3a1a151b7269d..0000000000000 --- a/atom/browser/ui/views/menu_delegate.cc +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/menu_delegate.h" - -#include "atom/browser/ui/views/menu_bar.h" -#include "atom/browser/ui/views/menu_model_adapter.h" -#include "content/public/browser/browser_thread.h" -#include "ui/views/controls/button/menu_button.h" -#include "ui/views/controls/menu/menu_item_view.h" -#include "ui/views/controls/menu/menu_runner.h" -#include "ui/views/widget/widget.h" - -namespace atom { - -MenuDelegate::MenuDelegate(MenuBar* menu_bar) - : menu_bar_(menu_bar), - id_(-1) { -} - -MenuDelegate::~MenuDelegate() { -} - -void MenuDelegate::RunMenu(AtomMenuModel* model, views::MenuButton* button) { - gfx::Point screen_loc; - views::View::ConvertPointToScreen(button, &screen_loc); - // Subtract 1 from the height to make the popup flush with the button border. - gfx::Rect bounds(screen_loc.x(), screen_loc.y(), button->width(), - button->height() - 1); - - id_ = button->tag(); - adapter_.reset(new MenuModelAdapter(model)); - - views::MenuItemView* item = new views::MenuItemView(this); - static_cast(adapter_.get())->BuildMenu(item); - - menu_runner_.reset(new views::MenuRunner( - item, - views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS)); - ignore_result(menu_runner_->RunMenuAt( - button->GetWidget()->GetTopLevelWidget(), - button, - bounds, - views::MENU_ANCHOR_TOPRIGHT, - ui::MENU_SOURCE_MOUSE)); -} - -void MenuDelegate::ExecuteCommand(int id) { - adapter_->ExecuteCommand(id); -} - -void MenuDelegate::ExecuteCommand(int id, int mouse_event_flags) { - adapter_->ExecuteCommand(id, mouse_event_flags); -} - -bool MenuDelegate::IsTriggerableEvent(views::MenuItemView* source, - const ui::Event& e) { - return adapter_->IsTriggerableEvent(source, e); -} - -bool MenuDelegate::GetAccelerator(int id, ui::Accelerator* accelerator) const { - return adapter_->GetAccelerator(id, accelerator); -} - -base::string16 MenuDelegate::GetLabel(int id) const { - return adapter_->GetLabel(id); -} - -const gfx::FontList* MenuDelegate::GetLabelFontList(int id) const { - return adapter_->GetLabelFontList(id); -} - -bool MenuDelegate::IsCommandEnabled(int id) const { - return adapter_->IsCommandEnabled(id); -} - -bool MenuDelegate::IsCommandVisible(int id) const { - return adapter_->IsCommandVisible(id); -} - -bool MenuDelegate::IsItemChecked(int id) const { - return adapter_->IsItemChecked(id); -} - -void MenuDelegate::SelectionChanged(views::MenuItemView* menu) { - adapter_->SelectionChanged(menu); -} - -void MenuDelegate::WillShowMenu(views::MenuItemView* menu) { - adapter_->WillShowMenu(menu); -} - -void MenuDelegate::WillHideMenu(views::MenuItemView* menu) { - adapter_->WillHideMenu(menu); -} - -views::MenuItemView* MenuDelegate::GetSiblingMenu( - views::MenuItemView* menu, - const gfx::Point& screen_point, - views::MenuAnchorPosition* anchor, - bool* has_mnemonics, - views::MenuButton**) { - views::MenuButton* button; - AtomMenuModel* model; - if (menu_bar_->GetMenuButtonFromScreenPoint(screen_point, &model, &button) && - button->tag() != id_) { - DCHECK(menu_runner_->IsRunning()); - menu_runner_->Cancel(); - // After canceling the menu, we need to wait until next tick - // so we are out of nested message loop. - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(base::IgnoreResult(&views::MenuButton::Activate), - base::Unretained(button), nullptr)); - } - - return nullptr; -} - -} // namespace atom diff --git a/atom/browser/ui/views/menu_delegate.h b/atom/browser/ui/views/menu_delegate.h deleted file mode 100644 index f813f9cc7d0b6..0000000000000 --- a/atom/browser/ui/views/menu_delegate.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_MENU_DELEGATE_H_ -#define ATOM_BROWSER_UI_VIEWS_MENU_DELEGATE_H_ - -#include - -#include "atom/browser/ui/atom_menu_model.h" -#include "ui/views/controls/menu/menu_delegate.h" - -namespace views { -class MenuRunner; -} - -namespace atom { - -class MenuBar; - -class MenuDelegate : public views::MenuDelegate { - public: - explicit MenuDelegate(MenuBar* menu_bar); - virtual ~MenuDelegate(); - - void RunMenu(AtomMenuModel* model, views::MenuButton* button); - - protected: - // views::MenuDelegate: - void ExecuteCommand(int id) override; - void ExecuteCommand(int id, int mouse_event_flags) override; - bool IsTriggerableEvent(views::MenuItemView* source, - const ui::Event& e) override; - bool GetAccelerator(int id, ui::Accelerator* accelerator) const override; - base::string16 GetLabel(int id) const override; - const gfx::FontList* GetLabelFontList(int id) const override; - bool IsCommandEnabled(int id) const override; - bool IsCommandVisible(int id) const override; - bool IsItemChecked(int id) const override; - void SelectionChanged(views::MenuItemView* menu) override; - void WillShowMenu(views::MenuItemView* menu) override; - void WillHideMenu(views::MenuItemView* menu) override; - views::MenuItemView* GetSiblingMenu( - views::MenuItemView* menu, - const gfx::Point& screen_point, - views::MenuAnchorPosition* anchor, - bool* has_mnemonics, - views::MenuButton** button) override; - - private: - MenuBar* menu_bar_; - int id_; - std::unique_ptr adapter_; - std::unique_ptr menu_runner_; - - DISALLOW_COPY_AND_ASSIGN(MenuDelegate); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_MENU_DELEGATE_H_ diff --git a/atom/browser/ui/views/menu_layout.cc b/atom/browser/ui/views/menu_layout.cc deleted file mode 100644 index 8f8e636472ca6..0000000000000 --- a/atom/browser/ui/views/menu_layout.cc +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/menu_layout.h" - -#if defined(OS_WIN) -#include "atom/browser/native_window_views.h" -#endif - -namespace atom { - -namespace { - -#if defined(OS_WIN) -gfx::Rect SubstractBorderSize(gfx::Rect bounds) { - int border_width = GetSystemMetrics(SM_CXSIZEFRAME) - 1; - int border_height = GetSystemMetrics(SM_CYSIZEFRAME) - 1; - bounds.set_x(bounds.x() + border_width); - bounds.set_y(bounds.y() + border_height); - bounds.set_width(bounds.width() - 2 * border_width); - bounds.set_height(bounds.height() - 2 * border_height); - return bounds; -} -#endif - -} // namespace - -MenuLayout::MenuLayout(NativeWindowViews* window, int menu_height) - : window_(window), - menu_height_(menu_height) { -} - -MenuLayout::~MenuLayout() { -} - -void MenuLayout::Layout(views::View* host) { -#if defined(OS_WIN) - // Reserve border space for maximized frameless window so we won't have the - // content go outside of screen. - if (!window_->has_frame() && window_->IsMaximized()) { - gfx::Rect bounds = SubstractBorderSize(host->GetContentsBounds()); - host->child_at(0)->SetBoundsRect(bounds); - return; - } -#endif - - if (!HasMenu(host)) { - views::FillLayout::Layout(host); - return; - } - - gfx::Size size = host->GetContentsBounds().size(); - gfx::Rect menu_Bar_bounds = gfx::Rect(0, 0, size.width(), menu_height_); - gfx::Rect web_view_bounds = gfx::Rect( - 0, menu_height_, size.width(), size.height() - menu_height_); - - views::View* web_view = host->child_at(0); - views::View* menu_bar = host->child_at(1); - web_view->SetBoundsRect(web_view_bounds); - menu_bar->SetBoundsRect(menu_Bar_bounds); -} - -gfx::Size MenuLayout::GetPreferredSize(const views::View* host) const { - gfx::Size size = views::FillLayout::GetPreferredSize(host); - if (!HasMenu(host)) - return size; - - size.set_height(size.height() + menu_height_); - return size; -} - -int MenuLayout::GetPreferredHeightForWidth( - const views::View* host, int width) const { - int height = views::FillLayout::GetPreferredHeightForWidth(host, width); - if (!HasMenu(host)) - return height; - - return height + menu_height_; -} - -bool MenuLayout::HasMenu(const views::View* host) const { - return host->child_count() == 2; -} - -} // namespace atom diff --git a/atom/browser/ui/views/menu_layout.h b/atom/browser/ui/views/menu_layout.h deleted file mode 100644 index 0a8464a1d44a3..0000000000000 --- a/atom/browser/ui/views/menu_layout.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_ -#define ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_ - -#include "ui/views/layout/fill_layout.h" - -namespace atom { - -class NativeWindowViews; - -class MenuLayout : public views::FillLayout { - public: - MenuLayout(NativeWindowViews* window, int menu_height); - virtual ~MenuLayout(); - - // views::LayoutManager: - void Layout(views::View* host) override; - gfx::Size GetPreferredSize(const views::View* host) const override; - int GetPreferredHeightForWidth( - const views::View* host, int width) const override; - - private: - bool HasMenu(const views::View* host) const; - - NativeWindowViews* window_; - int menu_height_; - - DISALLOW_COPY_AND_ASSIGN(MenuLayout); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_MENU_LAYOUT_H_ diff --git a/atom/browser/ui/views/menu_model_adapter.cc b/atom/browser/ui/views/menu_model_adapter.cc deleted file mode 100644 index 303cdb9babd26..0000000000000 --- a/atom/browser/ui/views/menu_model_adapter.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/menu_model_adapter.h" - -namespace atom { - -MenuModelAdapter::MenuModelAdapter(AtomMenuModel* menu_model) - : views::MenuModelAdapter(menu_model), - menu_model_(menu_model) { -} - -MenuModelAdapter::~MenuModelAdapter() { -} - -bool MenuModelAdapter::GetAccelerator(int id, - ui::Accelerator* accelerator) const { - ui::MenuModel* model = menu_model_; - int index = 0; - if (ui::MenuModel::GetModelAndIndexForCommandId(id, &model, &index)) { - return static_cast(model)-> - GetAcceleratorAtWithParams(index, true, accelerator); - } - return false; -} - -} // namespace atom diff --git a/atom/browser/ui/views/menu_model_adapter.h b/atom/browser/ui/views/menu_model_adapter.h deleted file mode 100644 index 4b87bc32fd561..0000000000000 --- a/atom/browser/ui/views/menu_model_adapter.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_MENU_MODEL_ADAPTER_H_ -#define ATOM_BROWSER_UI_VIEWS_MENU_MODEL_ADAPTER_H_ - -#include "atom/browser/ui/atom_menu_model.h" -#include "ui/views/controls/menu/menu_model_adapter.h" - -namespace atom { - -class MenuModelAdapter : public views::MenuModelAdapter { - public: - explicit MenuModelAdapter(AtomMenuModel* menu_model); - virtual ~MenuModelAdapter(); - - protected: - bool GetAccelerator(int id, ui::Accelerator* accelerator) const override; - - private: - AtomMenuModel* menu_model_; - - DISALLOW_COPY_AND_ASSIGN(MenuModelAdapter); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_MENU_MODEL_ADAPTER_H_ diff --git a/atom/browser/ui/views/native_frame_view.cc b/atom/browser/ui/views/native_frame_view.cc deleted file mode 100644 index 134255f48458c..0000000000000 --- a/atom/browser/ui/views/native_frame_view.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/native_frame_view.h" - -#include "atom/browser/native_window.h" - -namespace atom { - -namespace { - -const char kViewClassName[] = "AtomNativeFrameView"; - -} // namespace - -NativeFrameView::NativeFrameView(NativeWindow* window, views::Widget* widget) - : views::NativeFrameView(widget), - window_(window) { -} - -gfx::Size NativeFrameView::GetMinimumSize() const { - return window_->GetMinimumSize(); -} - -gfx::Size NativeFrameView::GetMaximumSize() const { - return window_->GetMaximumSize(); -} - -const char* NativeFrameView::GetClassName() const { - return kViewClassName; -} - -} // namespace atom diff --git a/atom/browser/ui/views/native_frame_view.h b/atom/browser/ui/views/native_frame_view.h deleted file mode 100644 index 670459f1cbd0a..0000000000000 --- a/atom/browser/ui/views/native_frame_view.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_NATIVE_FRAME_VIEW_H_ -#define ATOM_BROWSER_UI_VIEWS_NATIVE_FRAME_VIEW_H_ - -#include "ui/views/window/native_frame_view.h" - -namespace atom { - -class NativeWindow; - -// Like the views::NativeFrameView, but returns the min/max size from the -// NativeWindowViews. -class NativeFrameView : public views::NativeFrameView { - public: - NativeFrameView(NativeWindow* window, views::Widget* widget); - - protected: - // views::View: - gfx::Size GetMinimumSize() const override; - gfx::Size GetMaximumSize() const override; - const char* GetClassName() const override; - - private: - NativeWindow* window_; // weak ref. - - DISALLOW_COPY_AND_ASSIGN(NativeFrameView); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_NATIVE_FRAME_VIEW_H_ diff --git a/atom/browser/ui/views/submenu_button.cc b/atom/browser/ui/views/submenu_button.cc deleted file mode 100644 index ca06d7d627ef4..0000000000000 --- a/atom/browser/ui/views/submenu_button.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/submenu_button.h" - -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/text_utils.h" -#include "ui/views/controls/button/label_button_border.h" - -namespace atom { - -namespace { - -// Filter out the "&" in menu label. -base::string16 FilterAccelerator(const base::string16& label) { - base::string16 out; - base::RemoveChars(label, base::ASCIIToUTF16("&").c_str(), &out); - return out; -} - -} // namespace - -SubmenuButton::SubmenuButton(views::ButtonListener* listener, - const base::string16& title, - views::MenuButtonListener* menu_button_listener) - : views::MenuButton(FilterAccelerator(title), - menu_button_listener, false), - accelerator_(0), - show_underline_(false), - underline_start_(-1), - underline_end_(-1), - text_width_(0), - text_height_(0), - underline_color_(SK_ColorBLACK) { -#if defined(OS_LINUX) - // Dont' use native style border. - SetBorder(std::move(CreateDefaultBorder())); -#endif - - if (GetUnderlinePosition(title, &accelerator_, &underline_start_, - &underline_end_)) - gfx::Canvas::SizeStringInt(GetText(), GetFontList(), &text_width_, - &text_height_, 0, 0); -} - -SubmenuButton::~SubmenuButton() { -} - -void SubmenuButton::SetAcceleratorVisibility(bool visible) { - if (visible == show_underline_) - return; - - show_underline_ = visible; - SchedulePaint(); -} - -void SubmenuButton::SetUnderlineColor(SkColor color) { - underline_color_ = color; -} - -void SubmenuButton::OnPaint(gfx::Canvas* canvas) { - views::MenuButton::OnPaint(canvas); - - if (show_underline_ && (underline_start_ != underline_end_)) { - int padding = (width() - text_width_) / 2; - int underline_height = (height() + text_height_) / 2 - 2; - canvas->DrawLine(gfx::Point(underline_start_ + padding, underline_height), - gfx::Point(underline_end_ + padding, underline_height), - underline_color_); - } -} - -bool SubmenuButton::GetUnderlinePosition(const base::string16& text, - base::char16* accelerator, - int* start, int* end) { - int pos, span; - base::string16 trimmed = gfx::RemoveAcceleratorChar(text, '&', &pos, &span); - if (pos > -1 && span != 0) { - *accelerator = base::ToUpperASCII(trimmed[pos]); - GetCharacterPosition(trimmed, pos, start); - GetCharacterPosition(trimmed, pos + span, end); - return true; - } - - return false; -} - -void SubmenuButton::GetCharacterPosition( - const base::string16& text, int index, int* pos) { - int height; - gfx::Canvas::SizeStringInt(text.substr(0, index), GetFontList(), pos, &height, - 0, 0); -} - -} // namespace atom diff --git a/atom/browser/ui/views/submenu_button.h b/atom/browser/ui/views/submenu_button.h deleted file mode 100644 index 3f72a60c10b49..0000000000000 --- a/atom/browser/ui/views/submenu_button.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_SUBMENU_BUTTON_H_ -#define ATOM_BROWSER_UI_VIEWS_SUBMENU_BUTTON_H_ - -#include "ui/views/controls/button/menu_button.h" - -namespace atom { - -// Special button that used by menu bar to show submenus. -class SubmenuButton : public views::MenuButton { - public: - SubmenuButton(views::ButtonListener* listener, - const base::string16& title, - views::MenuButtonListener* menu_button_listener); - virtual ~SubmenuButton(); - - void SetAcceleratorVisibility(bool visible); - void SetUnderlineColor(SkColor color); - - void SetEnabledColor(SkColor color); - void SetBackgroundColor(SkColor color); - - base::char16 accelerator() const { return accelerator_; } - - // views::MenuButton: - void OnPaint(gfx::Canvas* canvas) override; - - private: - bool GetUnderlinePosition(const base::string16& text, - base::char16* accelerator, - int* start, int* end); - void GetCharacterPosition( - const base::string16& text, int index, int* pos); - - base::char16 accelerator_; - - bool show_underline_; - - int underline_start_; - int underline_end_; - int text_width_; - int text_height_; - SkColor underline_color_; - - DISALLOW_COPY_AND_ASSIGN(SubmenuButton); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_SUBMENU_BUTTON_H_ diff --git a/atom/browser/ui/views/win_frame_view.cc b/atom/browser/ui/views/win_frame_view.cc deleted file mode 100644 index fca7cb23347c6..0000000000000 --- a/atom/browser/ui/views/win_frame_view.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/views/win_frame_view.h" - -#include "atom/browser/native_window_views.h" -#include "ui/views/widget/widget.h" -#include "ui/views/win/hwnd_util.h" - -namespace atom { - -namespace { - -const char kViewClassName[] = "WinFrameView"; - -} // namespace - - -WinFrameView::WinFrameView() { -} - -WinFrameView::~WinFrameView() { -} - - -gfx::Rect WinFrameView::GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const { - return views::GetWindowBoundsForClientBounds( - static_cast(const_cast(this)), - client_bounds); -} - -int WinFrameView::NonClientHitTest(const gfx::Point& point) { - if (window_->has_frame()) - return frame_->client_view()->NonClientHitTest(point); - else - return FramelessView::NonClientHitTest(point); -} - -const char* WinFrameView::GetClassName() const { - return kViewClassName; -} - -} // namespace atom diff --git a/atom/browser/ui/views/win_frame_view.h b/atom/browser/ui/views/win_frame_view.h deleted file mode 100644 index b2c1ef3a15de9..0000000000000 --- a/atom/browser/ui/views/win_frame_view.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_ -#define ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_ - -#include "atom/browser/ui/views/frameless_view.h" - -namespace atom { - -class WinFrameView : public FramelessView { - public: - WinFrameView(); - virtual ~WinFrameView(); - - // views::NonClientFrameView: - gfx::Rect GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const override; - int NonClientHitTest(const gfx::Point& point) override; - - // views::View: - const char* GetClassName() const override; - - private: - DISALLOW_COPY_AND_ASSIGN(WinFrameView); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_VIEWS_WIN_FRAME_VIEW_H_ diff --git a/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc b/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc deleted file mode 100644 index 84a6d9aa3e50c..0000000000000 --- a/atom/browser/ui/win/atom_desktop_window_tree_host_win.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h" - -#include "atom/browser/ui/win/message_handler_delegate.h" - -namespace atom { - -AtomDesktopWindowTreeHostWin::AtomDesktopWindowTreeHostWin( - MessageHandlerDelegate* delegate, - views::internal::NativeWidgetDelegate* native_widget_delegate, - views::DesktopNativeWidgetAura* desktop_native_widget_aura) - : views::DesktopWindowTreeHostWin(native_widget_delegate, - desktop_native_widget_aura), - delegate_(delegate) { -} - -AtomDesktopWindowTreeHostWin::~AtomDesktopWindowTreeHostWin() { -} - -bool AtomDesktopWindowTreeHostWin::PreHandleMSG( - UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) { - return delegate_->PreHandleMSG(message, w_param, l_param, result); -} - -} // namespace atom diff --git a/atom/browser/ui/win/atom_desktop_window_tree_host_win.h b/atom/browser/ui/win/atom_desktop_window_tree_host_win.h deleted file mode 100644 index 47e4cb6aed2a9..0000000000000 --- a/atom/browser/ui/win/atom_desktop_window_tree_host_win.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ -#define ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ - -#include - -#include - -#include "atom/browser/native_window.h" -#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" - -namespace atom { - -class MessageHandlerDelegate; - -class AtomDesktopWindowTreeHostWin : public views::DesktopWindowTreeHostWin { - public: - AtomDesktopWindowTreeHostWin( - MessageHandlerDelegate* delegate, - views::internal::NativeWidgetDelegate* native_widget_delegate, - views::DesktopNativeWidgetAura* desktop_native_widget_aura); - ~AtomDesktopWindowTreeHostWin() override; - - protected: - bool PreHandleMSG( - UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override; - - private: - MessageHandlerDelegate* delegate_; // weak ref - - DISALLOW_COPY_AND_ASSIGN(AtomDesktopWindowTreeHostWin); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_WIN_ATOM_DESKTOP_WINDOW_TREE_HOST_WIN_H_ diff --git a/atom/browser/ui/win/message_handler_delegate.cc b/atom/browser/ui/win/message_handler_delegate.cc deleted file mode 100644 index 791d1fd816d9e..0000000000000 --- a/atom/browser/ui/win/message_handler_delegate.cc +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/win/message_handler_delegate.h" - -namespace atom { - -bool MessageHandlerDelegate::PreHandleMSG( - UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) { - return false; -} - -} // namespace atom diff --git a/atom/browser/ui/win/message_handler_delegate.h b/atom/browser/ui/win/message_handler_delegate.h deleted file mode 100644 index d8cfcf7fc43b9..0000000000000 --- a/atom/browser/ui/win/message_handler_delegate.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_WIN_MESSAGE_HANDLER_DELEGATE_H_ -#define ATOM_BROWSER_UI_WIN_MESSAGE_HANDLER_DELEGATE_H_ - -#include - -namespace atom { - -class MessageHandlerDelegate { - public: - // Catch-all message handling and filtering. Called before - // HWNDMessageHandler's built-in handling, which may pre-empt some - // expectations in Views/Aura if messages are consumed. Returns true if the - // message was consumed by the delegate and should not be processed further - // by the HWNDMessageHandler. In this case, |result| is returned. |result| is - // not modified otherwise. - virtual bool PreHandleMSG( - UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_WIN_MESSAGE_HANDLER_DELEGATE_H_ diff --git a/atom/browser/ui/win/notify_icon.cc b/atom/browser/ui/win/notify_icon.cc deleted file mode 100644 index e62b682e3e58a..0000000000000 --- a/atom/browser/ui/win/notify_icon.cc +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/win/notify_icon.h" - -#include "atom/browser/ui/win/notify_icon_host.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/windows_version.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/image/image.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/display/screen.h" -#include "ui/display/win/screen_win.h" -#include "ui/views/controls/menu/menu_runner.h" - -namespace atom { - -NotifyIcon::NotifyIcon(NotifyIconHost* host, - UINT id, - HWND window, - UINT message) - : host_(host), - icon_id_(id), - window_(window), - message_id_(message), - menu_model_(NULL) { - NOTIFYICONDATA icon_data; - InitIconData(&icon_data); - icon_data.uFlags |= NIF_MESSAGE; - icon_data.uCallbackMessage = message_id_; - BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data); - // This can happen if the explorer process isn't running when we try to - // create the icon for some reason (for example, at startup). - if (!result) - LOG(WARNING) << "Unable to create status tray icon."; -} - -NotifyIcon::~NotifyIcon() { - // Remove our icon. - host_->Remove(this); - NOTIFYICONDATA icon_data; - InitIconData(&icon_data); - Shell_NotifyIcon(NIM_DELETE, &icon_data); -} - -void NotifyIcon::HandleClickEvent(int modifiers, - bool left_mouse_click, - bool double_button_click) { - gfx::Rect bounds = GetBounds(); - - if (left_mouse_click) { - if (double_button_click) // double left click - NotifyDoubleClicked(bounds, modifiers); - else // single left click - NotifyClicked(bounds, modifiers); - return; - } else if (!double_button_click) { // single right click - if (menu_model_) - PopUpContextMenu(gfx::Point(), menu_model_); - else - NotifyRightClicked(bounds, modifiers); - } -} - -void NotifyIcon::ResetIcon() { - NOTIFYICONDATA icon_data; - InitIconData(&icon_data); - // Delete any previously existing icon. - Shell_NotifyIcon(NIM_DELETE, &icon_data); - InitIconData(&icon_data); - icon_data.uFlags |= NIF_MESSAGE; - icon_data.uCallbackMessage = message_id_; - icon_data.hIcon = icon_.get(); - // If we have an image, then set the NIF_ICON flag, which tells - // Shell_NotifyIcon() to set the image for the status icon it creates. - if (icon_data.hIcon) - icon_data.uFlags |= NIF_ICON; - // Re-add our icon. - BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data); - if (!result) - LOG(WARNING) << "Unable to re-create status tray icon."; -} - -void NotifyIcon::SetImage(HICON image) { - icon_ = base::win::ScopedHICON(CopyIcon(image)); - - // Create the icon. - NOTIFYICONDATA icon_data; - InitIconData(&icon_data); - icon_data.uFlags |= NIF_ICON; - icon_data.hIcon = image; - BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); - if (!result) - LOG(WARNING) << "Error setting status tray icon image"; -} - -void NotifyIcon::SetPressedImage(HICON image) { - // Ignore pressed images, since the standard on Windows is to not highlight - // pressed status icons. -} - -void NotifyIcon::SetToolTip(const std::string& tool_tip) { - // Create the icon. - NOTIFYICONDATA icon_data; - InitIconData(&icon_data); - icon_data.uFlags |= NIF_TIP; - wcsncpy_s(icon_data.szTip, base::UTF8ToUTF16(tool_tip).c_str(), _TRUNCATE); - BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); - if (!result) - LOG(WARNING) << "Unable to set tooltip for status tray icon"; -} - -void NotifyIcon::DisplayBalloon(HICON icon, - const base::string16& title, - const base::string16& contents) { - NOTIFYICONDATA icon_data; - InitIconData(&icon_data); - icon_data.uFlags |= NIF_INFO; - icon_data.dwInfoFlags = NIIF_INFO; - wcsncpy_s(icon_data.szInfoTitle, title.c_str(), _TRUNCATE); - wcsncpy_s(icon_data.szInfo, contents.c_str(), _TRUNCATE); - icon_data.uTimeout = 0; - icon_data.hBalloonIcon = icon; - icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; - - BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); - if (!result) - LOG(WARNING) << "Unable to create status tray balloon."; -} - -void NotifyIcon::PopUpContextMenu(const gfx::Point& pos, - AtomMenuModel* menu_model) { - // Returns if context menu isn't set. - if (menu_model == nullptr && menu_model_ == nullptr) - return; - - // Set our window as the foreground window, so the context menu closes when - // we click away from it. - if (!SetForegroundWindow(window_)) - return; - - // Show menu at mouse's position by default. - gfx::Rect rect(pos, gfx::Size()); - if (pos.IsOrigin()) - rect.set_origin(display::Screen::GetScreen()->GetCursorScreenPoint()); - - views::MenuRunner menu_runner( - menu_model != nullptr ? menu_model : menu_model_, - views::MenuRunner::CONTEXT_MENU | views::MenuRunner::HAS_MNEMONICS); - ignore_result(menu_runner.RunMenuAt( - NULL, NULL, rect, views::MENU_ANCHOR_TOPLEFT, ui::MENU_SOURCE_MOUSE)); -} - -void NotifyIcon::SetContextMenu(AtomMenuModel* menu_model) { - menu_model_ = menu_model; -} - -gfx::Rect NotifyIcon::GetBounds() { - NOTIFYICONIDENTIFIER icon_id; - memset(&icon_id, 0, sizeof(NOTIFYICONIDENTIFIER)); - icon_id.uID = icon_id_; - icon_id.hWnd = window_; - icon_id.cbSize = sizeof(NOTIFYICONIDENTIFIER); - - RECT rect = { 0 }; - Shell_NotifyIconGetRect(&icon_id, &rect); - return display::win::ScreenWin::ScreenToDIPRect(window_, gfx::Rect(rect)); -} - -void NotifyIcon::InitIconData(NOTIFYICONDATA* icon_data) { - memset(icon_data, 0, sizeof(NOTIFYICONDATA)); - icon_data->cbSize = sizeof(NOTIFYICONDATA); - icon_data->hWnd = window_; - icon_data->uID = icon_id_; -} - -} // namespace atom diff --git a/atom/browser/ui/win/notify_icon.h b/atom/browser/ui/win/notify_icon.h deleted file mode 100644 index ae6c9ca8a14b2..0000000000000 --- a/atom/browser/ui/win/notify_icon.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_WIN_NOTIFY_ICON_H_ -#define ATOM_BROWSER_UI_WIN_NOTIFY_ICON_H_ - -#include -#include - -#include - -#include "atom/browser/ui/tray_icon.h" -#include "base/macros.h" -#include "base/compiler_specific.h" -#include "base/win/scoped_gdi_object.h" - -namespace gfx { -class Point; -} - -namespace atom { - -class NotifyIconHost; - -class NotifyIcon : public TrayIcon { - public: - // Constructor which provides this icon's unique ID and messaging window. - NotifyIcon(NotifyIconHost* host, UINT id, HWND window, UINT message); - virtual ~NotifyIcon(); - - // Handles a click event from the user - if |left_button_click| is true and - // there is a registered observer, passes the click event to the observer, - // otherwise displays the context menu if there is one. - void HandleClickEvent(int modifiers, - bool left_button_click, - bool double_button_click); - - // Re-creates the status tray icon now after the taskbar has been created. - void ResetIcon(); - - UINT icon_id() const { return icon_id_; } - HWND window() const { return window_; } - UINT message_id() const { return message_id_; } - - // Overridden from TrayIcon: - void SetImage(HICON image) override; - void SetPressedImage(HICON image) override; - void SetToolTip(const std::string& tool_tip) override; - void DisplayBalloon(HICON icon, - const base::string16& title, - const base::string16& contents) override; - void PopUpContextMenu(const gfx::Point& pos, - AtomMenuModel* menu_model) override; - void SetContextMenu(AtomMenuModel* menu_model) override; - gfx::Rect GetBounds() override; - - private: - void InitIconData(NOTIFYICONDATA* icon_data); - - // The tray that owns us. Weak. - NotifyIconHost* host_; - - // The unique ID corresponding to this icon. - UINT icon_id_; - - // Window used for processing messages from this icon. - HWND window_; - - // The message identifier used for status icon messages. - UINT message_id_; - - // The currently-displayed icon for the window. - base::win::ScopedHICON icon_; - - // The context menu. - AtomMenuModel* menu_model_; - - DISALLOW_COPY_AND_ASSIGN(NotifyIcon); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_WIN_NOTIFY_ICON_H_ diff --git a/atom/browser/ui/win/notify_icon_host.cc b/atom/browser/ui/win/notify_icon_host.cc deleted file mode 100644 index 1f0b35b09fd24..0000000000000 --- a/atom/browser/ui/win/notify_icon_host.cc +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/win/notify_icon_host.h" - -#include -#include - -#include "atom/browser/ui/win/notify_icon.h" -#include "base/bind.h" -#include "base/stl_util.h" -#include "base/threading/non_thread_safe.h" -#include "base/threading/thread.h" -#include "base/win/win_util.h" -#include "base/win/wrapped_window_proc.h" -#include "ui/events/event_constants.h" -#include "ui/events/win/system_event_state_lookup.h" -#include "ui/gfx/win/hwnd_util.h" - -namespace atom { - -namespace { - -const UINT kNotifyIconMessage = WM_APP + 1; - -// |kBaseIconId| is 2 to avoid conflicts with plugins that hard-code id 1. -const UINT kBaseIconId = 2; - -const wchar_t kNotifyIconHostWindowClass[] = L"Electron_NotifyIconHostWindow"; - -bool IsWinPressed() { - return ((::GetKeyState(VK_LWIN) & 0x8000) == 0x8000) || - ((::GetKeyState(VK_RWIN) & 0x8000) == 0x8000); -} - -int GetKeyboardModifers() { - int modifiers = ui::EF_NONE; - if (ui::win::IsShiftPressed()) - modifiers |= ui::EF_SHIFT_DOWN; - if (ui::win::IsCtrlPressed()) - modifiers |= ui::EF_CONTROL_DOWN; - if (ui::win::IsAltPressed()) - modifiers |= ui::EF_ALT_DOWN; - if (IsWinPressed()) - modifiers |= ui::EF_COMMAND_DOWN; - return modifiers; -} - -} // namespace - -NotifyIconHost::NotifyIconHost() - : next_icon_id_(1), - atom_(0), - instance_(NULL), - window_(NULL) { - // Register our window class - WNDCLASSEX window_class; - base::win::InitializeWindowClass( - kNotifyIconHostWindowClass, - &base::win::WrappedWindowProc, - 0, 0, 0, NULL, NULL, NULL, NULL, NULL, - &window_class); - instance_ = window_class.hInstance; - atom_ = RegisterClassEx(&window_class); - CHECK(atom_); - - // If the taskbar is re-created after we start up, we have to rebuild all of - // our icons. - taskbar_created_message_ = RegisterWindowMessage(TEXT("TaskbarCreated")); - - // Create an offscreen window for handling messages for the status icons. We - // create a hidden WS_POPUP window instead of an HWND_MESSAGE window, because - // only top-level windows such as popups can receive broadcast messages like - // "TaskbarCreated". - window_ = CreateWindow(MAKEINTATOM(atom_), - 0, WS_POPUP, 0, 0, 0, 0, 0, 0, instance_, 0); - gfx::CheckWindowCreated(window_); - gfx::SetWindowUserData(window_, this); -} - -NotifyIconHost::~NotifyIconHost() { - if (window_) - DestroyWindow(window_); - - if (atom_) - UnregisterClass(MAKEINTATOM(atom_), instance_); - - NotifyIcons copied_container(notify_icons_); - STLDeleteContainerPointers(copied_container.begin(), copied_container.end()); -} - -NotifyIcon* NotifyIconHost::CreateNotifyIcon() { - NotifyIcon* notify_icon = - new NotifyIcon(this, NextIconId(), window_, kNotifyIconMessage); - notify_icons_.push_back(notify_icon); - return notify_icon; -} - -void NotifyIconHost::Remove(NotifyIcon* icon) { - NotifyIcons::iterator i( - std::find(notify_icons_.begin(), notify_icons_.end(), icon)); - - if (i == notify_icons_.end()) { - NOTREACHED(); - return; - } - - notify_icons_.erase(i); -} - -LRESULT CALLBACK NotifyIconHost::WndProcStatic(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - NotifyIconHost* msg_wnd = reinterpret_cast( - GetWindowLongPtr(hwnd, GWLP_USERDATA)); - if (msg_wnd) - return msg_wnd->WndProc(hwnd, message, wparam, lparam); - else - return ::DefWindowProc(hwnd, message, wparam, lparam); -} - -LRESULT CALLBACK NotifyIconHost::WndProc(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - if (message == taskbar_created_message_) { - // We need to reset all of our icons because the taskbar went away. - for (NotifyIcons::const_iterator i(notify_icons_.begin()); - i != notify_icons_.end(); ++i) { - NotifyIcon* win_icon = static_cast(*i); - win_icon->ResetIcon(); - } - return TRUE; - } else if (message == kNotifyIconMessage) { - NotifyIcon* win_icon = NULL; - - // Find the selected status icon. - for (NotifyIcons::const_iterator i(notify_icons_.begin()); - i != notify_icons_.end(); ++i) { - NotifyIcon* current_win_icon = static_cast(*i); - if (current_win_icon->icon_id() == wparam) { - win_icon = current_win_icon; - break; - } - } - - // It is possible for this procedure to be called with an obsolete icon - // id. In that case we should just return early before handling any - // actions. - if (!win_icon) - return TRUE; - - switch (lparam) { - case TB_CHECKBUTTON: - win_icon->NotifyBalloonShow(); - return TRUE; - - case TB_INDETERMINATE: - win_icon->NotifyBalloonClicked(); - return TRUE; - - case TB_HIDEBUTTON: - win_icon->NotifyBalloonClosed(); - return TRUE; - - case WM_LBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_RBUTTONDBLCLK: - case WM_CONTEXTMENU: - // Walk our icons, find which one was clicked on, and invoke its - // HandleClickEvent() method. - win_icon->HandleClickEvent( - GetKeyboardModifers(), - (lparam == WM_LBUTTONDOWN || lparam == WM_LBUTTONDBLCLK), - (lparam == WM_LBUTTONDBLCLK || lparam == WM_RBUTTONDBLCLK)); - return TRUE; - } - } - return ::DefWindowProc(hwnd, message, wparam, lparam); -} - -UINT NotifyIconHost::NextIconId() { - UINT icon_id = next_icon_id_++; - return kBaseIconId + icon_id; -} - -} // namespace atom diff --git a/atom/browser/ui/win/notify_icon_host.h b/atom/browser/ui/win/notify_icon_host.h deleted file mode 100644 index 773b3112d4709..0000000000000 --- a/atom/browser/ui/win/notify_icon_host.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_WIN_NOTIFY_ICON_HOST_H_ -#define ATOM_BROWSER_UI_WIN_NOTIFY_ICON_HOST_H_ - -#include - -#include - -#include "base/macros.h" - -namespace atom { - -class NotifyIcon; - -class NotifyIconHost { - public: - NotifyIconHost(); - ~NotifyIconHost(); - - NotifyIcon* CreateNotifyIcon(); - void Remove(NotifyIcon* notify_icon); - - private: - typedef std::vector NotifyIcons; - - // Static callback invoked when a message comes in to our messaging window. - static LRESULT CALLBACK - WndProcStatic(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); - - LRESULT CALLBACK - WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); - - UINT NextIconId(); - - // The unique icon ID we will assign to the next icon. - UINT next_icon_id_; - - // List containing all active NotifyIcons. - NotifyIcons notify_icons_; - - // The window class of |window_|. - ATOM atom_; - - // The handle of the module that contains the window procedure of |window_|. - HMODULE instance_; - - // The window used for processing events. - HWND window_; - - // The message ID of the "TaskbarCreated" message, sent to us when we need to - // reset our status icons. - UINT taskbar_created_message_; - - DISALLOW_COPY_AND_ASSIGN(NotifyIconHost); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_WIN_NOTIFY_ICON_HOST_H_ diff --git a/atom/browser/ui/win/taskbar_host.cc b/atom/browser/ui/win/taskbar_host.cc deleted file mode 100644 index 8fef5e08a3fb5..0000000000000 --- a/atom/browser/ui/win/taskbar_host.cc +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/win/taskbar_host.h" - -#include - -#include "base/stl_util.h" -#include "base/win/scoped_gdi_object.h" -#include "base/strings/utf_string_conversions.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/icon_util.h" - -namespace atom { - -namespace { - -// From MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#thumbbars -// The thumbnail toolbar has a maximum of seven buttons due to the limited room. -const size_t kMaxButtonsCount = 7; - -// The base id of Thumbar button. -const int kButtonIdBase = 40001; - -bool GetThumbarButtonFlags(const std::vector& flags, - THUMBBUTTONFLAGS* out) { - THUMBBUTTONFLAGS result = THBF_ENABLED; // THBF_ENABLED == 0 - for (const auto& flag : flags) { - if (flag == "disabled") - result |= THBF_DISABLED; - else if (flag == "dismissonclick") - result |= THBF_DISMISSONCLICK; - else if (flag == "nobackground") - result |= THBF_NOBACKGROUND; - else if (flag == "hidden") - result |= THBF_HIDDEN; - else if (flag == "noninteractive") - result |= THBF_NONINTERACTIVE; - else - return false; - } - *out = result; - return true; -} - -} // namespace - -TaskbarHost::TaskbarHost() : thumbar_buttons_added_(false) { -} - -TaskbarHost::~TaskbarHost() { -} - -bool TaskbarHost::SetThumbarButtons( - HWND window, const std::vector& buttons) { - if (buttons.size() > kMaxButtonsCount || !InitializeTaskbar()) - return false; - - callback_map_.clear(); - - // The number of buttons in thumbar can not be changed once it is created, - // so we have to claim kMaxButtonsCount buttons initialy in case users add - // more buttons later. - base::win::ScopedHICON icons[kMaxButtonsCount] = {}; - THUMBBUTTON thumb_buttons[kMaxButtonsCount] = {}; - - for (size_t i = 0; i < kMaxButtonsCount; ++i) { - THUMBBUTTON& thumb_button = thumb_buttons[i]; - - // Set ID. - thumb_button.iId = kButtonIdBase + i; - thumb_button.dwMask = THB_FLAGS; - - if (i >= buttons.size()) { - // This button is used to occupy the place in toolbar, and it does not - // show. - thumb_button.dwFlags = THBF_HIDDEN; - continue; - } - - // This button is user's button. - const ThumbarButton& button = buttons[i]; - - // Generate flags. - thumb_button.dwFlags = THBF_ENABLED; - if (!GetThumbarButtonFlags(button.flags, &thumb_button.dwFlags)) - return false; - - // Set icon. - if (!button.icon.IsEmpty()) { - thumb_button.dwMask |= THB_ICON; - icons[i] = IconUtil::CreateHICONFromSkBitmap(button.icon.AsBitmap()); - thumb_button.hIcon = icons[i].get(); - } - - // Set tooltip. - if (!button.tooltip.empty()) { - thumb_button.dwMask |= THB_TOOLTIP; - wcsncpy_s(thumb_button.szTip, base::UTF8ToUTF16(button.tooltip).c_str(), - _TRUNCATE); - } - - // Save callback. - callback_map_[thumb_button.iId] = button.clicked_callback; - } - - // Finally add them to taskbar. - HRESULT r; - if (thumbar_buttons_added_) - r = taskbar_->ThumbBarUpdateButtons(window, kMaxButtonsCount, - thumb_buttons); - else - r = taskbar_->ThumbBarAddButtons(window, kMaxButtonsCount, thumb_buttons); - - thumbar_buttons_added_ = true; - return SUCCEEDED(r); -} - -bool TaskbarHost::SetProgressBar(HWND window, double value) { - if (!InitializeTaskbar()) - return false; - - HRESULT r; - if (value > 1.0) - r = taskbar_->SetProgressState(window, TBPF_INDETERMINATE); - else if (value < 0) - r = taskbar_->SetProgressState(window, TBPF_NOPROGRESS); - else - r = taskbar_->SetProgressValue(window, static_cast(value * 100), 100); - return SUCCEEDED(r); -} - -bool TaskbarHost::SetOverlayIcon( - HWND window, const gfx::Image& overlay, const std::string& text) { - if (!InitializeTaskbar()) - return false; - - base::win::ScopedHICON icon( - IconUtil::CreateHICONFromSkBitmap(overlay.AsBitmap())); - return SUCCEEDED(taskbar_->SetOverlayIcon( - window, icon.get(), base::UTF8ToUTF16(text).c_str())); -} - -bool TaskbarHost::SetThumbnailClip(HWND window, const gfx::Rect& region) { - if (!InitializeTaskbar()) - return false; - - if (region.IsEmpty()) { - return SUCCEEDED(taskbar_->SetThumbnailClip(window, NULL)); - } else { - RECT rect; - rect.left = region.x(); - rect.right = region.right(); - rect.top = region.y(); - rect.bottom = region.bottom(); - return SUCCEEDED(taskbar_->SetThumbnailClip(window, &rect)); - } -} - -bool TaskbarHost::HandleThumbarButtonEvent(int button_id) { - if (ContainsKey(callback_map_, button_id)) { - auto callback = callback_map_[button_id]; - if (!callback.is_null()) - callback.Run(); - return true; - } - return false; -} - -bool TaskbarHost::InitializeTaskbar() { - if (FAILED(taskbar_.CreateInstance(CLSID_TaskbarList, - nullptr, - CLSCTX_INPROC_SERVER)) || - FAILED(taskbar_->HrInit())) { - return false; - } else { - return true; - } -} - -} // namespace atom diff --git a/atom/browser/ui/win/taskbar_host.h b/atom/browser/ui/win/taskbar_host.h deleted file mode 100644 index c10e05f764ddf..0000000000000 --- a/atom/browser/ui/win/taskbar_host.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_WIN_TASKBAR_HOST_H_ -#define ATOM_BROWSER_UI_WIN_TASKBAR_HOST_H_ - -#include - -#include -#include -#include - -#include "base/callback.h" -#include "base/win/scoped_comptr.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/image/image.h" - -namespace atom { - -class TaskbarHost { - public: - struct ThumbarButton { - std::string tooltip; - gfx::Image icon; - std::vector flags; - base::Closure clicked_callback; - }; - - TaskbarHost(); - virtual ~TaskbarHost(); - - // Add or update the buttons in thumbar. - bool SetThumbarButtons( - HWND window, const std::vector& buttons); - - // Set the progress state in taskbar. - bool SetProgressBar(HWND window, double value); - - // Set the overlay icon in taskbar. - bool SetOverlayIcon( - HWND window, const gfx::Image& overlay, const std::string& text); - - // Set the region of the window to show as a thumbnail in taskbar. - bool TaskbarHost::SetThumbnailClip(HWND window, const gfx::Rect& region); - - // Called by the window that there is a button in thumbar clicked. - bool HandleThumbarButtonEvent(int button_id); - - private: - // Initialize the taskbar object. - bool InitializeTaskbar(); - - using CallbackMap = std::map; - CallbackMap callback_map_; - - // The COM object of taskbar. - base::win::ScopedComPtr taskbar_; - - // Whether we have already added the buttons to thumbar. - bool thumbar_buttons_added_; - - DISALLOW_COPY_AND_ASSIGN(TaskbarHost); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_WIN_TASKBAR_HOST_H_ diff --git a/atom/browser/ui/x/event_disabler.cc b/atom/browser/ui/x/event_disabler.cc deleted file mode 100644 index 6d0e4cfeb04bf..0000000000000 --- a/atom/browser/ui/x/event_disabler.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/x/event_disabler.h" - -namespace atom { - -EventDisabler::EventDisabler() { -} - -EventDisabler::~EventDisabler() { -} - -ui::EventRewriteStatus EventDisabler::RewriteEvent( - const ui::Event& event, - std::unique_ptr* rewritten_event) { - return ui::EVENT_REWRITE_DISCARD; -} - -ui::EventRewriteStatus EventDisabler::NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr* new_event) { - return ui::EVENT_REWRITE_CONTINUE; -} - -} // namespace atom diff --git a/atom/browser/ui/x/event_disabler.h b/atom/browser/ui/x/event_disabler.h deleted file mode 100644 index 9a6645bcdca31..0000000000000 --- a/atom/browser/ui/x/event_disabler.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_X_EVENT_DISABLER_H_ -#define ATOM_BROWSER_UI_X_EVENT_DISABLER_H_ - -#include "base/macros.h" -#include "ui/events/event_rewriter.h" - -namespace atom { - -class EventDisabler : public ui::EventRewriter { - public: - EventDisabler(); - ~EventDisabler() override; - - // ui::EventRewriter: - ui::EventRewriteStatus RewriteEvent( - const ui::Event& event, - std::unique_ptr* rewritten_event) override; - ui::EventRewriteStatus NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr* new_event) override; - - private: - DISALLOW_COPY_AND_ASSIGN(EventDisabler); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_X_EVENT_DISABLER_H_ diff --git a/atom/browser/ui/x/window_state_watcher.cc b/atom/browser/ui/x/window_state_watcher.cc deleted file mode 100644 index e1b2716b868f2..0000000000000 --- a/atom/browser/ui/x/window_state_watcher.cc +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/x/window_state_watcher.h" - -#include - -#include "ui/events/platform/platform_event_source.h" - -namespace atom { - -namespace { - -const char* kAtomsToCache[] = { - "_NET_WM_STATE", - NULL, -}; - -} // namespace - -WindowStateWatcher::WindowStateWatcher(NativeWindowViews* window) - : window_(window), - widget_(window->GetAcceleratedWidget()), - atom_cache_(gfx::GetXDisplay(), kAtomsToCache), - was_minimized_(false), - was_maximized_(false) { - ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this); -} - -WindowStateWatcher::~WindowStateWatcher() { - ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this); -} - -void WindowStateWatcher::WillProcessEvent(const ui::PlatformEvent& event) { - if (IsWindowStateEvent(event)) { - was_minimized_ = window_->IsMinimized(); - was_maximized_ = window_->IsMaximized(); - } -} - -void WindowStateWatcher::DidProcessEvent(const ui::PlatformEvent& event) { - if (IsWindowStateEvent(event)) { - bool is_minimized = window_->IsMinimized(); - bool is_maximized = window_->IsMaximized(); - bool is_fullscreen = window_->IsFullscreen(); - if (is_minimized != was_minimized_) { - if (is_minimized) - window_->NotifyWindowMinimize(); - else - window_->NotifyWindowRestore(); - } else if (is_maximized != was_maximized_) { - if (is_maximized) - window_->NotifyWindowMaximize(); - else - window_->NotifyWindowUnmaximize(); - } else { - // If this is neither a "maximize" or "minimize" event, then we think it - // is a "fullscreen" event. - // The "IsFullscreen()" becomes true immediately before "WillProcessEvent" - // is called, so we can not handle this like "maximize" and "minimize" by - // watching whether they have changed. - if (is_fullscreen) - window_->NotifyWindowEnterFullScreen(); - else - window_->NotifyWindowLeaveFullScreen(); - } - } -} - -bool WindowStateWatcher::IsWindowStateEvent(const ui::PlatformEvent& event) { - ::Atom changed_atom = event->xproperty.atom; - return (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE") && - event->type == PropertyNotify && - event->xproperty.window == widget_); -} - -} // namespace atom diff --git a/atom/browser/ui/x/window_state_watcher.h b/atom/browser/ui/x/window_state_watcher.h deleted file mode 100644 index 2888c9fc6fec1..0000000000000 --- a/atom/browser/ui/x/window_state_watcher.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_ -#define ATOM_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_ - -#include "ui/events/platform/platform_event_observer.h" - -#include "atom/browser/native_window_views.h" -#include "ui/gfx/x/x11_atom_cache.h" - -namespace atom { - -class WindowStateWatcher : public ui::PlatformEventObserver { - public: - explicit WindowStateWatcher(NativeWindowViews* window); - virtual ~WindowStateWatcher(); - - protected: - // ui::PlatformEventObserver: - void WillProcessEvent(const ui::PlatformEvent& event) override; - void DidProcessEvent(const ui::PlatformEvent& event) override; - - private: - bool IsWindowStateEvent(const ui::PlatformEvent& event); - - NativeWindowViews* window_; - gfx::AcceleratedWidget widget_; - - ui::X11AtomCache atom_cache_; - - bool was_minimized_; - bool was_maximized_; - - DISALLOW_COPY_AND_ASSIGN(WindowStateWatcher); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_ diff --git a/atom/browser/ui/x/x_window_utils.cc b/atom/browser/ui/x/x_window_utils.cc deleted file mode 100644 index 48e8bc977322a..0000000000000 --- a/atom/browser/ui/x/x_window_utils.cc +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/ui/x/x_window_utils.h" - -#include - -#include "base/environment.h" -#include "base/strings/string_util.h" -#include "dbus/bus.h" -#include "dbus/object_proxy.h" -#include "dbus/message.h" -#include "ui/base/x/x11_util.h" - -namespace atom { - -::Atom GetAtom(const char* name) { - return XInternAtom(gfx::GetXDisplay(), name, false); -} - -void SetWMSpecState(::Window xwindow, bool enabled, ::Atom state) { - XEvent xclient; - memset(&xclient, 0, sizeof(xclient)); - xclient.type = ClientMessage; - xclient.xclient.window = xwindow; - xclient.xclient.message_type = GetAtom("_NET_WM_STATE"); - xclient.xclient.format = 32; - xclient.xclient.data.l[0] = enabled ? 1 : 0; - xclient.xclient.data.l[1] = state; - xclient.xclient.data.l[2] = None; - xclient.xclient.data.l[3] = 1; - xclient.xclient.data.l[4] = 0; - - XDisplay* xdisplay = gfx::GetXDisplay(); - XSendEvent(xdisplay, DefaultRootWindow(xdisplay), False, - SubstructureRedirectMask | SubstructureNotifyMask, - &xclient); -} - -void SetWindowType(::Window xwindow, const std::string& type) { - XDisplay* xdisplay = gfx::GetXDisplay(); - std::string type_prefix = "_NET_WM_WINDOW_TYPE_"; - ::Atom window_type = XInternAtom( - xdisplay, (type_prefix + base::ToUpperASCII(type)).c_str(), False); - XChangeProperty(xdisplay, xwindow, - XInternAtom(xdisplay, "_NET_WM_WINDOW_TYPE", False), - XA_ATOM, - 32, PropModeReplace, - reinterpret_cast(&window_type), 1); -} - -bool ShouldUseGlobalMenuBar() { - std::unique_ptr env(base::Environment::Create()); - if (env->HasVar("ELECTRON_FORCE_WINDOW_MENU_BAR")) - return false; - - dbus::Bus::Options options; - scoped_refptr bus(new dbus::Bus(options)); - - dbus::ObjectProxy* object_proxy = - bus->GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS)); - dbus::MethodCall method_call(DBUS_INTERFACE_DBUS, "ListNames"); - std::unique_ptr response(object_proxy->CallMethodAndBlock( - &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); - if (!response) { - bus->ShutdownAndBlock(); - return false; - } - - dbus::MessageReader reader(response.get()); - dbus::MessageReader array_reader(NULL); - if (!reader.PopArray(&array_reader)) { - bus->ShutdownAndBlock(); - return false; - } - while (array_reader.HasMoreData()) { - std::string name; - if (array_reader.PopString(&name) && - name == "com.canonical.AppMenu.Registrar") { - bus->ShutdownAndBlock(); - return true; - } - } - - bus->ShutdownAndBlock(); - return false; -} - -} // namespace atom diff --git a/atom/browser/ui/x/x_window_utils.h b/atom/browser/ui/x/x_window_utils.h deleted file mode 100644 index 16f3ddac6ccd8..0000000000000 --- a/atom/browser/ui/x/x_window_utils.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_ -#define ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_ - -#include -#include -#include - -#include - -namespace atom { - -::Atom GetAtom(const char* name); - -// Sends a message to the x11 window manager, enabling or disabling the |state| -// for _NET_WM_STATE. -void SetWMSpecState(::Window xwindow, bool enabled, ::Atom state); - -// Sets the _NET_WM_WINDOW_TYPE of window. -void SetWindowType(::Window xwindow, const std::string& type); - -// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available. -bool ShouldUseGlobalMenuBar(); - -} // namespace atom - -#endif // ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_ diff --git a/atom/browser/unresponsive_suppressor.cc b/atom/browser/unresponsive_suppressor.cc deleted file mode 100644 index 89bfa6b9003b3..0000000000000 --- a/atom/browser/unresponsive_suppressor.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/unresponsive_suppressor.h" - -namespace atom { - -namespace { - -int g_suppress_level = 0; - -} // namespace - -bool IsUnresponsiveEventSuppressed() { - return g_suppress_level > 0; -} - -UnresponsiveSuppressor::UnresponsiveSuppressor() { - g_suppress_level++; -} - -UnresponsiveSuppressor::~UnresponsiveSuppressor() { - g_suppress_level--; -} - -} // namespace atom diff --git a/atom/browser/unresponsive_suppressor.h b/atom/browser/unresponsive_suppressor.h deleted file mode 100644 index 9fb3819237d53..0000000000000 --- a/atom/browser/unresponsive_suppressor.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_UNRESPONSIVE_SUPPRESSOR_H_ -#define ATOM_BROWSER_UNRESPONSIVE_SUPPRESSOR_H_ - -#include "base/macros.h" - -namespace atom { - -bool IsUnresponsiveEventSuppressed(); - -class UnresponsiveSuppressor { - public: - UnresponsiveSuppressor(); - ~UnresponsiveSuppressor(); - - private: - DISALLOW_COPY_AND_ASSIGN(UnresponsiveSuppressor); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_UNRESPONSIVE_SUPPRESSOR_H_ diff --git a/atom/browser/web_contents_permission_helper.cc b/atom/browser/web_contents_permission_helper.cc deleted file mode 100644 index 73405b571934c..0000000000000 --- a/atom/browser/web_contents_permission_helper.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/web_contents_permission_helper.h" - -#include - -#include "atom/browser/atom_permission_manager.h" -#include "brightray/browser/media/media_stream_devices_controller.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/render_process_host.h" - -DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::WebContentsPermissionHelper); - -namespace atom { - -namespace { - -void MediaAccessAllowed( - const content::MediaStreamRequest& request, - const content::MediaResponseCallback& callback, - bool allowed) { - brightray::MediaStreamDevicesController controller(request, callback); - if (allowed) - controller.TakeAction(); - else - controller.Deny(content::MEDIA_DEVICE_PERMISSION_DENIED); -} - -void OnPointerLockResponse(content::WebContents* web_contents, bool allowed) { - if (web_contents) - web_contents->GotResponseToLockMouseRequest(allowed); -} - -void OnPermissionResponse(const base::Callback& callback, - blink::mojom::PermissionStatus status) { - if (status == blink::mojom::PermissionStatus::GRANTED) - callback.Run(true); - else - callback.Run(false); -} - -} // namespace - -WebContentsPermissionHelper::WebContentsPermissionHelper( - content::WebContents* web_contents) - : web_contents_(web_contents) { -} - -WebContentsPermissionHelper::~WebContentsPermissionHelper() { -} - -void WebContentsPermissionHelper::RequestPermission( - content::PermissionType permission, - const base::Callback& callback, - bool user_gesture) { - auto rfh = web_contents_->GetMainFrame(); - auto permission_manager = static_cast( - web_contents_->GetBrowserContext()->GetPermissionManager()); - auto origin = web_contents_->GetLastCommittedURL(); - permission_manager->RequestPermission( - permission, rfh, origin, - base::Bind(&OnPermissionResponse, callback)); -} - -void WebContentsPermissionHelper::RequestFullscreenPermission( - const base::Callback& callback) { - RequestPermission((content::PermissionType)(PermissionType::FULLSCREEN), - callback); -} - -void WebContentsPermissionHelper::RequestMediaAccessPermission( - const content::MediaStreamRequest& request, - const content::MediaResponseCallback& response_callback) { - auto callback = base::Bind(&MediaAccessAllowed, request, response_callback); - // The permission type doesn't matter here, AUDIO_CAPTURE/VIDEO_CAPTURE - // are presented as same type in content_converter.h. - RequestPermission(content::PermissionType::AUDIO_CAPTURE, callback); -} - -void WebContentsPermissionHelper::RequestWebNotificationPermission( - const base::Callback& callback) { - RequestPermission(content::PermissionType::NOTIFICATIONS, callback); -} - -void WebContentsPermissionHelper::RequestPointerLockPermission( - bool user_gesture) { - RequestPermission((content::PermissionType)(PermissionType::POINTER_LOCK), - base::Bind(&OnPointerLockResponse, web_contents_), - user_gesture); -} - -void WebContentsPermissionHelper::RequestOpenExternalPermission( - const base::Callback& callback, - bool user_gesture) { - RequestPermission((content::PermissionType)(PermissionType::OPEN_EXTERNAL), - callback, - user_gesture); -} - -} // namespace atom diff --git a/atom/browser/web_contents_permission_helper.h b/atom/browser/web_contents_permission_helper.h deleted file mode 100644 index 89da64b758337..0000000000000 --- a/atom/browser/web_contents_permission_helper.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_WEB_CONTENTS_PERMISSION_HELPER_H_ -#define ATOM_BROWSER_WEB_CONTENTS_PERMISSION_HELPER_H_ - -#include "content/public/browser/permission_type.h" -#include "content/public/browser/web_contents_user_data.h" -#include "content/public/common/media_stream_request.h" - -namespace atom { - -// Applies the permission requested for WebContents. -class WebContentsPermissionHelper - : public content::WebContentsUserData { - public: - ~WebContentsPermissionHelper() override; - - enum class PermissionType { - POINTER_LOCK = static_cast(content::PermissionType::NUM) + 1, - FULLSCREEN, - OPEN_EXTERNAL, - }; - - void RequestFullscreenPermission( - const base::Callback& callback); - void RequestMediaAccessPermission( - const content::MediaStreamRequest& request, - const content::MediaResponseCallback& callback); - void RequestWebNotificationPermission( - const base::Callback& callback); - void RequestPointerLockPermission(bool user_gesture); - void RequestOpenExternalPermission( - const base::Callback& callback, - bool user_gesture); - - private: - explicit WebContentsPermissionHelper(content::WebContents* web_contents); - friend class content::WebContentsUserData; - - void RequestPermission( - content::PermissionType permission, - const base::Callback& callback, - bool user_gesture = false); - - content::WebContents* web_contents_; - - DISALLOW_COPY_AND_ASSIGN(WebContentsPermissionHelper); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_WEB_CONTENTS_PERMISSION_HELPER_H_ diff --git a/atom/browser/web_contents_preferences.cc b/atom/browser/web_contents_preferences.cc deleted file mode 100644 index 7faf8c8899caa..0000000000000 --- a/atom/browser/web_contents_preferences.cc +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/web_contents_preferences.h" - -#include -#include -#include - -#include "atom/browser/native_window.h" -#include "atom/browser/web_view_manager.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/options_switches.h" -#include "base/command_line.h" -#include "base/strings/string_number_conversions.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/common/content_switches.h" -#include "content/public/common/web_preferences.h" -#include "native_mate/dictionary.h" -#include "net/base/filename_util.h" -#include "cc/base/switches.h" - -#if defined(OS_WIN) -#include "ui/gfx/switches.h" -#endif - -DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::WebContentsPreferences); - -namespace atom { - -// static -std::vector WebContentsPreferences::instances_; - -WebContentsPreferences::WebContentsPreferences( - content::WebContents* web_contents, - const mate::Dictionary& web_preferences) - : web_contents_(web_contents) { - v8::Isolate* isolate = web_preferences.isolate(); - mate::Dictionary copied(isolate, web_preferences.GetHandle()->Clone()); - // Following fields should not be stored. - copied.Delete("embedder"); - copied.Delete("isGuest"); - copied.Delete("session"); - - mate::ConvertFromV8(isolate, copied.GetHandle(), &web_preferences_); - web_contents->SetUserData(UserDataKey(), this); - - instances_.push_back(this); -} - -WebContentsPreferences::~WebContentsPreferences() { - instances_.erase( - std::remove(instances_.begin(), instances_.end(), this), - instances_.end()); -} - -void WebContentsPreferences::Merge(const base::DictionaryValue& extend) { - web_preferences_.MergeDictionary(&extend); -} - -// static -content::WebContents* WebContentsPreferences::GetWebContentsFromProcessID( - int process_id) { - for (WebContentsPreferences* preferences : instances_) { - content::WebContents* web_contents = preferences->web_contents_; - if (web_contents->GetRenderProcessHost()->GetID() == process_id) - return web_contents; - } - return nullptr; -} - -// static -void WebContentsPreferences::AppendExtraCommandLineSwitches( - content::WebContents* web_contents, base::CommandLine* command_line) { - WebContentsPreferences* self = FromWebContents(web_contents); - if (!self) - return; - - base::DictionaryValue& web_preferences = self->web_preferences_; - - bool b; - // Check if plugins are enabled. - if (web_preferences.GetBoolean("plugins", &b) && b) - command_line->AppendSwitch(switches::kEnablePlugins); - - // Experimental flags. - if (web_preferences.GetBoolean(options::kExperimentalFeatures, &b) && b) - command_line->AppendSwitch( - ::switches::kEnableExperimentalWebPlatformFeatures); - if (web_preferences.GetBoolean(options::kExperimentalCanvasFeatures, &b) && b) - command_line->AppendSwitch(::switches::kEnableExperimentalCanvasFeatures); - - // Check if we have node integration specified. - bool node_integration = true; - web_preferences.GetBoolean(options::kNodeIntegration, &node_integration); - command_line->AppendSwitchASCII(switches::kNodeIntegration, - node_integration ? "true" : "false"); - - // The preload script. - base::FilePath::StringType preload; - if (web_preferences.GetString(options::kPreloadScript, &preload)) { - if (base::FilePath(preload).IsAbsolute()) - command_line->AppendSwitchNative(switches::kPreloadScript, preload); - else - LOG(ERROR) << "preload script must have absolute path."; - } else if (web_preferences.GetString(options::kPreloadURL, &preload)) { - // Translate to file path if there is "preload-url" option. - base::FilePath preload_path; - if (net::FileURLToFilePath(GURL(preload), &preload_path)) - command_line->AppendSwitchPath(switches::kPreloadScript, preload_path); - else - LOG(ERROR) << "preload url must be file:// protocol."; - } - - // --background-color. - std::string color; - if (web_preferences.GetString(options::kBackgroundColor, &color)) - command_line->AppendSwitchASCII(switches::kBackgroundColor, color); - - // The zoom factor. - double zoom_factor = 1.0; - if (web_preferences.GetDouble(options::kZoomFactor, &zoom_factor) && - zoom_factor != 1.0) - command_line->AppendSwitchASCII(switches::kZoomFactor, - base::DoubleToString(zoom_factor)); - - // --guest-instance-id, which is used to identify guest WebContents. - int guest_instance_id = 0; - if (web_preferences.GetInteger(options::kGuestInstanceID, &guest_instance_id)) - command_line->AppendSwitchASCII(switches::kGuestInstanceID, - base::IntToString(guest_instance_id)); - - // Pass the opener's window id. - int opener_id; - if (web_preferences.GetInteger(options::kOpenerID, &opener_id)) - command_line->AppendSwitchASCII(switches::kOpenerID, - base::IntToString(opener_id)); - -#if defined(OS_MACOSX) - // Enable scroll bounce. - bool scroll_bounce; - if (web_preferences.GetBoolean(options::kScrollBounce, &scroll_bounce) && - scroll_bounce) - command_line->AppendSwitch(switches::kScrollBounce); -#endif - - // Custom command line switches. - const base::ListValue* args; - if (web_preferences.GetList("commandLineSwitches", &args)) { - for (size_t i = 0; i < args->GetSize(); ++i) { - std::string arg; - if (args->GetString(i, &arg) && !arg.empty()) - command_line->AppendSwitch(arg); - } - } - - // Enable blink features. - std::string blink_features; - if (web_preferences.GetString(options::kBlinkFeatures, &blink_features)) - command_line->AppendSwitchASCII(::switches::kEnableBlinkFeatures, - blink_features); - - // Disable blink features. - std::string disable_blink_features; - if (web_preferences.GetString(options::kDisableBlinkFeatures, - &disable_blink_features)) - command_line->AppendSwitchASCII(::switches::kDisableBlinkFeatures, - disable_blink_features); - - // The initial visibility state. - NativeWindow* window = NativeWindow::FromWebContents(web_contents); - - // Use embedder window for webviews - if (guest_instance_id && !window) { - auto manager = WebViewManager::GetWebViewManager(web_contents); - if (manager) { - auto embedder = manager->GetEmbedder(guest_instance_id); - if (embedder) - window = NativeWindow::FromWebContents(embedder); - } - } - - if (window) { - bool visible = window->IsVisible() && !window->IsMinimized(); - if (!visible) // Default state is visible. - command_line->AppendSwitch("hidden-page"); - } - - // Use frame scheduling for offscreen renderers. - // TODO(zcbenz): Remove this after Chrome 54, on which it becomes default. - bool offscreen; - if (web_preferences.GetBoolean("offscreen", &offscreen) && offscreen) - command_line->AppendSwitch(cc::switches::kEnableBeginFrameScheduling); -} - -// static -void WebContentsPreferences::OverrideWebkitPrefs( - content::WebContents* web_contents, content::WebPreferences* prefs) { - WebContentsPreferences* self = FromWebContents(web_contents); - if (!self) - return; - - bool b; - if (self->web_preferences_.GetBoolean("javascript", &b)) - prefs->javascript_enabled = b; - if (self->web_preferences_.GetBoolean("images", &b)) - prefs->images_enabled = b; - if (self->web_preferences_.GetBoolean("textAreasAreResizable", &b)) - prefs->text_areas_are_resizable = b; - if (self->web_preferences_.GetBoolean("webgl", &b)) - prefs->experimental_webgl_enabled = b; - if (self->web_preferences_.GetBoolean("webSecurity", &b)) { - prefs->web_security_enabled = b; - prefs->allow_displaying_insecure_content = !b; - prefs->allow_running_insecure_content = !b; - } - if (self->web_preferences_.GetBoolean("allowDisplayingInsecureContent", &b)) - prefs->allow_displaying_insecure_content = b; - if (self->web_preferences_.GetBoolean("allowRunningInsecureContent", &b)) - prefs->allow_running_insecure_content = b; - const base::DictionaryValue* fonts = nullptr; - if (self->web_preferences_.GetDictionary("defaultFontFamily", &fonts)) { - base::string16 font; - if (fonts->GetString("standard", &font)) - prefs->standard_font_family_map[content::kCommonScript] = font; - if (fonts->GetString("serif", &font)) - prefs->serif_font_family_map[content::kCommonScript] = font; - if (fonts->GetString("sansSerif", &font)) - prefs->sans_serif_font_family_map[content::kCommonScript] = font; - if (fonts->GetString("monospace", &font)) - prefs->fixed_font_family_map[content::kCommonScript] = font; - } - int size; - if (self->web_preferences_.GetInteger("defaultFontSize", &size)) - prefs->default_font_size = size; - if (self->web_preferences_.GetInteger("defaultMonospaceFontSize", &size)) - prefs->default_fixed_font_size = size; - if (self->web_preferences_.GetInteger("minimumFontSize", &size)) - prefs->minimum_font_size = size; - std::string encoding; - if (self->web_preferences_.GetString("defaultEncoding", &encoding)) - prefs->default_encoding = encoding; -} - -} // namespace atom diff --git a/atom/browser/web_contents_preferences.h b/atom/browser/web_contents_preferences.h deleted file mode 100644 index daf1f6e84de56..0000000000000 --- a/atom/browser/web_contents_preferences.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_WEB_CONTENTS_PREFERENCES_H_ -#define ATOM_BROWSER_WEB_CONTENTS_PREFERENCES_H_ - -#include - -#include "base/values.h" -#include "content/public/browser/web_contents_user_data.h" - -namespace base { -class CommandLine; -} - -namespace content { -struct WebPreferences; -} - -namespace mate { -class Dictionary; -} - -namespace atom { - -// Stores and applies the preferences of WebContents. -class WebContentsPreferences - : public content::WebContentsUserData { - public: - // Get WebContents according to process ID. - // FIXME(zcbenz): This method does not belong here. - static content::WebContents* GetWebContentsFromProcessID(int process_id); - - // Append command paramters according to |web_contents|'s preferences. - static void AppendExtraCommandLineSwitches( - content::WebContents* web_contents, base::CommandLine* command_line); - - // Modify the WebPreferences according to |web_contents|'s preferences. - static void OverrideWebkitPrefs( - content::WebContents* web_contents, content::WebPreferences* prefs); - - WebContentsPreferences(content::WebContents* web_contents, - const mate::Dictionary& web_preferences); - ~WebContentsPreferences() override; - - // $.extend(|web_preferences_|, |new_web_preferences|). - void Merge(const base::DictionaryValue& new_web_preferences); - - // Returns the web preferences. - base::DictionaryValue* web_preferences() { return &web_preferences_; } - - private: - friend class content::WebContentsUserData; - - static std::vector instances_; - - content::WebContents* web_contents_; - base::DictionaryValue web_preferences_; - - DISALLOW_COPY_AND_ASSIGN(WebContentsPreferences); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_WEB_CONTENTS_PREFERENCES_H_ diff --git a/atom/browser/web_dialog_helper.cc b/atom/browser/web_dialog_helper.cc deleted file mode 100644 index 2d2a9e5db80d1..0000000000000 --- a/atom/browser/web_dialog_helper.cc +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/web_dialog_helper.h" - -#include -#include - -#include "atom/browser/atom_browser_context.h" -#include "atom/browser/native_window.h" -#include "atom/browser/ui/file_dialog.h" -#include "base/bind.h" -#include "base/files/file_enumerator.h" -#include "base/files/file_path.h" -#include "components/prefs/pref_service.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/common/pref_names.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/file_chooser_file_info.h" -#include "net/base/mime_util.h" -#include "ui/shell_dialogs/selected_file_info.h" - -namespace { - -file_dialog::Filters GetFileTypesFromAcceptType( - const std::vector& accept_types) { - file_dialog::Filters filters; - if (accept_types.empty()) - return filters; - - std::vector extensions; - - for (const auto& accept_type : accept_types) { - std::string ascii_type = base::UTF16ToASCII(accept_type); - if (ascii_type[0] == '.') { - // If the type starts with a period it is assumed to be a file extension, - // like `.txt`, // so we just have to add it to the list. - base::FilePath::StringType extension( - ascii_type.begin(), ascii_type.end()); - // Skip the first character. - extensions.push_back(extension.substr(1)); - } else { - // For MIME Type, `audio/*, vidio/*, image/* - net::GetExtensionsForMimeType(ascii_type, &extensions); - } - } - - // If no valid exntesion is added, return empty filters. - if (extensions.empty()) - return filters; - - filters.push_back(file_dialog::Filter()); - for (const auto& extension : extensions) { -#if defined(OS_WIN) - filters[0].second.push_back(base::UTF16ToASCII(extension)); -#else - filters[0].second.push_back(extension); -#endif - } - return filters; -} - -} // namespace - -namespace atom { - -WebDialogHelper::WebDialogHelper(NativeWindow* window) - : window_(window), - weak_factory_(this) { -} - -WebDialogHelper::~WebDialogHelper() { -} - - -void WebDialogHelper::RunFileChooser(content::WebContents* web_contents, - const content::FileChooserParams& params) { - std::vector result; - file_dialog::Filters filters = GetFileTypesFromAcceptType( - params.accept_types); - if (params.mode == content::FileChooserParams::Save) { - base::FilePath path; - if (file_dialog::ShowSaveDialog(window_, - base::UTF16ToUTF8(params.title), - "", - params.default_file_name, - filters, - &path)) { - content::FileChooserFileInfo info; - info.file_path = path; - info.display_name = path.BaseName().value(); - result.push_back(info); - } - } else { - int flags = file_dialog::FILE_DIALOG_CREATE_DIRECTORY; - switch (params.mode) { - case content::FileChooserParams::OpenMultiple: - flags |= file_dialog::FILE_DIALOG_MULTI_SELECTIONS; - case content::FileChooserParams::Open: - flags |= file_dialog::FILE_DIALOG_OPEN_FILE; - break; - case content::FileChooserParams::UploadFolder: - flags |= file_dialog::FILE_DIALOG_OPEN_DIRECTORY; - break; - default: - NOTREACHED(); - } - - std::vector paths; - AtomBrowserContext* browser_context = static_cast( - window_->web_contents()->GetBrowserContext()); - base::FilePath default_file_path = browser_context->prefs()->GetFilePath( - prefs::kSelectFileLastDirectory).Append(params.default_file_name); - if (file_dialog::ShowOpenDialog(window_, - base::UTF16ToUTF8(params.title), - "", - default_file_path, - filters, - flags, - &paths)) { - for (auto& path : paths) { - content::FileChooserFileInfo info; - info.file_path = path; - info.display_name = path.BaseName().value(); - result.push_back(info); - } - if (!paths.empty()) { - browser_context->prefs()->SetFilePath(prefs::kSelectFileLastDirectory, - paths[0].DirName()); - } - } - } - - web_contents->GetRenderViewHost()->FilesSelectedInChooser( - result, params.mode); -} - -void WebDialogHelper::EnumerateDirectory(content::WebContents* web_contents, - int request_id, - const base::FilePath& dir) { - int types = base::FileEnumerator::FILES | - base::FileEnumerator::DIRECTORIES | - base::FileEnumerator::INCLUDE_DOT_DOT; - base::FileEnumerator file_enum(dir, false, types); - - base::FilePath path; - std::vector paths; - while (!(path = file_enum.Next()).empty()) - paths.push_back(path); - - web_contents->GetRenderViewHost()->DirectoryEnumerationFinished( - request_id, paths); -} - -} // namespace atom diff --git a/atom/browser/web_dialog_helper.h b/atom/browser/web_dialog_helper.h deleted file mode 100644 index a3472da4acbb9..0000000000000 --- a/atom/browser/web_dialog_helper.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_WEB_DIALOG_HELPER_H_ -#define ATOM_BROWSER_WEB_DIALOG_HELPER_H_ - -#include "base/memory/weak_ptr.h" - -namespace base { -class FilePath; -} - -namespace content { -struct FileChooserParams; -class WebContents; -} - -namespace atom { - -class NativeWindow; - -class WebDialogHelper { - public: - explicit WebDialogHelper(NativeWindow* window); - ~WebDialogHelper(); - - void RunFileChooser(content::WebContents* web_contents, - const content::FileChooserParams& params); - void EnumerateDirectory(content::WebContents* web_contents, - int request_id, - const base::FilePath& path); - - private: - NativeWindow* window_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(WebDialogHelper); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_WEB_DIALOG_HELPER_H_ diff --git a/atom/browser/web_view_guest_delegate.cc b/atom/browser/web_view_guest_delegate.cc deleted file mode 100644 index 7f5a9261b93de..0000000000000 --- a/atom/browser/web_view_guest_delegate.cc +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/web_view_guest_delegate.h" - -#include "atom/browser/api/atom_api_web_contents.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "content/public/browser/guest_host.h" -#include "content/public/browser/navigation_handle.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host.h" -#include "content/public/browser/render_widget_host_view.h" - -namespace atom { - -namespace { - -const int kDefaultWidth = 300; -const int kDefaultHeight = 300; - -} // namespace - -WebViewGuestDelegate::WebViewGuestDelegate() - : guest_host_(nullptr), - auto_size_enabled_(false), - is_full_page_plugin_(false), - api_web_contents_(nullptr) { -} - -WebViewGuestDelegate::~WebViewGuestDelegate() { -} - -void WebViewGuestDelegate::Initialize(api::WebContents* api_web_contents) { - api_web_contents_ = api_web_contents; - Observe(api_web_contents->GetWebContents()); -} - -void WebViewGuestDelegate::Destroy() { - // Give the content module an opportunity to perform some cleanup. - guest_host_->WillDestroy(); - guest_host_ = nullptr; -} - -void WebViewGuestDelegate::SetSize(const SetSizeParams& params) { - bool enable_auto_size = - params.enable_auto_size ? *params.enable_auto_size : auto_size_enabled_; - gfx::Size min_size = params.min_size ? *params.min_size : min_auto_size_; - gfx::Size max_size = params.max_size ? *params.max_size : max_auto_size_; - - if (params.normal_size) - normal_size_ = *params.normal_size; - - min_auto_size_ = min_size; - min_auto_size_.SetToMin(max_size); - max_auto_size_ = max_size; - max_auto_size_.SetToMax(min_size); - - enable_auto_size &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty(); - - auto rvh = web_contents()->GetRenderViewHost(); - if (enable_auto_size) { - // Autosize is being enabled. - rvh->EnableAutoResize(min_auto_size_, max_auto_size_); - normal_size_.SetSize(0, 0); - } else { - // Autosize is being disabled. - // Use default width/height if missing from partially defined normal size. - if (normal_size_.width() && !normal_size_.height()) - normal_size_.set_height(GetDefaultSize().height()); - if (!normal_size_.width() && normal_size_.height()) - normal_size_.set_width(GetDefaultSize().width()); - - gfx::Size new_size; - if (!normal_size_.IsEmpty()) { - new_size = normal_size_; - } else if (!guest_size_.IsEmpty()) { - new_size = guest_size_; - } else { - new_size = GetDefaultSize(); - } - - if (auto_size_enabled_) { - // Autosize was previously enabled. - rvh->DisableAutoResize(new_size); - GuestSizeChangedDueToAutoSize(guest_size_, new_size); - } else { - // Autosize was already disabled. - guest_host_->SizeContents(new_size); - } - - guest_size_ = new_size; - } - - auto_size_enabled_ = enable_auto_size; -} - -void WebViewGuestDelegate::DidFinishNavigation( - content::NavigationHandle* navigation_handle) { - if (navigation_handle->HasCommitted() && !navigation_handle->IsErrorPage()) { - auto is_main_frame = navigation_handle->IsInMainFrame(); - auto url = navigation_handle->GetURL(); - api_web_contents_->Emit("load-commit", url, is_main_frame); - } -} - -void WebViewGuestDelegate::DidAttach(int guest_proxy_routing_id) { - api_web_contents_->Emit("did-attach"); -} - -content::WebContents* WebViewGuestDelegate::GetOwnerWebContents() const { - return embedder_web_contents_; -} - -void WebViewGuestDelegate::GuestSizeChanged(const gfx::Size& new_size) { - if (!auto_size_enabled_) - return; - GuestSizeChangedDueToAutoSize(guest_size_, new_size); - guest_size_ = new_size; -} - -void WebViewGuestDelegate::SetGuestHost(content::GuestHost* guest_host) { - guest_host_ = guest_host; -} - -void WebViewGuestDelegate::WillAttach( - content::WebContents* embedder_web_contents, - int element_instance_id, - bool is_full_page_plugin, - const base::Closure& completion_callback) { - embedder_web_contents_ = embedder_web_contents; - is_full_page_plugin_ = is_full_page_plugin; - completion_callback.Run(); -} - -void WebViewGuestDelegate::GuestSizeChangedDueToAutoSize( - const gfx::Size& old_size, const gfx::Size& new_size) { - api_web_contents_->Emit("size-changed", - old_size.width(), old_size.height(), - new_size.width(), new_size.height()); -} - -gfx::Size WebViewGuestDelegate::GetDefaultSize() const { - if (is_full_page_plugin_) { - // Full page plugins default to the size of the owner's viewport. - return embedder_web_contents_->GetRenderWidgetHostView() - ->GetVisibleViewportSize(); - } else { - return gfx::Size(kDefaultWidth, kDefaultHeight); - } -} - -} // namespace atom diff --git a/atom/browser/web_view_guest_delegate.h b/atom/browser/web_view_guest_delegate.h deleted file mode 100644 index f63a46cf76ce7..0000000000000 --- a/atom/browser/web_view_guest_delegate.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_WEB_VIEW_GUEST_DELEGATE_H_ -#define ATOM_BROWSER_WEB_VIEW_GUEST_DELEGATE_H_ - -#include "content/public/browser/browser_plugin_guest_delegate.h" -#include "content/public/browser/web_contents_observer.h" - -namespace atom { - -namespace api { -class WebContents; -} - -// A struct of parameters for SetSize(). The parameters are all declared as -// scoped pointers since they are all optional. Null pointers indicate that the -// parameter has not been provided, and the last used value should be used. Note -// that when |enable_auto_size| is true, providing |normal_size| is not -// meaningful. This is because the normal size of the guestview is overridden -// whenever autosizing occurs. -struct SetSizeParams { - SetSizeParams() {} - ~SetSizeParams() {} - - std::unique_ptr enable_auto_size; - std::unique_ptr min_size; - std::unique_ptr max_size; - std::unique_ptr normal_size; -}; - -class WebViewGuestDelegate : public content::BrowserPluginGuestDelegate, - public content::WebContentsObserver { - public: - WebViewGuestDelegate(); - ~WebViewGuestDelegate() override; - - void Initialize(api::WebContents* api_web_contents); - - // Called when the WebContents is going to be destroyed. - void Destroy(); - - // Used to toggle autosize mode for this GuestView, and set both the automatic - // and normal sizes. - void SetSize(const SetSizeParams& params); - - protected: - // content::WebContentsObserver: - void DidFinishNavigation( - content::NavigationHandle* navigation_handle) override; - - // content::BrowserPluginGuestDelegate: - void DidAttach(int guest_proxy_routing_id) final; - content::WebContents* GetOwnerWebContents() const final; - void GuestSizeChanged(const gfx::Size& new_size) final; - void SetGuestHost(content::GuestHost* guest_host) final; - void WillAttach(content::WebContents* embedder_web_contents, - int element_instance_id, - bool is_full_page_plugin, - const base::Closure& completion_callback) final; - - private: - // This method is invoked when the contents auto-resized to give the container - // an opportunity to match it if it wishes. - // - // This gives the derived class an opportunity to inform its container element - // or perform other actions. - void GuestSizeChangedDueToAutoSize(const gfx::Size& old_size, - const gfx::Size& new_size); - - // Returns the default size of the guestview. - gfx::Size GetDefaultSize() const; - - // The WebContents that attaches this guest view. - content::WebContents* embedder_web_contents_; - - // The size of the container element. - gfx::Size element_size_; - - // The size of the guest content. Note: In autosize mode, the container - // element may not match the size of the guest. - gfx::Size guest_size_; - - // A pointer to the guest_host. - content::GuestHost* guest_host_; - - // Indicates whether autosize mode is enabled or not. - bool auto_size_enabled_; - - // The maximum size constraints of the container element in autosize mode. - gfx::Size max_auto_size_; - - // The minimum size constraints of the container element in autosize mode. - gfx::Size min_auto_size_; - - // The size that will be used when autosize mode is disabled. - gfx::Size normal_size_; - - // Whether the guest view is inside a plugin document. - bool is_full_page_plugin_; - - api::WebContents* api_web_contents_; - - DISALLOW_COPY_AND_ASSIGN(WebViewGuestDelegate); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_WEB_VIEW_GUEST_DELEGATE_H_ diff --git a/atom/browser/web_view_manager.cc b/atom/browser/web_view_manager.cc deleted file mode 100644 index 815e60a166ca9..0000000000000 --- a/atom/browser/web_view_manager.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/web_view_manager.h" - -#include "atom/browser/atom_browser_context.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/web_contents.h" - -namespace atom { - -WebViewManager::WebViewManager() { -} - -WebViewManager::~WebViewManager() { -} - -void WebViewManager::AddGuest(int guest_instance_id, - int element_instance_id, - content::WebContents* embedder, - content::WebContents* web_contents) { - web_contents_embedder_map_[guest_instance_id] = { web_contents, embedder }; - - // Map the element in embedder to guest. - int owner_process_id = embedder->GetRenderProcessHost()->GetID(); - ElementInstanceKey key(owner_process_id, element_instance_id); - element_instance_id_to_guest_map_[key] = guest_instance_id; -} - -void WebViewManager::RemoveGuest(int guest_instance_id) { - if (!ContainsKey(web_contents_embedder_map_, guest_instance_id)) - return; - - web_contents_embedder_map_.erase(guest_instance_id); - - // Remove the record of element in embedder too. - for (const auto& element : element_instance_id_to_guest_map_) - if (element.second == guest_instance_id) { - element_instance_id_to_guest_map_.erase(element.first); - break; - } -} - -content::WebContents* WebViewManager::GetEmbedder(int guest_instance_id) { - if (ContainsKey(web_contents_embedder_map_, guest_instance_id)) - return web_contents_embedder_map_[guest_instance_id].embedder; - else - return nullptr; -} - -content::WebContents* WebViewManager::GetGuestByInstanceID( - int owner_process_id, - int element_instance_id) { - ElementInstanceKey key(owner_process_id, element_instance_id); - if (!ContainsKey(element_instance_id_to_guest_map_, key)) - return nullptr; - - int guest_instance_id = element_instance_id_to_guest_map_[key]; - if (ContainsKey(web_contents_embedder_map_, guest_instance_id)) - return web_contents_embedder_map_[guest_instance_id].web_contents; - else - return nullptr; -} - -bool WebViewManager::ForEachGuest(content::WebContents* embedder_web_contents, - const GuestCallback& callback) { - for (auto& item : web_contents_embedder_map_) - if (item.second.embedder == embedder_web_contents && - callback.Run(item.second.web_contents)) - return true; - return false; -} - -// static -WebViewManager* WebViewManager::GetWebViewManager( - content::WebContents* web_contents) { - auto context = web_contents->GetBrowserContext(); - if (context) { - auto manager = context->GetGuestManager(); - return static_cast(manager); - } else { - return nullptr; - } -} - -} // namespace atom diff --git a/atom/browser/web_view_manager.h b/atom/browser/web_view_manager.h deleted file mode 100644 index eb2ba8ad42c87..0000000000000 --- a/atom/browser/web_view_manager.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_WEB_VIEW_MANAGER_H_ -#define ATOM_BROWSER_WEB_VIEW_MANAGER_H_ - -#include - -#include "content/public/browser/browser_plugin_guest_manager.h" - -namespace atom { - -class WebViewManager : public content::BrowserPluginGuestManager { - public: - WebViewManager(); - ~WebViewManager() override; - - void AddGuest(int guest_instance_id, - int element_instance_id, - content::WebContents* embedder, - content::WebContents* web_contents); - void RemoveGuest(int guest_instance_id); - content::WebContents* GetEmbedder(int guest_instance_id); - - static WebViewManager* GetWebViewManager(content::WebContents* web_contents); - - protected: - // content::BrowserPluginGuestManager: - content::WebContents* GetGuestByInstanceID(int owner_process_id, - int element_instance_id) override; - bool ForEachGuest(content::WebContents* embedder, - const GuestCallback& callback) override; - - private: - struct WebContentsWithEmbedder { - content::WebContents* web_contents; - content::WebContents* embedder; - }; - // guest_instance_id => (web_contents, embedder) - std::map web_contents_embedder_map_; - - struct ElementInstanceKey { - int embedder_process_id; - int element_instance_id; - - ElementInstanceKey(int embedder_process_id, int element_instance_id) - : embedder_process_id(embedder_process_id), - element_instance_id(element_instance_id) {} - - bool operator<(const ElementInstanceKey& other) const { - if (embedder_process_id != other.embedder_process_id) - return embedder_process_id < other.embedder_process_id; - return element_instance_id < other.element_instance_id; - } - - bool operator==(const ElementInstanceKey& other) const { - return (embedder_process_id == other.embedder_process_id) && - (element_instance_id == other.element_instance_id); - } - }; - // (embedder_process_id, element_instance_id) => guest_instance_id - std::map element_instance_id_to_guest_map_; - - DISALLOW_COPY_AND_ASSIGN(WebViewManager); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_WEB_VIEW_MANAGER_H_ diff --git a/atom/browser/window_list.cc b/atom/browser/window_list.cc deleted file mode 100644 index 83bf615aad259..0000000000000 --- a/atom/browser/window_list.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/browser/window_list.h" - -#include - -#include "atom/browser/native_window.h" -#include "atom/browser/window_list_observer.h" -#include "base/logging.h" - -namespace atom { - -// static -base::LazyInstance>::Leaky - WindowList::observers_ = LAZY_INSTANCE_INITIALIZER; - -// static -WindowList* WindowList::instance_ = nullptr; - -// static -WindowList* WindowList::GetInstance() { - if (!instance_) - instance_ = new WindowList; - return instance_; -} - -// static -void WindowList::AddWindow(NativeWindow* window) { - DCHECK(window); - // Push |window| on the appropriate list instance. - WindowVector& windows = GetInstance()->windows_; - windows.push_back(window); - - FOR_EACH_OBSERVER(WindowListObserver, observers_.Get(), - OnWindowAdded(window)); -} - -// static -void WindowList::RemoveWindow(NativeWindow* window) { - WindowVector& windows = GetInstance()->windows_; - windows.erase(std::remove(windows.begin(), windows.end(), window), - windows.end()); - - FOR_EACH_OBSERVER(WindowListObserver, observers_.Get(), - OnWindowRemoved(window)); - - if (windows.size() == 0) - FOR_EACH_OBSERVER(WindowListObserver, observers_.Get(), - OnWindowAllClosed()); -} - -// static -void WindowList::WindowCloseCancelled(NativeWindow* window) { - FOR_EACH_OBSERVER(WindowListObserver, observers_.Get(), - OnWindowCloseCancelled(window)); -} - -// static -void WindowList::AddObserver(WindowListObserver* observer) { - observers_.Get().AddObserver(observer); -} - -// static -void WindowList::RemoveObserver(WindowListObserver* observer) { - observers_.Get().RemoveObserver(observer); -} - -// static -void WindowList::CloseAllWindows() { - WindowVector windows = GetInstance()->windows_; - for (const auto& window : windows) - window->Close(); -} - -WindowList::WindowList() { -} - -WindowList::~WindowList() { -} - -} // namespace atom diff --git a/atom/browser/window_list.h b/atom/browser/window_list.h deleted file mode 100644 index 3dd87b2c34c29..0000000000000 --- a/atom/browser/window_list.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_WINDOW_LIST_H_ -#define ATOM_BROWSER_WINDOW_LIST_H_ - -#include - -#include "base/macros.h" -#include "base/lazy_instance.h" -#include "base/observer_list.h" - -namespace atom { - -class NativeWindow; -class WindowListObserver; - -class WindowList { - public: - typedef std::vector WindowVector; - typedef WindowVector::iterator iterator; - typedef WindowVector::const_iterator const_iterator; - - // Windows are added to the list before they have constructed windows, - // so the |window()| member function may return NULL. - const_iterator begin() const { return windows_.begin(); } - const_iterator end() const { return windows_.end(); } - - iterator begin() { return windows_.begin(); } - iterator end() { return windows_.end(); } - - bool empty() const { return windows_.empty(); } - size_t size() const { return windows_.size(); } - - NativeWindow* get(size_t index) const { return windows_[index]; } - - static WindowList* GetInstance(); - - // Adds or removes |window| from the list it is associated with. - static void AddWindow(NativeWindow* window); - static void RemoveWindow(NativeWindow* window); - - // Called by window when a close is cancelled by beforeunload handler. - static void WindowCloseCancelled(NativeWindow* window); - - // Adds and removes |observer| from the observer list. - static void AddObserver(WindowListObserver* observer); - static void RemoveObserver(WindowListObserver* observer); - - // Closes all windows. - static void CloseAllWindows(); - - private: - WindowList(); - ~WindowList(); - - // A vector of the windows in this list, in the order they were added. - WindowVector windows_; - - // A list of observers which will be notified of every window addition and - // removal across all WindowLists. - static base::LazyInstance>::Leaky - observers_; - - static WindowList* instance_; - - DISALLOW_COPY_AND_ASSIGN(WindowList); -}; - -} // namespace atom - -#endif // ATOM_BROWSER_WINDOW_LIST_H_ diff --git a/atom/browser/window_list_observer.h b/atom/browser/window_list_observer.h deleted file mode 100644 index 424efa25a2b01..0000000000000 --- a/atom/browser/window_list_observer.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_BROWSER_WINDOW_LIST_OBSERVER_H_ -#define ATOM_BROWSER_WINDOW_LIST_OBSERVER_H_ - -namespace atom { - -class NativeWindow; - -class WindowListObserver { - public: - // Called immediately after a window is added to the list. - virtual void OnWindowAdded(NativeWindow* window) {} - - // Called immediately after a window is removed from the list. - virtual void OnWindowRemoved(NativeWindow* window) {} - - // Called when a window close is cancelled by beforeunload handler. - virtual void OnWindowCloseCancelled(NativeWindow* window) {} - - // Called immediately after all windows are closed. - virtual void OnWindowAllClosed() {} - - protected: - virtual ~WindowListObserver() {} -}; - -} // namespace atom - -#endif // ATOM_BROWSER_WINDOW_LIST_OBSERVER_H_ diff --git a/atom/common/api/api_messages.h b/atom/common/api/api_messages.h deleted file mode 100644 index ab27d5a2516e6..0000000000000 --- a/atom/common/api/api_messages.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// Multiply-included file, no traditional include guard. - -#include "atom/common/draggable_region.h" -#include "base/strings/string16.h" -#include "base/values.h" -#include "content/public/common/common_param_traits.h" -#include "ipc/ipc_message_macros.h" -#include "ui/gfx/ipc/gfx_param_traits.h" - -// The message starter should be declared in ipc/ipc_message_start.h. Since -// we don't want to patch Chromium, we just pretend to be Content Shell. - -#define IPC_MESSAGE_START ShellMsgStart - -IPC_STRUCT_TRAITS_BEGIN(atom::DraggableRegion) - IPC_STRUCT_TRAITS_MEMBER(draggable) - IPC_STRUCT_TRAITS_MEMBER(bounds) -IPC_STRUCT_TRAITS_END() - -IPC_MESSAGE_ROUTED2(AtomViewHostMsg_Message, - base::string16 /* channel */, - base::ListValue /* arguments */) - -IPC_SYNC_MESSAGE_ROUTED2_1(AtomViewHostMsg_Message_Sync, - base::string16 /* channel */, - base::ListValue /* arguments */, - base::string16 /* result (in JSON) */) - -IPC_MESSAGE_ROUTED3(AtomViewMsg_Message, - bool /* send_to_all */, - base::string16 /* channel */, - base::ListValue /* arguments */) - -// Sent by the renderer when the draggable regions are updated. -IPC_MESSAGE_ROUTED1(AtomViewHostMsg_UpdateDraggableRegions, - std::vector /* regions */) - -// Update renderer process preferences. -IPC_MESSAGE_CONTROL1(AtomMsg_UpdatePreferences, base::ListValue) diff --git a/atom/common/api/atom_api_asar.cc b/atom/common/api/atom_api_asar.cc deleted file mode 100644 index 012d8f3c16709..0000000000000 --- a/atom/common/api/atom_api_asar.cc +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include - -#include - -#include "atom_natives.h" // NOLINT: This file is generated with coffee2c. -#include "atom/common/asar/archive.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/node_includes.h" -#include "native_mate/arguments.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" -#include "native_mate/wrappable.h" - -namespace { - -class Archive : public mate::Wrappable { - public: - static v8::Local Create(v8::Isolate* isolate, - const base::FilePath& path) { - std::unique_ptr archive(new asar::Archive(path)); - if (!archive->Init()) - return v8::False(isolate); - return (new Archive(isolate, std::move(archive)))->GetWrapper(); - } - - static void BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "Archive")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetProperty("path", &Archive::GetPath) - .SetMethod("getFileInfo", &Archive::GetFileInfo) - .SetMethod("stat", &Archive::Stat) - .SetMethod("readdir", &Archive::Readdir) - .SetMethod("realpath", &Archive::Realpath) - .SetMethod("copyFileOut", &Archive::CopyFileOut) - .SetMethod("getFd", &Archive::GetFD) - .SetMethod("destroy", &Archive::Destroy); - } - - protected: - Archive(v8::Isolate* isolate, std::unique_ptr archive) - : archive_(std::move(archive)) { - Init(isolate); - } - - // Returns the path of the file. - base::FilePath GetPath() { - return archive_->path(); - } - - // Reads the offset and size of file. - v8::Local GetFileInfo(v8::Isolate* isolate, - const base::FilePath& path) { - asar::Archive::FileInfo info; - if (!archive_ || !archive_->GetFileInfo(path, &info)) - return v8::False(isolate); - mate::Dictionary dict(isolate, v8::Object::New(isolate)); - dict.Set("size", info.size); - dict.Set("unpacked", info.unpacked); - dict.Set("offset", info.offset); - return dict.GetHandle(); - } - - // Returns a fake result of fs.stat(path). - v8::Local Stat(v8::Isolate* isolate, - const base::FilePath& path) { - asar::Archive::Stats stats; - if (!archive_ || !archive_->Stat(path, &stats)) - return v8::False(isolate); - mate::Dictionary dict(isolate, v8::Object::New(isolate)); - dict.Set("size", stats.size); - dict.Set("offset", stats.offset); - dict.Set("isFile", stats.is_file); - dict.Set("isDirectory", stats.is_directory); - dict.Set("isLink", stats.is_link); - return dict.GetHandle(); - } - - // Returns all files under a directory. - v8::Local Readdir(v8::Isolate* isolate, - const base::FilePath& path) { - std::vector files; - if (!archive_ || !archive_->Readdir(path, &files)) - return v8::False(isolate); - return mate::ConvertToV8(isolate, files); - } - - // Returns the path of file with symbol link resolved. - v8::Local Realpath(v8::Isolate* isolate, - const base::FilePath& path) { - base::FilePath realpath; - if (!archive_ || !archive_->Realpath(path, &realpath)) - return v8::False(isolate); - return mate::ConvertToV8(isolate, realpath); - } - - // Copy the file out into a temporary file and returns the new path. - v8::Local CopyFileOut(v8::Isolate* isolate, - const base::FilePath& path) { - base::FilePath new_path; - if (!archive_ || !archive_->CopyFileOut(path, &new_path)) - return v8::False(isolate); - return mate::ConvertToV8(isolate, new_path); - } - - // Return the file descriptor. - int GetFD() const { - if (!archive_) - return -1; - return archive_->GetFD(); - } - - // Free the resources used by archive. - void Destroy() { - archive_.reset(); - } - - private: - std::unique_ptr archive_; - - DISALLOW_COPY_AND_ASSIGN(Archive); -}; - -void InitAsarSupport(v8::Isolate* isolate, - v8::Local process, - v8::Local require) { - // Evaluate asar_init.coffee. - const char* asar_init_native = reinterpret_cast( - static_cast(node::asar_init_native)); - v8::Local asar_init = v8::Script::Compile(v8::String::NewFromUtf8( - isolate, - asar_init_native, - v8::String::kNormalString, - sizeof(node::asar_init_native) -1)); - v8::Local result = asar_init->Run(); - - // Initialize asar support. - base::Callback, - v8::Local, - std::string)> init; - if (mate::ConvertFromV8(isolate, result, &init)) { - const char* asar_native = reinterpret_cast( - static_cast(node::asar_native)); - init.Run(process, - require, - std::string(asar_native, sizeof(node::asar_native) - 1)); - } -} - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("createArchive", &Archive::Create); - dict.SetMethod("initAsarSupport", &InitAsarSupport); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_asar, Initialize) diff --git a/atom/common/api/atom_api_clipboard.cc b/atom/common/api/atom_api_clipboard.cc deleted file mode 100644 index 01e670be92615..0000000000000 --- a/atom/common/api/atom_api_clipboard.cc +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include -#include - -#include "atom/common/native_mate_converters/image_converter.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "base/strings/utf_string_conversions.h" -#include "native_mate/arguments.h" -#include "native_mate/dictionary.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/clipboard/clipboard.h" -#include "ui/base/clipboard/scoped_clipboard_writer.h" -#include "ui/gfx/image/image.h" - -#include "atom/common/node_includes.h" - -namespace { - -ui::ClipboardType GetClipboardType(mate::Arguments* args) { - std::string type; - if (args->GetNext(&type) && type == "selection") - return ui::CLIPBOARD_TYPE_SELECTION; - else - return ui::CLIPBOARD_TYPE_COPY_PASTE; -} - -std::vector AvailableFormats(mate::Arguments* args) { - std::vector format_types; - bool ignore; - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - clipboard->ReadAvailableTypes(GetClipboardType(args), &format_types, &ignore); - return format_types; -} - -bool Has(const std::string& format_string, mate::Arguments* args) { - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string)); - return clipboard->IsFormatAvailable(format, GetClipboardType(args)); -} - -std::string Read(const std::string& format_string, - mate::Arguments* args) { - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - ui::Clipboard::FormatType format(ui::Clipboard::GetFormatType(format_string)); - - std::string data; - clipboard->ReadData(format, &data); - return data; -} - -void Write(const mate::Dictionary& data, - mate::Arguments* args) { - ui::ScopedClipboardWriter writer(GetClipboardType(args)); - base::string16 text, html, bookmark; - gfx::Image image; - - if (data.Get("text", &text)) { - writer.WriteText(text); - - if (data.Get("bookmark", &bookmark)) - writer.WriteBookmark(bookmark, base::UTF16ToUTF8(text)); - } - - if (data.Get("rtf", &text)) { - std::string rtf = base::UTF16ToUTF8(text); - writer.WriteRTF(rtf); - } - - if (data.Get("html", &html)) - writer.WriteHTML(html, std::string()); - - if (data.Get("image", &image)) - writer.WriteImage(image.AsBitmap()); -} - -base::string16 ReadText(mate::Arguments* args) { - base::string16 data; - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - auto type = GetClipboardType(args); - if (clipboard->IsFormatAvailable( - ui::Clipboard::GetPlainTextWFormatType(), type)) { - clipboard->ReadText(type, &data); - } else if (clipboard->IsFormatAvailable( - ui::Clipboard::GetPlainTextFormatType(), type)) { - std::string result; - clipboard->ReadAsciiText(type, &result); - data = base::ASCIIToUTF16(result); - } - return data; -} - -void WriteText(const base::string16& text, mate::Arguments* args) { - ui::ScopedClipboardWriter writer(GetClipboardType(args)); - writer.WriteText(text); -} - -base::string16 ReadRtf(mate::Arguments* args) { - std::string data; - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - clipboard->ReadRTF(GetClipboardType(args), &data); - return base::UTF8ToUTF16(data); -} - -void WriteRtf(const std::string& text, mate::Arguments* args) { - ui::ScopedClipboardWriter writer(GetClipboardType(args)); - writer.WriteRTF(text); -} - -base::string16 ReadHtml(mate::Arguments* args) { - base::string16 data; - base::string16 html; - std::string url; - uint32_t start; - uint32_t end; - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - clipboard->ReadHTML(GetClipboardType(args), &html, &url, &start, &end); - data = html.substr(start, end - start); - return data; -} - -void WriteHtml(const base::string16& html, mate::Arguments* args) { - ui::ScopedClipboardWriter writer(GetClipboardType(args)); - writer.WriteHTML(html, std::string()); -} - -v8::Local ReadBookmark(mate::Arguments* args) { - base::string16 title; - std::string url; - mate::Dictionary dict = mate::Dictionary::CreateEmpty(args->isolate()); - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - clipboard->ReadBookmark(&title, &url); - dict.Set("title", title); - dict.Set("url", url); - return dict.GetHandle(); -} - -void WriteBookmark(const base::string16& title, const std::string& url, - mate::Arguments* args) { - ui::ScopedClipboardWriter writer(GetClipboardType(args)); - writer.WriteBookmark(title, url); -} - -gfx::Image ReadImage(mate::Arguments* args) { - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - SkBitmap bitmap = clipboard->ReadImage(GetClipboardType(args)); - return gfx::Image::CreateFrom1xBitmap(bitmap); -} - -void WriteImage(const gfx::Image& image, mate::Arguments* args) { - ui::ScopedClipboardWriter writer(GetClipboardType(args)); - writer.WriteImage(image.AsBitmap()); -} - -void Clear(mate::Arguments* args) { - ui::Clipboard::GetForCurrentThread()->Clear(GetClipboardType(args)); -} - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("availableFormats", &AvailableFormats); - dict.SetMethod("has", &Has); - dict.SetMethod("read", &Read); - dict.SetMethod("write", &Write); - dict.SetMethod("readText", &ReadText); - dict.SetMethod("writeText", &WriteText); - dict.SetMethod("readRTF", &ReadRtf); - dict.SetMethod("writeRTF", &WriteRtf); - dict.SetMethod("readHTML", &ReadHtml); - dict.SetMethod("writeHTML", &WriteHtml); - dict.SetMethod("readBookmark", &ReadBookmark); - dict.SetMethod("writeBookmark", &WriteBookmark); - dict.SetMethod("readImage", &ReadImage); - dict.SetMethod("writeImage", &WriteImage); - dict.SetMethod("clear", &Clear); - - // TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings - dict.SetMethod("readRtf", &ReadRtf); - dict.SetMethod("writeRtf", &WriteRtf); - dict.SetMethod("readHtml", &ReadHtml); - dict.SetMethod("writeHtml", &WriteHtml); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_clipboard, Initialize) diff --git a/atom/common/api/atom_api_crash_reporter.cc b/atom/common/api/atom_api_crash_reporter.cc deleted file mode 100644 index 184a70c72c14b..0000000000000 --- a/atom/common/api/atom_api_crash_reporter.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include -#include - -#include "atom/common/crash_reporter/crash_reporter.h" -#include "base/bind.h" -#include "native_mate/dictionary.h" - -#include "atom/common/node_includes.h" - -using crash_reporter::CrashReporter; - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const CrashReporter::UploadReportResult& reports) { - mate::Dictionary dict(isolate, v8::Object::New(isolate)); - dict.Set("date", v8::Date::New(isolate, reports.first*1000.0)); - dict.Set("id", reports.second); - return dict.GetHandle(); - } -}; - -} // namespace mate - -namespace { - - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - auto report = base::Unretained(CrashReporter::GetInstance()); - dict.SetMethod("start", - base::Bind(&CrashReporter::Start, report)); - dict.SetMethod("_getUploadedReports", - base::Bind(&CrashReporter::GetUploadedReports, report)); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_crash_reporter, Initialize) diff --git a/atom/common/api/atom_api_key_weak_map.h b/atom/common/api/atom_api_key_weak_map.h deleted file mode 100644 index 743b719e40e3a..0000000000000 --- a/atom/common/api/atom_api_key_weak_map.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_API_ATOM_API_KEY_WEAK_MAP_H_ -#define ATOM_COMMON_API_ATOM_API_KEY_WEAK_MAP_H_ - -#include "atom/common/key_weak_map.h" -#include "native_mate/object_template_builder.h" -#include "native_mate/handle.h" -#include "native_mate/wrappable.h" - -namespace atom { - -namespace api { - -template -class KeyWeakMap : public mate::Wrappable> { - public: - static mate::Handle> Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new KeyWeakMap(isolate)); - } - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "KeyWeakMap")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("set", &KeyWeakMap::Set) - .SetMethod("get", &KeyWeakMap::Get) - .SetMethod("has", &KeyWeakMap::Has) - .SetMethod("remove", &KeyWeakMap::Remove); - } - - protected: - explicit KeyWeakMap(v8::Isolate* isolate) { - mate::Wrappable>::Init(isolate); - } - ~KeyWeakMap() override {} - - private: - // API for KeyWeakMap. - void Set(v8::Isolate* isolate, const K& key, v8::Local object) { - key_weak_map_.Set(isolate, key, object); - } - - v8::Local Get(v8::Isolate* isolate, const K& key) { - return key_weak_map_.Get(isolate, key).ToLocalChecked(); - } - - bool Has(const K& key) { - return key_weak_map_.Has(key); - } - - void Remove(const K& key) { - key_weak_map_.Remove(key); - } - - atom::KeyWeakMap key_weak_map_; - - DISALLOW_COPY_AND_ASSIGN(KeyWeakMap); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_COMMON_API_ATOM_API_KEY_WEAK_MAP_H_ diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc deleted file mode 100644 index b08c9a95d3a74..0000000000000 --- a/atom/common/api/atom_api_native_image.cc +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/api/atom_api_native_image.h" - -#include -#include - -#include "atom/common/asar/asar_util.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/native_mate_converters/gfx_converter.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/node_includes.h" -#include "base/base64.h" -#include "base/files/file_util.h" -#include "base/strings/string_util.h" -#include "base/strings/pattern.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" -#include "net/base/data_url.h" -#include "ui/base/layout.h" -#include "ui/gfx/codec/jpeg_codec.h" -#include "ui/gfx/codec/png_codec.h" -#include "ui/gfx/geometry/size.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/gfx/image/image_util.h" -#include "third_party/skia/include/core/SkPixelRef.h" - -#if defined(OS_WIN) -#include "atom/common/asar/archive.h" -#include "base/win/scoped_gdi_object.h" -#include "ui/gfx/icon_util.h" -#endif - -namespace atom { - -namespace api { - -namespace { - -struct ScaleFactorPair { - const char* name; - float scale; -}; - -ScaleFactorPair kScaleFactorPairs[] = { - // The "@2x" is put as first one to make scale matching faster. - { "@2x" , 2.0f }, - { "@3x" , 3.0f }, - { "@1x" , 1.0f }, - { "@4x" , 4.0f }, - { "@5x" , 5.0f }, - { "@1.25x" , 1.25f }, - { "@1.33x" , 1.33f }, - { "@1.4x" , 1.4f }, - { "@1.5x" , 1.5f }, - { "@1.8x" , 1.8f }, - { "@2.5x" , 2.5f }, -}; - -float GetScaleFactorFromPath(const base::FilePath& path) { - std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); - - // We don't try to convert string to float here because it is very very - // expensive. - for (const auto& kScaleFactorPair : kScaleFactorPairs) { - if (base::EndsWith(filename, kScaleFactorPair.name, - base::CompareCase::INSENSITIVE_ASCII)) - return kScaleFactorPair.scale; - } - - return 1.0f; -} - -bool AddImageSkiaRep(gfx::ImageSkia* image, - const unsigned char* data, - size_t size, - double scale_factor) { - std::unique_ptr decoded(new SkBitmap()); - - // Try PNG first. - if (!gfx::PNGCodec::Decode(data, size, decoded.get())) - // Try JPEG. - decoded = gfx::JPEGCodec::Decode(data, size); - - if (!decoded) - return false; - - image->AddRepresentation(gfx::ImageSkiaRep(*decoded, scale_factor)); - return true; -} - -bool AddImageSkiaRep(gfx::ImageSkia* image, - const base::FilePath& path, - double scale_factor) { - std::string file_contents; - if (!asar::ReadFileToString(path, &file_contents)) - return false; - - const unsigned char* data = - reinterpret_cast(file_contents.data()); - size_t size = file_contents.size(); - return AddImageSkiaRep(image, data, size, scale_factor); -} - -bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image, - const base::FilePath& path) { - bool succeed = false; - std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); - if (base::MatchPattern(filename, "*@*x")) - // Don't search for other representations if the DPI has been specified. - return AddImageSkiaRep(image, path, GetScaleFactorFromPath(path)); - else - succeed |= AddImageSkiaRep(image, path, 1.0f); - - for (const ScaleFactorPair& pair : kScaleFactorPairs) - succeed |= AddImageSkiaRep(image, - path.InsertBeforeExtensionASCII(pair.name), - pair.scale); - return succeed; -} - -base::FilePath NormalizePath(const base::FilePath& path) { - if (!path.ReferencesParent()) { - return path; - } - - base::FilePath absolute_path = MakeAbsoluteFilePath(path); - // MakeAbsoluteFilePath returns an empty path on failures so use original path - if (absolute_path.empty()) { - return path; - } else { - return absolute_path; - } -} - -#if defined(OS_MACOSX) -bool IsTemplateFilename(const base::FilePath& path) { - return (base::MatchPattern(path.value(), "*Template.*") || - base::MatchPattern(path.value(), "*Template@*x.*")); -} -#endif - -#if defined(OS_WIN) -base::win::ScopedHICON ReadICOFromPath(int size, const base::FilePath& path) { - // If file is in asar archive, we extract it to a temp file so LoadImage can - // load it. - base::FilePath asar_path, relative_path; - base::FilePath image_path(path); - if (asar::GetAsarArchivePath(image_path, &asar_path, &relative_path)) { - std::shared_ptr archive = - asar::GetOrCreateAsarArchive(asar_path); - if (archive) - archive->CopyFileOut(relative_path, &image_path); - } - - // Load the icon from file. - return base::win::ScopedHICON(static_cast( - LoadImage(NULL, image_path.value().c_str(), IMAGE_ICON, size, size, - LR_LOADFROMFILE))); -} - -bool ReadImageSkiaFromICO(gfx::ImageSkia* image, HICON icon) { - // Convert the icon from the Windows specific HICON to gfx::ImageSkia. - std::unique_ptr bitmap(IconUtil::CreateSkBitmapFromHICON(icon)); - if (!bitmap) - return false; - - image->AddRepresentation(gfx::ImageSkiaRep(*bitmap, 1.0f)); - return true; -} -#endif - -void Noop(char*, void*) { -} - -} // namespace - -NativeImage::NativeImage(v8::Isolate* isolate, const gfx::Image& image) - : image_(image) { - Init(isolate); -} - -#if defined(OS_WIN) -NativeImage::NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path) - : hicon_path_(hicon_path) { - // Use the 256x256 icon as fallback icon. - gfx::ImageSkia image_skia; - ReadImageSkiaFromICO(&image_skia, GetHICON(256)); - image_ = gfx::Image(image_skia); - Init(isolate); -} -#endif - -NativeImage::~NativeImage() {} - -#if defined(OS_WIN) -HICON NativeImage::GetHICON(int size) { - auto iter = hicons_.find(size); - if (iter != hicons_.end()) - return iter->second.get(); - - // First try loading the icon with specified size. - if (!hicon_path_.empty()) { - hicons_[size] = std::move(ReadICOFromPath(size, hicon_path_)); - return hicons_[size].get(); - } - - // Then convert the image to ICO. - if (image_.IsEmpty()) - return NULL; - hicons_[size] = std::move( - IconUtil::CreateHICONFromSkBitmap(image_.AsBitmap())); - return hicons_[size].get(); -} -#endif - -v8::Local NativeImage::ToPNG(v8::Isolate* isolate) { - scoped_refptr png = image_.As1xPNGBytes(); - return node::Buffer::Copy(isolate, - reinterpret_cast(png->front()), - static_cast(png->size())).ToLocalChecked(); -} - -v8::Local NativeImage::ToBitmap(v8::Isolate* isolate) { - const SkBitmap* bitmap = image_.ToSkBitmap(); - SkPixelRef* ref = bitmap->pixelRef(); - return node::Buffer::Copy(isolate, - reinterpret_cast(ref->pixels()), - bitmap->getSafeSize()).ToLocalChecked(); -} - -v8::Local NativeImage::ToJPEG(v8::Isolate* isolate, int quality) { - std::vector output; - gfx::JPEG1xEncodedDataFromImage(image_, quality, &output); - return node::Buffer::Copy( - isolate, - reinterpret_cast(&output.front()), - static_cast(output.size())).ToLocalChecked(); -} - -std::string NativeImage::ToDataURL() { - scoped_refptr png = image_.As1xPNGBytes(); - std::string data_url; - data_url.insert(data_url.end(), png->front(), png->front() + png->size()); - base::Base64Encode(data_url, &data_url); - data_url.insert(0, "data:image/png;base64,"); - return data_url; -} - -v8::Local NativeImage::GetBitmap(v8::Isolate* isolate) { - const SkBitmap* bitmap = image_.ToSkBitmap(); - SkPixelRef* ref = bitmap->pixelRef(); - return node::Buffer::New(isolate, - reinterpret_cast(ref->pixels()), - bitmap->getSafeSize(), - &Noop, - nullptr).ToLocalChecked(); -} - -v8::Local NativeImage::GetNativeHandle(v8::Isolate* isolate, - mate::Arguments* args) { -#if defined(OS_MACOSX) - NSImage* ptr = image_.AsNSImage(); - return node::Buffer::Copy( - isolate, - reinterpret_cast(ptr), - sizeof(void*)).ToLocalChecked(); -#else - args->ThrowError("Not implemented"); - return v8::Undefined(isolate); -#endif -} - -bool NativeImage::IsEmpty() { - return image_.IsEmpty(); -} - -gfx::Size NativeImage::GetSize() { - return image_.Size(); -} - -#if !defined(OS_MACOSX) -void NativeImage::SetTemplateImage(bool setAsTemplate) { -} - -bool NativeImage::IsTemplateImage() { - return false; -} -#endif - -// static -mate::Handle NativeImage::CreateEmpty(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new NativeImage(isolate, gfx::Image())); -} - -// static -mate::Handle NativeImage::Create( - v8::Isolate* isolate, const gfx::Image& image) { - return mate::CreateHandle(isolate, new NativeImage(isolate, image)); -} - -// static -mate::Handle NativeImage::CreateFromPNG( - v8::Isolate* isolate, const char* buffer, size_t length) { - gfx::Image image = gfx::Image::CreateFrom1xPNGBytes( - reinterpret_cast(buffer), length); - return Create(isolate, image); -} - -// static -mate::Handle NativeImage::CreateFromJPEG( - v8::Isolate* isolate, const char* buffer, size_t length) { - gfx::Image image = gfx::ImageFrom1xJPEGEncodedData( - reinterpret_cast(buffer), length); - return Create(isolate, image); -} - -// static -mate::Handle NativeImage::CreateFromPath( - v8::Isolate* isolate, const base::FilePath& path) { - base::FilePath image_path = NormalizePath(path); -#if defined(OS_WIN) - if (image_path.MatchesExtension(FILE_PATH_LITERAL(".ico"))) { - return mate::CreateHandle(isolate, - new NativeImage(isolate, image_path)); - } -#endif - gfx::ImageSkia image_skia; - PopulateImageSkiaRepsFromPath(&image_skia, image_path); - gfx::Image image(image_skia); - mate::Handle handle = Create(isolate, image); -#if defined(OS_MACOSX) - if (IsTemplateFilename(image_path)) - handle->SetTemplateImage(true); -#endif - return handle; -} - -// static -mate::Handle NativeImage::CreateFromBuffer( - mate::Arguments* args, v8::Local buffer) { - double scale_factor = 1.; - args->GetNext(&scale_factor); - - gfx::ImageSkia image_skia; - AddImageSkiaRep(&image_skia, - reinterpret_cast(node::Buffer::Data(buffer)), - node::Buffer::Length(buffer), - scale_factor); - return Create(args->isolate(), gfx::Image(image_skia)); -} - -// static -mate::Handle NativeImage::CreateFromDataURL( - v8::Isolate* isolate, const GURL& url) { - std::string mime_type, charset, data; - if (net::DataURL::Parse(url, &mime_type, &charset, &data)) { - if (mime_type == "image/png") - return CreateFromPNG(isolate, data.c_str(), data.size()); - else if (mime_type == "image/jpeg") - return CreateFromJPEG(isolate, data.c_str(), data.size()); - } - - return CreateEmpty(isolate); -} - -// static -void NativeImage::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "NativeImage")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("toPNG", &NativeImage::ToPNG) - .SetMethod("toJPEG", &NativeImage::ToJPEG) - .SetMethod("toBitmap", &NativeImage::ToBitmap) - .SetMethod("getBitmap", &NativeImage::GetBitmap) - .SetMethod("getNativeHandle", &NativeImage::GetNativeHandle) - .SetMethod("toDataURL", &NativeImage::ToDataURL) - .SetMethod("isEmpty", &NativeImage::IsEmpty) - .SetMethod("getSize", &NativeImage::GetSize) - .SetMethod("setTemplateImage", &NativeImage::SetTemplateImage) - .SetMethod("isTemplateImage", &NativeImage::IsTemplateImage) - // TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings - .SetMethod("toPng", &NativeImage::ToPNG) - .SetMethod("toJpeg", &NativeImage::ToJPEG); -} - -} // namespace api - -} // namespace atom - -namespace mate { - -v8::Local Converter>::ToV8( - v8::Isolate* isolate, - const mate::Handle& val) { - return val.ToV8(); -} - -bool Converter>::FromV8( - v8::Isolate* isolate, v8::Local val, - mate::Handle* out) { - // Try converting from file path. - base::FilePath path; - if (ConvertFromV8(isolate, val, &path)) { - *out = atom::api::NativeImage::CreateFromPath(isolate, path); - // Should throw when failed to initialize from path. - return !(*out)->image().IsEmpty(); - } - - WrappableBase* wrapper = static_cast(internal::FromV8Impl( - isolate, val)); - if (!wrapper) - return false; - - *out = CreateHandle(isolate, static_cast(wrapper)); - return true; -} - -} // namespace mate - -namespace { - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("createEmpty", &atom::api::NativeImage::CreateEmpty); - dict.SetMethod("createFromPath", &atom::api::NativeImage::CreateFromPath); - dict.SetMethod("createFromBuffer", &atom::api::NativeImage::CreateFromBuffer); - dict.SetMethod("createFromDataURL", - &atom::api::NativeImage::CreateFromDataURL); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_native_image, Initialize) diff --git a/atom/common/api/atom_api_native_image.h b/atom/common/api/atom_api_native_image.h deleted file mode 100644 index 743a3c599b7e0..0000000000000 --- a/atom/common/api/atom_api_native_image.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ -#define ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ - -#include -#include - -#include "native_mate/handle.h" -#include "native_mate/wrappable.h" -#include "ui/gfx/image/image.h" - -#if defined(OS_WIN) -#include "base/files/file_path.h" -#include "base/win/scoped_gdi_object.h" -#endif - -class GURL; - -namespace base { -class FilePath; -} - -namespace gfx { -class Size; -} - -namespace mate { -class Arguments; -} - -namespace atom { - -namespace api { - -class NativeImage : public mate::Wrappable { - public: - static mate::Handle CreateEmpty(v8::Isolate* isolate); - static mate::Handle Create( - v8::Isolate* isolate, const gfx::Image& image); - static mate::Handle CreateFromPNG( - v8::Isolate* isolate, const char* buffer, size_t length); - static mate::Handle CreateFromJPEG( - v8::Isolate* isolate, const char* buffer, size_t length); - static mate::Handle CreateFromPath( - v8::Isolate* isolate, const base::FilePath& path); - static mate::Handle CreateFromBuffer( - mate::Arguments* args, v8::Local buffer); - static mate::Handle CreateFromDataURL( - v8::Isolate* isolate, const GURL& url); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - -#if defined(OS_WIN) - HICON GetHICON(int size); -#endif - - const gfx::Image& image() const { return image_; } - - protected: - NativeImage(v8::Isolate* isolate, const gfx::Image& image); -#if defined(OS_WIN) - NativeImage(v8::Isolate* isolate, const base::FilePath& hicon_path); -#endif - ~NativeImage() override; - - private: - v8::Local ToPNG(v8::Isolate* isolate); - v8::Local ToJPEG(v8::Isolate* isolate, int quality); - v8::Local ToBitmap(v8::Isolate* isolate); - v8::Local GetBitmap(v8::Isolate* isolate); - v8::Local GetNativeHandle( - v8::Isolate* isolate, - mate::Arguments* args); - std::string ToDataURL(); - bool IsEmpty(); - gfx::Size GetSize(); - - // Mark the image as template image. - void SetTemplateImage(bool setAsTemplate); - // Determine if the image is a template image. - bool IsTemplateImage(); - -#if defined(OS_WIN) - base::FilePath hicon_path_; - std::map hicons_; -#endif - - gfx::Image image_; - - DISALLOW_COPY_AND_ASSIGN(NativeImage); -}; - -} // namespace api - -} // namespace atom - -namespace mate { - -// A custom converter that allows converting path to NativeImage. -template<> -struct Converter> { - static v8::Local ToV8( - v8::Isolate* isolate, - const mate::Handle& val); - static bool FromV8(v8::Isolate* isolate, v8::Local val, - mate::Handle* out); -}; - -} // namespace mate - - -#endif // ATOM_COMMON_API_ATOM_API_NATIVE_IMAGE_H_ diff --git a/atom/common/api/atom_api_native_image_mac.mm b/atom/common/api/atom_api_native_image_mac.mm deleted file mode 100644 index ad72d4b149246..0000000000000 --- a/atom/common/api/atom_api_native_image_mac.mm +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/api/atom_api_native_image.h" - -#import - -namespace atom { - -namespace api { - -void NativeImage::SetTemplateImage(bool setAsTemplate) { - [image_.AsNSImage() setTemplate:setAsTemplate]; -} - -bool NativeImage::IsTemplateImage() { - return [image_.AsNSImage() isTemplate]; -} - -} // namespace api - -} // namespace atom diff --git a/atom/common/api/atom_api_shell.cc b/atom/common/api/atom_api_shell.cc deleted file mode 100644 index 2d9d6e02697a6..0000000000000 --- a/atom/common/api/atom_api_shell.cc +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include - -#include "atom/common/platform_util.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "atom/common/node_includes.h" -#include "native_mate/dictionary.h" - -#if defined(OS_WIN) -#include "base/win/scoped_com_initializer.h" -#include "base/win/shortcut.h" - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Handle val, - base::win::ShortcutOperation* out) { - std::string operation; - if (!ConvertFromV8(isolate, val, & operation)) - return false; - if (operation.empty() || operation == "create") - *out = base::win::SHORTCUT_CREATE_ALWAYS; - else if (operation == "update") - *out = base::win::SHORTCUT_UPDATE_EXISTING; - else if (operation == "replace") - *out = base::win::SHORTCUT_REPLACE_EXISTING; - else - return false; - return true; - } -}; - -} // namespace mate -#endif - -namespace { - -bool OpenExternal( -#if defined(OS_WIN) - const base::string16& url, -#else - const GURL& url, -#endif - mate::Arguments* args) { - bool activate = true; - if (args->Length() == 2) { - mate::Dictionary options; - if (args->GetNext(&options)) { - options.Get("activate", &activate); - } - } - return platform_util::OpenExternal(url, activate); -} - -#if defined(OS_WIN) -bool WriteShortcutLink(const base::FilePath& shortcut_path, - mate::Arguments* args) { - base::win::ShortcutOperation operation = base::win::SHORTCUT_CREATE_ALWAYS; - args->GetNext(&operation); - mate::Dictionary options = mate::Dictionary::CreateEmpty(args->isolate()); - if (!args->GetNext(&options)) { - args->ThrowError(); - return false; - } - - base::win::ShortcutProperties properties; - base::FilePath path; - base::string16 str; - int index; - if (options.Get("target", &path)) - properties.set_target(path); - if (options.Get("cwd", &path)) - properties.set_working_dir(path); - if (options.Get("args", &str)) - properties.set_arguments(str); - if (options.Get("description", &str)) - properties.set_description(str); - if (options.Get("icon", &path) && options.Get("iconIndex", &index)) - properties.set_icon(path, index); - if (options.Get("appUserModelId", &str)) - properties.set_app_id(str); - - base::win::ScopedCOMInitializer com_initializer; - return base::win::CreateOrUpdateShortcutLink( - shortcut_path, properties, operation); -} - -v8::Local ReadShortcutLink(mate::Arguments* args, - const base::FilePath& path) { - using base::win::ShortcutProperties; - mate::Dictionary options = mate::Dictionary::CreateEmpty(args->isolate()); - base::win::ScopedCOMInitializer com_initializer; - base::win::ShortcutProperties properties; - if (!base::win::ResolveShortcutProperties( - path, ShortcutProperties::PROPERTIES_ALL, &properties)) { - args->ThrowError("Failed to read shortcut link"); - return v8::Null(args->isolate()); - } - options.Set("target", properties.target); - options.Set("cwd", properties.working_dir); - options.Set("args", properties.arguments); - options.Set("description", properties.description); - options.Set("icon", properties.icon); - options.Set("iconIndex", properties.icon_index); - options.Set("appUserModelId", properties.app_id); - return options.GetHandle(); -} -#endif - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("showItemInFolder", &platform_util::ShowItemInFolder); - dict.SetMethod("openItem", &platform_util::OpenItem); - dict.SetMethod("openExternal", &OpenExternal); - dict.SetMethod("moveItemToTrash", &platform_util::MoveItemToTrash); - dict.SetMethod("beep", &platform_util::Beep); -#if defined(OS_WIN) - dict.SetMethod("writeShortcutLink", &WriteShortcutLink); - dict.SetMethod("readShortcutLink", &ReadShortcutLink); -#endif -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_shell, Initialize) diff --git a/atom/common/api/atom_api_v8_util.cc b/atom/common/api/atom_api_v8_util.cc deleted file mode 100644 index 7b7655c6cd2e0..0000000000000 --- a/atom/common/api/atom_api_v8_util.cc +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include -#include - -#include "atom/common/api/atom_api_key_weak_map.h" -#include "atom/common/api/remote_callback_freer.h" -#include "atom/common/api/remote_object_freer.h" -#include "atom/common/native_mate_converters/content_converter.h" -#include "atom/common/node_includes.h" -#include "base/hash.h" -#include "native_mate/dictionary.h" -#include "v8/include/v8-profiler.h" - -namespace std { - -// The hash function used by DoubleIDWeakMap. -template -struct hash> { - std::size_t operator()(std::pair value) const { - return base::HashInts(value.first, value.second); - } -}; - -} // namespace std - -namespace mate { - -template -struct Converter> { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - std::pair* out) { - if (!val->IsArray()) - return false; - - v8::Local array(v8::Local::Cast(val)); - if (array->Length() != 2) - return false; - return Converter::FromV8(isolate, array->Get(0), &out->first) && - Converter::FromV8(isolate, array->Get(1), &out->second); - } -}; - -} // namespace mate - -namespace { - -v8::Local GetHiddenValue(v8::Isolate* isolate, - v8::Local object, - v8::Local key) { - v8::Local context = isolate->GetCurrentContext(); - v8::Local privateKey = v8::Private::ForApi(isolate, key); - v8::Local value; - v8::Maybe result = object->HasPrivate(context, privateKey); - if (!(result.IsJust() && result.FromJust())) - return v8::Local(); - if (object->GetPrivate(context, privateKey).ToLocal(&value)) - return value; - return v8::Local(); -} - -void SetHiddenValue(v8::Isolate* isolate, - v8::Local object, - v8::Local key, - v8::Local value) { - if (value.IsEmpty()) - return; - v8::Local context = isolate->GetCurrentContext(); - v8::Local privateKey = v8::Private::ForApi(isolate, key); - object->SetPrivate(context, privateKey, value); -} - -void DeleteHiddenValue(v8::Isolate* isolate, - v8::Local object, - v8::Local key) { - v8::Local context = isolate->GetCurrentContext(); - v8::Local privateKey = v8::Private::ForApi(isolate, key); - // Actually deleting the value would make force the object into - // dictionary mode which is unnecessarily slow. Instead, we replace - // the hidden value with "undefined". - object->SetPrivate(context, privateKey, v8::Undefined(isolate)); -} - -int32_t GetObjectHash(v8::Local object) { - return object->GetIdentityHash(); -} - -void TakeHeapSnapshot(v8::Isolate* isolate) { - isolate->GetHeapProfiler()->TakeHeapSnapshot(); -} - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("getHiddenValue", &GetHiddenValue); - dict.SetMethod("setHiddenValue", &SetHiddenValue); - dict.SetMethod("deleteHiddenValue", &DeleteHiddenValue); - dict.SetMethod("getObjectHash", &GetObjectHash); - dict.SetMethod("takeHeapSnapshot", &TakeHeapSnapshot); - dict.SetMethod("setRemoteCallbackFreer", &atom::RemoteCallbackFreer::BindTo); - dict.SetMethod("setRemoteObjectFreer", &atom::RemoteObjectFreer::BindTo); - dict.SetMethod("createIDWeakMap", &atom::api::KeyWeakMap::Create); - dict.SetMethod("createDoubleIDWeakMap", - &atom::api::KeyWeakMap>::Create); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_common_v8_util, Initialize) diff --git a/atom/common/api/atom_bindings.cc b/atom/common/api/atom_bindings.cc deleted file mode 100644 index b5a51ad507e40..0000000000000 --- a/atom/common/api/atom_bindings.cc +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/api/atom_bindings.h" - -#include -#include -#include - -#include "atom/common/atom_version.h" -#include "atom/common/chrome_version.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "base/logging.h" -#include "base/process/process_metrics.h" -#include "native_mate/dictionary.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace { - -// Dummy class type that used for crashing the program. -struct DummyClass { bool crash; }; - -void Crash() { - static_cast(nullptr)->crash = true; -} - -void Hang() { - for (;;) - base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); -} - -v8::Local GetProcessMemoryInfo(v8::Isolate* isolate) { - std::unique_ptr metrics( - base::ProcessMetrics::CreateCurrentProcessMetrics()); - - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("workingSetSize", - static_cast(metrics->GetWorkingSetSize() >> 10)); - dict.Set("peakWorkingSetSize", - static_cast(metrics->GetPeakWorkingSetSize() >> 10)); - - size_t private_bytes, shared_bytes; - if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) { - dict.Set("privateBytes", static_cast(private_bytes >> 10)); - dict.Set("sharedBytes", static_cast(shared_bytes >> 10)); - } - - return dict.GetHandle(); -} - -v8::Local GetSystemMemoryInfo(v8::Isolate* isolate, - mate::Arguments* args) { - base::SystemMemoryInfoKB mem_info; - if (!base::GetSystemMemoryInfo(&mem_info)) { - args->ThrowError("Unable to retrieve system memory information"); - return v8::Undefined(isolate); - } - - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("total", mem_info.total); - dict.Set("free", mem_info.free); - - // NB: These return bogus values on macOS -#if !defined(OS_MACOSX) - dict.Set("swapTotal", mem_info.swap_total); - dict.Set("swapFree", mem_info.swap_free); -#endif - - return dict.GetHandle(); -} - -// Called when there is a fatal error in V8, we just crash the process here so -// we can get the stack trace. -void FatalErrorCallback(const char* location, const char* message) { - LOG(ERROR) << "Fatal error in V8: " << location << " " << message; - Crash(); -} - -void Log(const base::string16& message) { - std::cout << message << std::flush; -} - -} // namespace - - -AtomBindings::AtomBindings() { - uv_async_init(uv_default_loop(), &call_next_tick_async_, OnCallNextTick); - call_next_tick_async_.data = this; -} - -AtomBindings::~AtomBindings() { -} - -void AtomBindings::BindTo(v8::Isolate* isolate, - v8::Local process) { - v8::V8::SetFatalErrorHandler(FatalErrorCallback); - - mate::Dictionary dict(isolate, process); - dict.SetMethod("crash", &Crash); - dict.SetMethod("hang", &Hang); - dict.SetMethod("log", &Log); - dict.SetMethod("getProcessMemoryInfo", &GetProcessMemoryInfo); - dict.SetMethod("getSystemMemoryInfo", &GetSystemMemoryInfo); -#if defined(OS_POSIX) - dict.SetMethod("setFdLimit", &base::SetFdLimit); -#endif - dict.SetMethod("activateUvLoop", - base::Bind(&AtomBindings::ActivateUVLoop, base::Unretained(this))); - -#if defined(MAS_BUILD) - dict.Set("mas", true); -#endif - - mate::Dictionary versions; - if (dict.Get("versions", &versions)) { - versions.Set(ATOM_PROJECT_NAME, ATOM_VERSION_STRING); - versions.Set("atom-shell", ATOM_VERSION_STRING); // For compatibility. - versions.Set("chrome", CHROME_VERSION_STRING); - } -} - -void AtomBindings::ActivateUVLoop(v8::Isolate* isolate) { - node::Environment* env = node::Environment::GetCurrent(isolate); - if (std::find(pending_next_ticks_.begin(), pending_next_ticks_.end(), env) != - pending_next_ticks_.end()) - return; - - pending_next_ticks_.push_back(env); - uv_async_send(&call_next_tick_async_); -} - -// static -void AtomBindings::OnCallNextTick(uv_async_t* handle) { - AtomBindings* self = static_cast(handle->data); - for (std::list::const_iterator it = - self->pending_next_ticks_.begin(); - it != self->pending_next_ticks_.end(); ++it) { - node::Environment* env = *it; - // KickNextTick, copied from node.cc: - node::Environment::AsyncCallbackScope callback_scope(env); - if (callback_scope.in_makecallback()) - continue; - node::Environment::TickInfo* tick_info = env->tick_info(); - if (tick_info->length() == 0) - env->isolate()->RunMicrotasks(); - v8::Local process = env->process_object(); - if (tick_info->length() == 0) - tick_info->set_index(0); - env->tick_callback_function()->Call(process, 0, nullptr).IsEmpty(); - } - - self->pending_next_ticks_.clear(); -} - -} // namespace atom diff --git a/atom/common/api/atom_bindings.h b/atom/common/api/atom_bindings.h deleted file mode 100644 index 9460145d2391a..0000000000000 --- a/atom/common/api/atom_bindings.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_API_ATOM_BINDINGS_H_ -#define ATOM_COMMON_API_ATOM_BINDINGS_H_ - -#include - -#include "base/macros.h" -#include "base/strings/string16.h" -#include "v8/include/v8.h" -#include "vendor/node/deps/uv/include/uv.h" - -namespace node { -class Environment; -} - -namespace atom { - -class AtomBindings { - public: - AtomBindings(); - virtual ~AtomBindings(); - - // Add process.atomBinding function, which behaves like process.binding but - // load native code from atom-shell instead. - void BindTo(v8::Isolate* isolate, v8::Local process); - - private: - void ActivateUVLoop(v8::Isolate* isolate); - - static void OnCallNextTick(uv_async_t* handle); - - uv_async_t call_next_tick_async_; - std::list pending_next_ticks_; - - DISALLOW_COPY_AND_ASSIGN(AtomBindings); -}; - -} // namespace atom - -#endif // ATOM_COMMON_API_ATOM_BINDINGS_H_ diff --git a/atom/common/api/event_emitter_caller.cc b/atom/common/api/event_emitter_caller.cc deleted file mode 100644 index 40448cad107e2..0000000000000 --- a/atom/common/api/event_emitter_caller.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/api/event_emitter_caller.h" - -#include "atom/common/api/locker.h" -#include "atom/common/node_includes.h" - -namespace mate { - -namespace internal { - -v8::Local CallEmitWithArgs(v8::Isolate* isolate, - v8::Local obj, - ValueVector* args) { - // Perform microtask checkpoint after running JavaScript. - v8::MicrotasksScope script_scope( - isolate, v8::MicrotasksScope::kRunMicrotasks); - // Use node::MakeCallback to call the callback, and it will also run pending - // tasks in Node.js. - return node::MakeCallback( - isolate, obj, "emit", args->size(), &args->front()); -} - -} // namespace internal - -} // namespace mate diff --git a/atom/common/api/event_emitter_caller.h b/atom/common/api/event_emitter_caller.h deleted file mode 100644 index a2567da9d1091..0000000000000 --- a/atom/common/api/event_emitter_caller.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_ -#define ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_ - -#include - -#include "native_mate/converter.h" - -namespace mate { - -namespace internal { - -using ValueVector = std::vector>; - -v8::Local CallEmitWithArgs(v8::Isolate* isolate, - v8::Local obj, - ValueVector* args); - -} // namespace internal - -// obj.emit.apply(obj, name, args...); -// The caller is responsible of allocating a HandleScope. -template -v8::Local EmitEvent(v8::Isolate* isolate, - v8::Local obj, - const StringType& name, - const internal::ValueVector& args) { - internal::ValueVector concatenated_args = { StringToV8(isolate, name) }; - concatenated_args.reserve(1 + args.size()); - concatenated_args.insert(concatenated_args.end(), args.begin(), args.end()); - return internal::CallEmitWithArgs(isolate, obj, &concatenated_args); -} - -// obj.emit(name, args...); -// The caller is responsible of allocating a HandleScope. -template -v8::Local EmitEvent(v8::Isolate* isolate, - v8::Local obj, - const StringType& name, - const Args&... args) { - internal::ValueVector converted_args = { - StringToV8(isolate, name), - ConvertToV8(isolate, args)..., - }; - return internal::CallEmitWithArgs(isolate, obj, &converted_args); -} - -} // namespace mate - -#endif // ATOM_COMMON_API_EVENT_EMITTER_CALLER_H_ diff --git a/atom/common/api/locker.cc b/atom/common/api/locker.cc deleted file mode 100644 index fe0b23479a46a..0000000000000 --- a/atom/common/api/locker.cc +++ /dev/null @@ -1,17 +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.chromium file. - -#include "atom/common/api/locker.h" - -namespace mate { - -Locker::Locker(v8::Isolate* isolate) { - if (IsBrowserProcess()) - locker_.reset(new v8::Locker(isolate)); -} - -Locker::~Locker() { -} - -} // namespace mate diff --git a/atom/common/api/locker.h b/atom/common/api/locker.h deleted file mode 100644 index e64ef1853ec5d..0000000000000 --- a/atom/common/api/locker.h +++ /dev/null @@ -1,36 +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.chromium file. - -#ifndef ATOM_COMMON_API_LOCKER_H_ -#define ATOM_COMMON_API_LOCKER_H_ - -#include - -#include "base/macros.h" -#include "v8/include/v8.h" - -namespace mate { - -// Only lock when lockers are used in current thread. -class Locker { - public: - explicit Locker(v8::Isolate* isolate); - ~Locker(); - - // Returns whether current process is browser process, currently we detect it - // by checking whether current has used V8 Lock, but it might be a bad idea. - static inline bool IsBrowserProcess() { return v8::Locker::IsActive(); } - - private: - void* operator new(size_t size); - void operator delete(void*, size_t); - - std::unique_ptr locker_; - - DISALLOW_COPY_AND_ASSIGN(Locker); -}; - -} // namespace mate - -#endif // ATOM_COMMON_API_LOCKER_H_ diff --git a/atom/common/api/object_life_monitor.cc b/atom/common/api/object_life_monitor.cc deleted file mode 100644 index ffcc0d7184206..0000000000000 --- a/atom/common/api/object_life_monitor.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Copyright (c) 2012 Intel Corp. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/api/object_life_monitor.h" - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" - -namespace atom { - -ObjectLifeMonitor::ObjectLifeMonitor(v8::Isolate* isolate, - v8::Local target) - : isolate_(isolate), - context_(isolate, isolate->GetCurrentContext()), - target_(isolate, target), - weak_ptr_factory_(this) { - target_.SetWeak(this, OnObjectGC, v8::WeakCallbackType::kParameter); -} - -ObjectLifeMonitor::~ObjectLifeMonitor() { - if (target_.IsEmpty()) - return; - target_.ClearWeak(); - target_.Reset(); -} - -// static -void ObjectLifeMonitor::OnObjectGC( - const v8::WeakCallbackInfo& data) { - ObjectLifeMonitor* self = data.GetParameter(); - self->target_.Reset(); - self->RunDestructor(); - data.SetSecondPassCallback(Free); -} - -// static -void ObjectLifeMonitor::Free( - const v8::WeakCallbackInfo& data) { - delete data.GetParameter(); -} - -} // namespace atom diff --git a/atom/common/api/object_life_monitor.h b/atom/common/api/object_life_monitor.h deleted file mode 100644 index 59d5fdb5cffda..0000000000000 --- a/atom/common/api/object_life_monitor.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_API_OBJECT_LIFE_MONITOR_H_ -#define ATOM_COMMON_API_OBJECT_LIFE_MONITOR_H_ - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "v8/include/v8.h" - -namespace atom { - -class ObjectLifeMonitor { - protected: - ObjectLifeMonitor(v8::Isolate* isolate, v8::Local target); - virtual ~ObjectLifeMonitor(); - - virtual void RunDestructor() = 0; - - private: - static void OnObjectGC(const v8::WeakCallbackInfo& data); - static void Free(const v8::WeakCallbackInfo& data); - - v8::Isolate* isolate_; - v8::Global context_; - v8::Global target_; - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ObjectLifeMonitor); -}; - -} // namespace atom - -#endif // ATOM_COMMON_API_OBJECT_LIFE_MONITOR_H_ diff --git a/atom/common/api/remote_callback_freer.cc b/atom/common/api/remote_callback_freer.cc deleted file mode 100644 index d1a185d51f394..0000000000000 --- a/atom/common/api/remote_callback_freer.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/api/remote_callback_freer.h" - -#include "atom/common/api/api_messages.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" - -namespace atom { - -// static -void RemoteCallbackFreer::BindTo(v8::Isolate* isolate, - v8::Local target, - int object_id, - content::WebContents* web_contents) { - new RemoteCallbackFreer(isolate, target, object_id, web_contents); -} - -RemoteCallbackFreer::RemoteCallbackFreer(v8::Isolate* isolate, - v8::Local target, - int object_id, - content::WebContents* web_contents) - : ObjectLifeMonitor(isolate, target), - content::WebContentsObserver(web_contents), - object_id_(object_id) { -} - -RemoteCallbackFreer::~RemoteCallbackFreer() { -} - -void RemoteCallbackFreer::RunDestructor() { - base::string16 channel = - base::ASCIIToUTF16("ELECTRON_RENDERER_RELEASE_CALLBACK"); - base::ListValue args; - args.AppendInteger(object_id_); - Send(new AtomViewMsg_Message(routing_id(), false, channel, args)); - - Observe(nullptr); -} - -void RemoteCallbackFreer::RenderViewDeleted(content::RenderViewHost*) { - delete this; -} - -} // namespace atom diff --git a/atom/common/api/remote_callback_freer.h b/atom/common/api/remote_callback_freer.h deleted file mode 100644 index 8fe80c8d4774c..0000000000000 --- a/atom/common/api/remote_callback_freer.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_ -#define ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_ -#include "atom/common/api/object_life_monitor.h" -#include "content/public/browser/web_contents_observer.h" - -namespace atom { - -class RemoteCallbackFreer : public ObjectLifeMonitor, - public content::WebContentsObserver { - public: - static void BindTo(v8::Isolate* isolate, - v8::Local target, - int object_id, - content::WebContents* web_conents); - - protected: - RemoteCallbackFreer(v8::Isolate* isolate, - v8::Local target, - int object_id, - content::WebContents* web_conents); - ~RemoteCallbackFreer() override; - - void RunDestructor() override; - - // content::WebContentsObserver: - void RenderViewDeleted(content::RenderViewHost*) override; - - private: - int object_id_; - - DISALLOW_COPY_AND_ASSIGN(RemoteCallbackFreer); -}; - -} // namespace atom - -#endif // ATOM_COMMON_API_REMOTE_CALLBACK_FREER_H_ diff --git a/atom/common/api/remote_object_freer.cc b/atom/common/api/remote_object_freer.cc deleted file mode 100644 index 1762f1d1e068d..0000000000000 --- a/atom/common/api/remote_object_freer.cc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/api/remote_object_freer.h" - -#include "atom/common/api/api_messages.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "content/public/renderer/render_view.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebView.h" - -using blink::WebLocalFrame; -using blink::WebView; - -namespace atom { - -namespace { - -content::RenderView* GetCurrentRenderView() { - WebLocalFrame* frame = WebLocalFrame::frameForCurrentContext(); - if (!frame) - return nullptr; - - WebView* view = frame->view(); - if (!view) - return nullptr; // can happen during closing. - - return content::RenderView::FromWebView(view); -} - -} // namespace - -// static -void RemoteObjectFreer::BindTo( - v8::Isolate* isolate, v8::Local target, int object_id) { - new RemoteObjectFreer(isolate, target, object_id); -} - -RemoteObjectFreer::RemoteObjectFreer( - v8::Isolate* isolate, v8::Local target, int object_id) - : ObjectLifeMonitor(isolate, target), - object_id_(object_id) { -} - -RemoteObjectFreer::~RemoteObjectFreer() { -} - -void RemoteObjectFreer::RunDestructor() { - content::RenderView* render_view = GetCurrentRenderView(); - if (!render_view) - return; - - base::string16 channel = base::ASCIIToUTF16("ipc-message"); - base::ListValue args; - args.AppendString("ELECTRON_BROWSER_DEREFERENCE"); - args.AppendInteger(object_id_); - render_view->Send( - new AtomViewHostMsg_Message(render_view->GetRoutingID(), channel, args)); -} - -} // namespace atom diff --git a/atom/common/api/remote_object_freer.h b/atom/common/api/remote_object_freer.h deleted file mode 100644 index c2b5d8b7d30b3..0000000000000 --- a/atom/common/api/remote_object_freer.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_ -#define ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_ - -#include "atom/common/api/object_life_monitor.h" - -namespace atom { - -class RemoteObjectFreer : public ObjectLifeMonitor { - public: - static void BindTo( - v8::Isolate* isolate, v8::Local target, int object_id); - - protected: - RemoteObjectFreer( - v8::Isolate* isolate, v8::Local target, int object_id); - ~RemoteObjectFreer() override; - - void RunDestructor() override; - - private: - int object_id_; - - DISALLOW_COPY_AND_ASSIGN(RemoteObjectFreer); -}; - -} // namespace atom - -#endif // ATOM_COMMON_API_REMOTE_OBJECT_FREER_H_ diff --git a/atom/common/asar/archive.cc b/atom/common/asar/archive.cc deleted file mode 100644 index e622effe5d3d2..0000000000000 --- a/atom/common/asar/archive.cc +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/asar/archive.h" - -#include -#include - -#include "atom/common/asar/scoped_temporary_file.h" -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/pickle.h" -#include "base/json/json_reader.h" -#include "base/strings/string_number_conversions.h" -#include "base/values.h" - -#if defined(OS_WIN) -#include "atom/node/osfhandle.h" -#endif - -namespace asar { - -namespace { - -#if defined(OS_WIN) -const char kSeparators[] = "\\/"; -#else -const char kSeparators[] = "/"; -#endif - -bool GetNodeFromPath(std::string path, - const base::DictionaryValue* root, - const base::DictionaryValue** out); - -// Gets the "files" from "dir". -bool GetFilesNode(const base::DictionaryValue* root, - const base::DictionaryValue* dir, - const base::DictionaryValue** out) { - // Test for symbol linked directory. - std::string link; - if (dir->GetStringWithoutPathExpansion("link", &link)) { - const base::DictionaryValue* linked_node = nullptr; - if (!GetNodeFromPath(link, root, &linked_node)) - return false; - dir = linked_node; - } - - return dir->GetDictionaryWithoutPathExpansion("files", out); -} - -// Gets sub-file "name" from "dir". -bool GetChildNode(const base::DictionaryValue* root, - const std::string& name, - const base::DictionaryValue* dir, - const base::DictionaryValue** out) { - if (name == "") { - *out = root; - return true; - } - - const base::DictionaryValue* files = nullptr; - return GetFilesNode(root, dir, &files) && - files->GetDictionaryWithoutPathExpansion(name, out); -} - -// Gets the node of "path" from "root". -bool GetNodeFromPath(std::string path, - const base::DictionaryValue* root, - const base::DictionaryValue** out) { - if (path == "") { - *out = root; - return true; - } - - const base::DictionaryValue* dir = root; - for (size_t delimiter_position = path.find_first_of(kSeparators); - delimiter_position != std::string::npos; - delimiter_position = path.find_first_of(kSeparators)) { - const base::DictionaryValue* child = nullptr; - if (!GetChildNode(root, path.substr(0, delimiter_position), dir, &child)) - return false; - - dir = child; - path.erase(0, delimiter_position + 1); - } - - return GetChildNode(root, path, dir, out); -} - -bool FillFileInfoWithNode(Archive::FileInfo* info, - uint32_t header_size, - const base::DictionaryValue* node) { - int size; - if (!node->GetInteger("size", &size)) - return false; - info->size = static_cast(size); - - if (node->GetBoolean("unpacked", &info->unpacked) && info->unpacked) - return true; - - std::string offset; - if (!node->GetString("offset", &offset)) - return false; - if (!base::StringToUint64(offset, &info->offset)) - return false; - info->offset += header_size; - - node->GetBoolean("executable", &info->executable); - - return true; -} - -} // namespace - -Archive::Archive(const base::FilePath& path) - : path_(path), - file_(path_, base::File::FLAG_OPEN | base::File::FLAG_READ), -#if defined(OS_WIN) - fd_(node::open_osfhandle( - reinterpret_cast(file_.GetPlatformFile()), 0)), -#elif defined(OS_POSIX) - fd_(file_.GetPlatformFile()), -#else - fd_(-1), -#endif - header_size_(0) { -} - -Archive::~Archive() { -#if defined(OS_WIN) - if (fd_ != -1) { - node::close(fd_); - // Don't close the handle since we already closed the fd. - file_.TakePlatformFile(); - } -#endif -} - -bool Archive::Init() { - if (!file_.IsValid()) { - if (file_.error_details() != base::File::FILE_ERROR_NOT_FOUND) { - LOG(WARNING) << "Opening " << path_.value() - << ": " << base::File::ErrorToString(file_.error_details()); - } - return false; - } - - std::vector buf; - int len; - - buf.resize(8); - len = file_.ReadAtCurrentPos(buf.data(), buf.size()); - if (len != static_cast(buf.size())) { - PLOG(ERROR) << "Failed to read header size from " << path_.value(); - return false; - } - - uint32_t size; - if (!base::PickleIterator(base::Pickle(buf.data(), buf.size())).ReadUInt32( - &size)) { - LOG(ERROR) << "Failed to parse header size from " << path_.value(); - return false; - } - - buf.resize(size); - len = file_.ReadAtCurrentPos(buf.data(), buf.size()); - if (len != static_cast(buf.size())) { - PLOG(ERROR) << "Failed to read header from " << path_.value(); - return false; - } - - std::string header; - if (!base::PickleIterator(base::Pickle(buf.data(), buf.size())).ReadString( - &header)) { - LOG(ERROR) << "Failed to parse header from " << path_.value(); - return false; - } - - std::string error; - base::JSONReader reader; - std::unique_ptr value(reader.ReadToValue(header)); - if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) { - LOG(ERROR) << "Failed to parse header: " << error; - return false; - } - - header_size_ = 8 + size; - header_.reset(static_cast(value.release())); - return true; -} - -bool Archive::GetFileInfo(const base::FilePath& path, FileInfo* info) { - if (!header_) - return false; - - const base::DictionaryValue* node; - if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node)) - return false; - - std::string link; - if (node->GetString("link", &link)) - return GetFileInfo(base::FilePath::FromUTF8Unsafe(link), info); - - return FillFileInfoWithNode(info, header_size_, node); -} - -bool Archive::Stat(const base::FilePath& path, Stats* stats) { - if (!header_) - return false; - - const base::DictionaryValue* node; - if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node)) - return false; - - if (node->HasKey("link")) { - stats->is_file = false; - stats->is_link = true; - return true; - } - - if (node->HasKey("files")) { - stats->is_file = false; - stats->is_directory = true; - return true; - } - - return FillFileInfoWithNode(stats, header_size_, node); -} - -bool Archive::Readdir(const base::FilePath& path, - std::vector* list) { - if (!header_) - return false; - - const base::DictionaryValue* node; - if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node)) - return false; - - const base::DictionaryValue* files; - if (!GetFilesNode(header_.get(), node, &files)) - return false; - - base::DictionaryValue::Iterator iter(*files); - while (!iter.IsAtEnd()) { - list->push_back(base::FilePath::FromUTF8Unsafe(iter.key())); - iter.Advance(); - } - return true; -} - -bool Archive::Realpath(const base::FilePath& path, base::FilePath* realpath) { - if (!header_) - return false; - - const base::DictionaryValue* node; - if (!GetNodeFromPath(path.AsUTF8Unsafe(), header_.get(), &node)) - return false; - - std::string link; - if (node->GetString("link", &link)) { - *realpath = base::FilePath::FromUTF8Unsafe(link); - return true; - } - - *realpath = path; - return true; -} - -bool Archive::CopyFileOut(const base::FilePath& path, base::FilePath* out) { - if (external_files_.contains(path)) { - *out = external_files_.get(path)->path(); - return true; - } - - FileInfo info; - if (!GetFileInfo(path, &info)) - return false; - - if (info.unpacked) { - *out = path_.AddExtension(FILE_PATH_LITERAL("unpacked")).Append(path); - return true; - } - - std::unique_ptr temp_file(new ScopedTemporaryFile); - base::FilePath::StringType ext = path.Extension(); - if (!temp_file->InitFromFile(&file_, ext, info.offset, info.size)) - return false; - -#if defined(OS_POSIX) - if (info.executable) { - // chmod a+x temp_file; - base::SetPosixFilePermissions(temp_file->path(), 0755); - } -#endif - - *out = temp_file->path(); - external_files_.set(path, std::move(temp_file)); - return true; -} - -int Archive::GetFD() const { - return fd_; -} - -} // namespace asar diff --git a/atom/common/asar/archive.h b/atom/common/asar/archive.h deleted file mode 100644 index 9e3abc3434dd9..0000000000000 --- a/atom/common/asar/archive.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_ASAR_ARCHIVE_H_ -#define ATOM_COMMON_ASAR_ARCHIVE_H_ - -#include -#include - -#include "base/containers/scoped_ptr_hash_map.h" -#include "base/files/file.h" -#include "base/files/file_path.h" - -namespace base { -class DictionaryValue; -} - -namespace asar { - -class ScopedTemporaryFile; - -// This class represents an asar package, and provides methods to read -// information from it. -class Archive { - public: - struct FileInfo { - FileInfo() : unpacked(false), executable(false), size(0), offset(0) {} - bool unpacked; - bool executable; - uint32_t size; - uint64_t offset; - }; - - struct Stats : public FileInfo { - Stats() : is_file(true), is_directory(false), is_link(false) {} - bool is_file; - bool is_directory; - bool is_link; - }; - - explicit Archive(const base::FilePath& path); - virtual ~Archive(); - - // Read and parse the header. - bool Init(); - - // Get the info of a file. - bool GetFileInfo(const base::FilePath& path, FileInfo* info); - - // Fs.stat(path). - bool Stat(const base::FilePath& path, Stats* stats); - - // Fs.readdir(path). - bool Readdir(const base::FilePath& path, std::vector* files); - - // Fs.realpath(path). - bool Realpath(const base::FilePath& path, base::FilePath* realpath); - - // Copy the file into a temporary file, and return the new path. - // For unpacked file, this method will return its real path. - bool CopyFileOut(const base::FilePath& path, base::FilePath* out); - - // Returns the file's fd. - int GetFD() const; - - base::FilePath path() const { return path_; } - base::DictionaryValue* header() const { return header_.get(); } - - private: - base::FilePath path_; - base::File file_; - int fd_; - uint32_t header_size_; - std::unique_ptr header_; - - // Cached external temporary files. - base::ScopedPtrHashMap> - external_files_; - - DISALLOW_COPY_AND_ASSIGN(Archive); -}; - -} // namespace asar - -#endif // ATOM_COMMON_ASAR_ARCHIVE_H_ diff --git a/atom/common/asar/asar_util.cc b/atom/common/asar/asar_util.cc deleted file mode 100644 index 1eee09949aff3..0000000000000 --- a/atom/common/asar/asar_util.cc +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/asar/asar_util.h" - -#include -#include - -#include "atom/common/asar/archive.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/lazy_instance.h" -#include "base/stl_util.h" - -namespace asar { - -namespace { - -// The global instance of ArchiveMap, will be destroyed on exit. -typedef std::map> ArchiveMap; -static base::LazyInstance g_archive_map = LAZY_INSTANCE_INITIALIZER; - -const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar"); - -} // namespace - -std::shared_ptr GetOrCreateAsarArchive(const base::FilePath& path) { - ArchiveMap& archive_map = *g_archive_map.Pointer(); - if (!ContainsKey(archive_map, path)) { - std::shared_ptr archive(new Archive(path)); - if (!archive->Init()) - return nullptr; - archive_map[path] = archive; - } - return archive_map[path]; -} - -bool GetAsarArchivePath(const base::FilePath& full_path, - base::FilePath* asar_path, - base::FilePath* relative_path) { - base::FilePath iter = full_path; - while (true) { - base::FilePath dirname = iter.DirName(); - if (iter.MatchesExtension(kAsarExtension)) - break; - else if (iter == dirname) - return false; - iter = dirname; - } - - base::FilePath tail; - if (!iter.AppendRelativePath(full_path, &tail)) - return false; - - *asar_path = iter; - *relative_path = tail; - return true; -} - -bool ReadFileToString(const base::FilePath& path, std::string* contents) { - base::FilePath asar_path, relative_path; - if (!GetAsarArchivePath(path, &asar_path, &relative_path)) - return base::ReadFileToString(path, contents); - - std::shared_ptr archive = GetOrCreateAsarArchive(asar_path); - if (!archive) - return false; - - Archive::FileInfo info; - if (!archive->GetFileInfo(relative_path, &info)) - return false; - - if (info.unpacked) { - base::FilePath real_path; - // For unpacked file it will return the real path instead of doing the copy. - archive->CopyFileOut(relative_path, &real_path); - return base::ReadFileToString(real_path, contents); - } - - base::File src(asar_path, base::File::FLAG_OPEN | base::File::FLAG_READ); - if (!src.IsValid()) - return false; - - contents->resize(info.size); - return static_cast(info.size) == src.Read( - info.offset, const_cast(contents->data()), contents->size()); -} - -} // namespace asar diff --git a/atom/common/asar/asar_util.h b/atom/common/asar/asar_util.h deleted file mode 100644 index 4cb5b88e04838..0000000000000 --- a/atom/common/asar/asar_util.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_ASAR_ASAR_UTIL_H_ -#define ATOM_COMMON_ASAR_ASAR_UTIL_H_ - -#include -#include - -namespace base { -class FilePath; -} - -namespace asar { - -class Archive; - -// Gets or creates a new Archive from the path. -std::shared_ptr GetOrCreateAsarArchive(const base::FilePath& path); - -// Separates the path to Archive out. -bool GetAsarArchivePath(const base::FilePath& full_path, - base::FilePath* asar_path, - base::FilePath* relative_path); - -// Same with base::ReadFileToString but supports asar Archive. -bool ReadFileToString(const base::FilePath& path, std::string* contents); - -} // namespace asar - -#endif // ATOM_COMMON_ASAR_ASAR_UTIL_H_ diff --git a/atom/common/asar/scoped_temporary_file.cc b/atom/common/asar/scoped_temporary_file.cc deleted file mode 100644 index 8578d90d9074f..0000000000000 --- a/atom/common/asar/scoped_temporary_file.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/asar/scoped_temporary_file.h" - -#include - -#include "base/files/file_util.h" -#include "base/threading/thread_restrictions.h" - -namespace asar { - -ScopedTemporaryFile::ScopedTemporaryFile() { -} - -ScopedTemporaryFile::~ScopedTemporaryFile() { - if (!path_.empty()) { - base::ThreadRestrictions::ScopedAllowIO allow_io; - // On Windows it is very likely the file is already in use (because it is - // mostly used for Node native modules), so deleting it now will halt the - // program. -#if defined(OS_WIN) - base::DeleteFileAfterReboot(path_); -#else - base::DeleteFile(path_, false); -#endif - } -} - -bool ScopedTemporaryFile::Init(const base::FilePath::StringType& ext) { - if (!path_.empty()) - return true; - - base::ThreadRestrictions::ScopedAllowIO allow_io; - if (!base::CreateTemporaryFile(&path_)) - return false; - -#if defined(OS_WIN) - // Keep the original extension. - if (!ext.empty()) { - base::FilePath new_path = path_.AddExtension(ext); - if (!base::Move(path_, new_path)) - return false; - path_ = new_path; - } -#endif - - return true; -} - -bool ScopedTemporaryFile::InitFromFile(base::File* src, - const base::FilePath::StringType& ext, - uint64_t offset, uint64_t size) { - if (!src->IsValid()) - return false; - - if (!Init(ext)) - return false; - - std::vector buf(size); - int len = src->Read(offset, buf.data(), buf.size()); - if (len != static_cast(size)) - return false; - - base::File dest(path_, base::File::FLAG_OPEN | base::File::FLAG_WRITE); - if (!dest.IsValid()) - return false; - - return dest.WriteAtCurrentPos(buf.data(), buf.size()) == - static_cast(size); -} - -} // namespace asar diff --git a/atom/common/asar/scoped_temporary_file.h b/atom/common/asar/scoped_temporary_file.h deleted file mode 100644 index 5931d9b87af78..0000000000000 --- a/atom/common/asar/scoped_temporary_file.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_ASAR_SCOPED_TEMPORARY_FILE_H_ -#define ATOM_COMMON_ASAR_SCOPED_TEMPORARY_FILE_H_ - -#include "base/files/file_path.h" - -namespace base { -class File; -} - -namespace asar { - -// An object representing a temporary file that should be cleaned up when this -// object goes out of scope. Note that since deletion occurs during the -// destructor, no further error handling is possible if the directory fails to -// be deleted. As a result, deletion is not guaranteed by this class. -class ScopedTemporaryFile { - public: - ScopedTemporaryFile(); - virtual ~ScopedTemporaryFile(); - - // Init an empty temporary file with a certain extension. - bool Init(const base::FilePath::StringType& ext); - - // Init an temporary file and fill it with content of |path|. - bool InitFromFile(base::File* src, - const base::FilePath::StringType& ext, - uint64_t offset, uint64_t size); - - base::FilePath path() const { return path_; } - - private: - base::FilePath path_; - - DISALLOW_COPY_AND_ASSIGN(ScopedTemporaryFile); -}; - -} // namespace asar - -#endif // ATOM_COMMON_ASAR_SCOPED_TEMPORARY_FILE_H_ diff --git a/atom/common/atom_command_line.cc b/atom/common/atom_command_line.cc deleted file mode 100644 index 08880ffe4a359..0000000000000 --- a/atom/common/atom_command_line.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/atom_command_line.h" - -#include "base/command_line.h" -#include "node/deps/uv/include/uv.h" - -namespace atom { - -// static -std::vector AtomCommandLine::argv_; - -#if defined(OS_WIN) -// static -std::vector AtomCommandLine::wargv_; -#endif - -// static -void AtomCommandLine::Init(int argc, const char* const* argv) { - // Hack around with the argv pointer. Used for process.title = "blah" - char** new_argv = uv_setup_args(argc, const_cast(argv)); - for (int i = 0; i < argc; ++i) { - argv_.push_back(new_argv[i]); - } -} - -#if defined(OS_WIN) -// static -void AtomCommandLine::InitW(int argc, const wchar_t* const* argv) { - for (int i = 0; i < argc; ++i) { - wargv_.push_back(argv[i]); - } -} -#endif - -#if defined(OS_LINUX) -// static -void AtomCommandLine::InitializeFromCommandLine() { - argv_ = base::CommandLine::ForCurrentProcess()->argv(); -} -#endif - -} // namespace atom diff --git a/atom/common/atom_command_line.h b/atom/common/atom_command_line.h deleted file mode 100644 index a834ce9256623..0000000000000 --- a/atom/common/atom_command_line.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_ATOM_COMMAND_LINE_H_ -#define ATOM_COMMON_ATOM_COMMAND_LINE_H_ - -#include -#include - -#include "base/macros.h" -#include "build/build_config.h" - -namespace atom { - -// Singleton to remember the original "argc" and "argv". -class AtomCommandLine { - public: - static void Init(int argc, const char* const* argv); - static std::vector argv() { return argv_; } - -#if defined(OS_WIN) - static void InitW(int argc, const wchar_t* const* argv); - static std::vector wargv() { return wargv_; } -#endif - -#if defined(OS_LINUX) - // On Linux the command line has to be read from base::CommandLine since - // it is using zygote. - static void InitializeFromCommandLine(); -#endif - - private: - static std::vector argv_; - -#if defined(OS_WIN) - static std::vector wargv_; -#endif - - DISALLOW_IMPLICIT_CONSTRUCTORS(AtomCommandLine); -}; - -} // namespace atom - -#endif // ATOM_COMMON_ATOM_COMMAND_LINE_H_ diff --git a/atom/common/atom_constants.cc b/atom/common/atom_constants.cc deleted file mode 100644 index f66c947aa24c2..0000000000000 --- a/atom/common/atom_constants.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/atom_constants.h" - -namespace atom { - -const char kCORSHeader[] = "Access-Control-Allow-Origin: *"; - -const char kSHA1Certificate[] = "SHA-1 Certificate"; -const char kSHA1MajorDescription[] = - "The certificate for this site expires in 2017 or later, " - "and the certificate chain contains a certificate signed using SHA-1."; -const char kSHA1MinorDescription[] = - "The certificate for this site expires in 2016, " - "and the certificate chain contains a certificate signed using SHA-1."; -const char kCertificateError[] = "Certificate Error"; -const char kValidCertificate[] = "Valid Certificate"; -const char kValidCertificateDescription[] = - "The connection to this site is using a valid, trusted server certificate."; -const char kSecureProtocol[] = "Secure TLS connection"; -const char kSecureProtocolDescription[] = - "The connection to this site is using a strong protocol version " - "and cipher suite."; - -} // namespace atom diff --git a/atom/common/atom_constants.h b/atom/common/atom_constants.h deleted file mode 100644 index b67b7b2e4ae5e..0000000000000 --- a/atom/common/atom_constants.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_ATOM_CONSTANTS_H_ -#define ATOM_COMMON_ATOM_CONSTANTS_H_ - -namespace atom { - -// Header to ignore CORS. -extern const char kCORSHeader[]; - -// Strings describing Chrome security policy for DevTools security panel. -extern const char kSHA1Certificate[]; -extern const char kSHA1MajorDescription[]; -extern const char kSHA1MinorDescription[]; -extern const char kCertificateError[]; -extern const char kValidCertificate[]; -extern const char kValidCertificateDescription[]; -extern const char kSecureProtocol[]; -extern const char kSecureProtocolDescription[]; - -} // namespace atom - -#endif // ATOM_COMMON_ATOM_CONSTANTS_H_ diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h deleted file mode 100644 index 9ed149610a189..0000000000000 --- a/atom/common/atom_version.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_VERSION_H -#define ATOM_VERSION_H - -#define ATOM_MAJOR_VERSION 1 -#define ATOM_MINOR_VERSION 3 -#define ATOM_PATCH_VERSION 2 - -#define ATOM_VERSION_IS_RELEASE 1 - -#ifndef ATOM_TAG -# define ATOM_TAG "" -#endif - -#ifndef ATOM_STRINGIFY -#define ATOM_STRINGIFY(n) ATOM_STRINGIFY_HELPER(n) -#define ATOM_STRINGIFY_HELPER(n) #n -#endif - -#if ATOM_VERSION_IS_RELEASE -# define ATOM_VERSION_STRING ATOM_STRINGIFY(ATOM_MAJOR_VERSION) "." \ - ATOM_STRINGIFY(ATOM_MINOR_VERSION) "." \ - ATOM_STRINGIFY(ATOM_PATCH_VERSION) \ - ATOM_TAG -#else -# define ATOM_VERSION_STRING ATOM_STRINGIFY(ATOM_MAJOR_VERSION) "." \ - ATOM_STRINGIFY(ATOM_MINOR_VERSION) "." \ - ATOM_STRINGIFY(ATOM_PATCH_VERSION) \ - ATOM_TAG "-pre" -#endif - -#define ATOM_VERSION "v" ATOM_VERSION_STRING - - -#define ATOM_VERSION_AT_LEAST(major, minor, patch) \ - (( (major) < ATOM_MAJOR_VERSION) \ - || ((major) == ATOM_MAJOR_VERSION && (minor) < ATOM_MINOR_VERSION) \ - || ((major) == ATOM_MAJOR_VERSION && (minor) == ATOM_MINOR_VERSION && (patch) <= ATOM_PATCH_VERSION)) - -#endif /* ATOM_VERSION_H */ diff --git a/atom/common/chrome_version.h b/atom/common/chrome_version.h deleted file mode 100644 index 96186adc4f7ce..0000000000000 --- a/atom/common/chrome_version.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// This file is generated by script/bootstrap.py, you should never modify it -// by hand. - -#ifndef ATOM_COMMON_CHROME_VERSION_H_ -#define ATOM_COMMON_CHROME_VERSION_H_ - -#define CHROME_VERSION_STRING "52.0.2743.82" -#define CHROME_VERSION "v" CHROME_VERSION_STRING - -#endif // ATOM_COMMON_CHROME_VERSION_H_ diff --git a/atom/common/color_util.cc b/atom/common/color_util.cc deleted file mode 100644 index a6640d9e08b6c..0000000000000 --- a/atom/common/color_util.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/color_util.h" - -#include - -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" - -namespace atom { - -SkColor ParseHexColor(const std::string& color_string) { - // Check the string for incorrect formatting. - if (color_string.empty() || color_string[0] != '#') - return SK_ColorWHITE; - - // Prepend FF if alpha channel is not specified. - std::string source = color_string.substr(1); - if (source.size() == 3) - source.insert(0, "F"); - else if (source.size() == 6) - source.insert(0, "FF"); - - // Convert the string from #FFF format to #FFFFFF format. - std::string formatted_color; - if (source.size() == 4) { - for (size_t i = 0; i < 4; ++i) { - formatted_color += source[i]; - formatted_color += source[i]; - } - } else if (source.size() == 8) { - formatted_color = source; - } else { - return SK_ColorWHITE; - } - - // Convert the string to an integer and make sure it is in the correct value - // range. - std::vector bytes; - if (!base::HexStringToBytes(formatted_color, &bytes)) - return SK_ColorWHITE; - - return SkColorSetARGB(bytes[0], bytes[1], bytes[2], bytes[3]); -} - -} // namespace atom diff --git a/atom/common/color_util.h b/atom/common/color_util.h deleted file mode 100644 index 0f2bb9633a73f..0000000000000 --- a/atom/common/color_util.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_COLOR_UTIL_H_ -#define ATOM_COMMON_COLOR_UTIL_H_ - -#include - -#include "third_party/skia/include/core/SkColor.h" - -namespace atom { - -// Parse hex color like "#FFF" or "#EFEFEF" -SkColor ParseHexColor(const std::string& name); - -} // namespace atom - -#endif // ATOM_COMMON_COLOR_UTIL_H_ diff --git a/atom/common/common_message_generator.cc b/atom/common/common_message_generator.cc deleted file mode 100644 index 854fc8778e9c0..0000000000000 --- a/atom/common/common_message_generator.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// Get basic type definitions. -#define IPC_MESSAGE_IMPL -#include "atom/common/common_message_generator.h" - -// Generate constructors. -#include "ipc/struct_constructor_macros.h" -#include "atom/common/common_message_generator.h" - -// Generate destructors. -#include "ipc/struct_destructor_macros.h" -#include "atom/common/common_message_generator.h" - -// Generate param traits write methods. -#include "ipc/param_traits_write_macros.h" -namespace IPC { -#include "atom/common/common_message_generator.h" -} // namespace IPC - -// Generate param traits read methods. -#include "ipc/param_traits_read_macros.h" -namespace IPC { -#include "atom/common/common_message_generator.h" -} // namespace IPC - -// Generate param traits log methods. -#include "ipc/param_traits_log_macros.h" -namespace IPC { -#include "atom/common/common_message_generator.h" -} // namespace IPC - diff --git a/atom/common/common_message_generator.h b/atom/common/common_message_generator.h deleted file mode 100644 index 64206956863ed..0000000000000 --- a/atom/common/common_message_generator.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// Multiply-included file, no traditional include guard. - -#include "atom/common/api/api_messages.h" -#include "chrome/common/print_messages.h" -#include "chrome/common/tts_messages.h" -#include "chrome/common/widevine_cdm_messages.h" -#include "chrome/common/chrome_utility_messages.h" diff --git a/atom/common/crash_reporter/crash_reporter.cc b/atom/common/crash_reporter/crash_reporter.cc deleted file mode 100644 index f4f0ff9b7b163..0000000000000 --- a/atom/common/crash_reporter/crash_reporter.cc +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/crash_reporter/crash_reporter.h" - -#include "atom/browser/browser.h" -#include "atom/common/atom_version.h" -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/strings/string_split.h" -#include "base/strings/string_number_conversions.h" -#include "content/public/common/content_switches.h" - -namespace crash_reporter { - -CrashReporter::CrashReporter() { - auto cmd = base::CommandLine::ForCurrentProcess(); - is_browser_ = cmd->GetSwitchValueASCII(switches::kProcessType).empty(); -} - -CrashReporter::~CrashReporter() { -} - -void CrashReporter::Start(const std::string& product_name, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler, - const StringMap& extra_parameters) { - SetUploadParameters(extra_parameters); - - InitBreakpad(product_name, ATOM_VERSION_STRING, company_name, submit_url, - auto_submit, skip_system_crash_handler); -} - -void CrashReporter::SetUploadParameters(const StringMap& parameters) { - upload_parameters_ = parameters; - upload_parameters_["process_type"] = is_browser_ ? "browser" : "renderer"; - - // Setting platform dependent parameters. - SetUploadParameters(); -} - -std::vector -CrashReporter::GetUploadedReports(const std::string& path) { - std::string file_content; - std::vector result; - if (base::ReadFileToString(base::FilePath::FromUTF8Unsafe(path), - &file_content)) { - std::vector reports = base::SplitString( - file_content, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - for (const std::string& report : reports) { - std::vector report_item = base::SplitString( - report, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - int report_time = 0; - if (report_item.size() >= 2 && base::StringToInt(report_item[0], - &report_time)) { - result.push_back(CrashReporter::UploadReportResult(report_time, - report_item[1])); - } - } - } - return result; -} - -void CrashReporter::InitBreakpad(const std::string& product_name, - const std::string& version, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler) { -} - -void CrashReporter::SetUploadParameters() { -} - -#if defined(OS_MACOSX) && defined(MAS_BUILD) -// static -CrashReporter* CrashReporter::GetInstance() { - static CrashReporter crash_reporter; - return &crash_reporter; -} -#endif - -} // namespace crash_reporter diff --git a/atom/common/crash_reporter/crash_reporter.h b/atom/common/crash_reporter/crash_reporter.h deleted file mode 100644 index eebbe16dca822..0000000000000 --- a/atom/common/crash_reporter/crash_reporter.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_H_ -#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_H_ - -#include -#include -#include -#include - -#include "base/macros.h" - -namespace crash_reporter { - -class CrashReporter { - public: - typedef std::map StringMap; - typedef std::pair UploadReportResult; // upload-date, id - - static CrashReporter* GetInstance(); - - void Start(const std::string& product_name, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler, - const StringMap& extra_parameters); - - virtual std::vector GetUploadedReports( - const std::string& path); - - protected: - CrashReporter(); - virtual ~CrashReporter(); - - virtual void InitBreakpad(const std::string& product_name, - const std::string& version, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler); - virtual void SetUploadParameters(); - - StringMap upload_parameters_; - bool is_browser_; - - private: - void SetUploadParameters(const StringMap& parameters); - - DISALLOW_COPY_AND_ASSIGN(CrashReporter); -}; - -} // namespace crash_reporter - -#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_H_ diff --git a/atom/common/crash_reporter/crash_reporter_linux.cc b/atom/common/crash_reporter/crash_reporter_linux.cc deleted file mode 100644 index 6fe69f486956c..0000000000000 --- a/atom/common/crash_reporter/crash_reporter_linux.cc +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/crash_reporter/crash_reporter_linux.h" - -#include -#include - -#include - -#include "base/debug/crash_logging.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/linux_util.h" -#include "base/logging.h" -#include "base/process/memory.h" -#include "base/memory/singleton.h" -#include "base/strings/stringprintf.h" -#include "vendor/breakpad/src/client/linux/handler/exception_handler.h" -#include "vendor/breakpad/src/common/linux/linux_libc_support.h" - -using google_breakpad::ExceptionHandler; -using google_breakpad::MinidumpDescriptor; - -namespace crash_reporter { - -namespace { - -static const size_t kDistroSize = 128; - -// Define a preferred limit on minidump sizes, because Crash Server currently -// throws away any larger than 1.2MB (1.2 * 1024 * 1024). A value of -1 means -// no limit. -static const off_t kMaxMinidumpFileSize = 1258291; - -} // namespace - -CrashReporterLinux::CrashReporterLinux() - : process_start_time_(0), - pid_(getpid()) { - // Set the base process start time value. - struct timeval tv; - if (!gettimeofday(&tv, NULL)) { - uint64_t ret = tv.tv_sec; - ret *= 1000; - ret += tv.tv_usec / 1000; - process_start_time_ = ret; - } - - // Make base::g_linux_distro work. - base::SetLinuxDistro(base::GetLinuxDistro()); -} - -CrashReporterLinux::~CrashReporterLinux() { -} - -void CrashReporterLinux::InitBreakpad(const std::string& product_name, - const std::string& version, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler) { - EnableCrashDumping(product_name); - - crash_keys_.SetKeyValue("prod", ATOM_PRODUCT_NAME); - crash_keys_.SetKeyValue("ver", version.c_str()); - upload_url_ = submit_url; - - for (StringMap::const_iterator iter = upload_parameters_.begin(); - iter != upload_parameters_.end(); ++iter) - crash_keys_.SetKeyValue(iter->first.c_str(), iter->second.c_str()); -} - -void CrashReporterLinux::SetUploadParameters() { - upload_parameters_["platform"] = "linux"; -} - -void CrashReporterLinux::EnableCrashDumping(const std::string& product_name) { - std::string dump_dir = "/tmp/" + product_name + " Crashes"; - base::FilePath dumps_path(dump_dir); - base::CreateDirectory(dumps_path); - - std::string log_file = base::StringPrintf( - "%s/%s", dump_dir.c_str(), "uploads.log"); - strncpy(g_crash_log_path, log_file.c_str(), sizeof(g_crash_log_path)); - - MinidumpDescriptor minidump_descriptor(dumps_path.value()); - minidump_descriptor.set_size_limit(kMaxMinidumpFileSize); - - breakpad_.reset(new ExceptionHandler( - minidump_descriptor, - NULL, - CrashDone, - this, - true, // Install handlers. - -1)); -} - -bool CrashReporterLinux::CrashDone(const MinidumpDescriptor& minidump, - void* context, - const bool succeeded) { - CrashReporterLinux* self = static_cast(context); - - // WARNING: this code runs in a compromised context. It may not call into - // libc nor allocate memory normally. - if (!succeeded) { - const char msg[] = "Failed to generate minidump."; - WriteLog(msg, sizeof(msg) - 1); - return false; - } - - DCHECK(!minidump.IsFD()); - - BreakpadInfo info = {0}; - info.filename = minidump.path(); - info.fd = minidump.fd(); - info.distro = base::g_linux_distro; - info.distro_length = my_strlen(base::g_linux_distro); - info.upload = true; - info.process_start_time = self->process_start_time_; - info.oom_size = base::g_oom_size; - info.pid = self->pid_; - info.upload_url = self->upload_url_.c_str(); - info.crash_keys = &self->crash_keys_; - HandleCrashDump(info); - return true; -} - -// static -CrashReporterLinux* CrashReporterLinux::GetInstance() { - return base::Singleton::get(); -} - -// static -CrashReporter* CrashReporter::GetInstance() { - return CrashReporterLinux::GetInstance(); -} - -} // namespace crash_reporter diff --git a/atom/common/crash_reporter/crash_reporter_linux.h b/atom/common/crash_reporter/crash_reporter_linux.h deleted file mode 100644 index de5a50e7191e5..0000000000000 --- a/atom/common/crash_reporter/crash_reporter_linux.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_LINUX_H_ -#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_LINUX_H_ - -#include -#include - -#include "atom/common/crash_reporter/crash_reporter.h" -#include "atom/common/crash_reporter/linux/crash_dump_handler.h" -#include "base/compiler_specific.h" - -namespace base { -template struct DefaultSingletonTraits; -} - -namespace google_breakpad { -class ExceptionHandler; -class MinidumpDescriptor; -} - -namespace crash_reporter { - -class CrashReporterLinux : public CrashReporter { - public: - static CrashReporterLinux* GetInstance(); - - void InitBreakpad(const std::string& product_name, - const std::string& version, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler) override; - void SetUploadParameters() override; - - private: - friend struct base::DefaultSingletonTraits; - - CrashReporterLinux(); - virtual ~CrashReporterLinux(); - - void EnableCrashDumping(const std::string& product_name); - - static bool CrashDone(const google_breakpad::MinidumpDescriptor& minidump, - void* context, - const bool succeeded); - - std::unique_ptr breakpad_; - CrashKeyStorage crash_keys_; - - uint64_t process_start_time_; - pid_t pid_; - std::string upload_url_; - - DISALLOW_COPY_AND_ASSIGN(CrashReporterLinux); -}; -} // namespace crash_reporter - -#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_LINUX_H_ diff --git a/atom/common/crash_reporter/crash_reporter_mac.h b/atom/common/crash_reporter/crash_reporter_mac.h deleted file mode 100644 index 8acf50285d36d..0000000000000 --- a/atom/common/crash_reporter/crash_reporter_mac.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_ -#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_ - -#include -#include - -#include "atom/common/crash_reporter/crash_reporter.h" -#include "base/compiler_specific.h" -#include "base/strings/string_piece.h" -#include "vendor/crashpad/client/simple_string_dictionary.h" - -namespace base { -template struct DefaultSingletonTraits; -} - -namespace crash_reporter { - -class CrashReporterMac : public CrashReporter { - public: - static CrashReporterMac* GetInstance(); - - void InitBreakpad(const std::string& product_name, - const std::string& version, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler) override; - void SetUploadParameters() override; - - private: - friend struct base::DefaultSingletonTraits; - - CrashReporterMac(); - virtual ~CrashReporterMac(); - - void SetUploadsEnabled(bool enable_uploads); - void SetCrashKeyValue(const base::StringPiece& key, - const base::StringPiece& value); - - std::vector GetUploadedReports( - const std::string& path) override; - - std::unique_ptr simple_string_dictionary_; - - DISALLOW_COPY_AND_ASSIGN(CrashReporterMac); -}; - -} // namespace crash_reporter - -#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_ diff --git a/atom/common/crash_reporter/crash_reporter_mac.mm b/atom/common/crash_reporter/crash_reporter_mac.mm deleted file mode 100644 index ee2ce036048fc..0000000000000 --- a/atom/common/crash_reporter/crash_reporter_mac.mm +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/crash_reporter/crash_reporter_mac.h" - -#include - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/mac/bundle_locations.h" -#include "base/mac/mac_util.h" -#include "base/memory/singleton.h" -#include "base/strings/string_piece.h" -#include "base/strings/stringprintf.h" -#include "base/strings/sys_string_conversions.h" -#include "vendor/crashpad/client/crash_report_database.h" -#include "vendor/crashpad/client/crashpad_client.h" -#include "vendor/crashpad/client/crashpad_info.h" -#include "vendor/crashpad/client/settings.h" - -namespace crash_reporter { - -CrashReporterMac::CrashReporterMac() { -} - -CrashReporterMac::~CrashReporterMac() { -} - -void CrashReporterMac::InitBreakpad(const std::string& product_name, - const std::string& version, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler) { - // check whether crashpad has been initilized. - // Only need to initilize once. - if (simple_string_dictionary_) - return; - - std::string dump_dir = "/tmp/" + product_name + " Crashes"; - base::FilePath database_path(dump_dir); - if (is_browser_) { - @autoreleasepool { - base::FilePath framework_bundle_path = base::mac::FrameworkBundlePath(); - base::FilePath handler_path = - framework_bundle_path.Append("Resources").Append("crashpad_handler"); - - crashpad::CrashpadClient crashpad_client; - if (crashpad_client.StartHandler(handler_path, database_path, - submit_url, - StringMap(), - std::vector(), - true)) { - crashpad_client.UseHandler(); - } - } // @autoreleasepool - } - - crashpad::CrashpadInfo* crashpad_info = - crashpad::CrashpadInfo::GetCrashpadInfo(); - if (skip_system_crash_handler) { - crashpad_info->set_system_crash_reporter_forwarding( - crashpad::TriState::kDisabled); - } - - simple_string_dictionary_.reset(new crashpad::SimpleStringDictionary()); - crashpad_info->set_simple_annotations(simple_string_dictionary_.get()); - - SetCrashKeyValue("prod", ATOM_PRODUCT_NAME); - SetCrashKeyValue("process_type", is_browser_ ? "browser" : "renderer"); - SetCrashKeyValue("ver", version); - - for (const auto& upload_parameter: upload_parameters_) { - SetCrashKeyValue(upload_parameter.first, upload_parameter.second); - } - if (is_browser_) { - std::unique_ptr database = - crashpad::CrashReportDatabase::Initialize(database_path); - if (database) { - database->GetSettings()->SetUploadsEnabled(auto_submit); - } - } -} - -void CrashReporterMac::SetUploadParameters() { - upload_parameters_["platform"] = "darwin"; -} - -void CrashReporterMac::SetCrashKeyValue(const base::StringPiece& key, - const base::StringPiece& value) { - simple_string_dictionary_->SetKeyValue(key.data(), value.data()); -} - -std::vector -CrashReporterMac::GetUploadedReports(const std::string& path) { - std::vector uploaded_reports; - - base::FilePath file_path(path); - if (!base::PathExists(file_path)) { - return uploaded_reports; - } - // Load crashpad database. - std::unique_ptr database = - crashpad::CrashReportDatabase::Initialize(file_path); - DCHECK(database); - - std::vector completed_reports; - crashpad::CrashReportDatabase::OperationStatus status = - database->GetCompletedReports(&completed_reports); - if (status != crashpad::CrashReportDatabase::kNoError) { - return uploaded_reports; - } - - for (const crashpad::CrashReportDatabase::Report& completed_report : - completed_reports) { - if (completed_report.uploaded) { - uploaded_reports.push_back( - UploadReportResult(static_cast(completed_report.creation_time), - completed_report.id)); - } - } - - auto sort_by_time = [](const UploadReportResult& a, - const UploadReportResult& b) {return a.first >= b.first;}; - std::sort(uploaded_reports.begin(), uploaded_reports.end(), sort_by_time); - return uploaded_reports; -} - -// static -CrashReporterMac* CrashReporterMac::GetInstance() { - return base::Singleton::get(); -} - -// static -CrashReporter* CrashReporter::GetInstance() { - return CrashReporterMac::GetInstance(); -} - -} // namespace crash_reporter diff --git a/atom/common/crash_reporter/crash_reporter_win.cc b/atom/common/crash_reporter/crash_reporter_win.cc deleted file mode 100644 index 3261f9c9c6a3b..0000000000000 --- a/atom/common/crash_reporter/crash_reporter_win.cc +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/crash_reporter/crash_reporter_win.h" - -#include - -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/memory/singleton.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "content/public/common/result_codes.h" -#include "gin/public/debug.h" -#include "sandbox/win/src/nt_internals.h" - -#pragma intrinsic(_AddressOfReturnAddress) -#pragma intrinsic(_ReturnAddress) - -#ifdef _WIN64 -// See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx -typedef struct _UNWIND_INFO { - unsigned char Version : 3; - unsigned char Flags : 5; - unsigned char SizeOfProlog; - unsigned char CountOfCodes; - unsigned char FrameRegister : 4; - unsigned char FrameOffset : 4; - ULONG ExceptionHandler; -} UNWIND_INFO, *PUNWIND_INFO; -#endif - -namespace crash_reporter { - -namespace { - -// Minidump with stacks, PEB, TEB, and unloaded module list. -const MINIDUMP_TYPE kSmallDumpType = static_cast( - MiniDumpWithProcessThreadData | // Get PEB and TEB. - MiniDumpWithUnloadedModules); // Get unloaded modules when available. - -const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent"; -const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service"; - -// Matches breakpad/src/client/windows/common/ipc_protocol.h. -const int kNameMaxLength = 64; -const int kValueMaxLength = 64; - -typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle, - NTSTATUS ExitStatus); -char* g_real_terminate_process_stub = NULL; - -void TerminateProcessWithoutDump() { - // Patched stub exists based on conditions (See InitCrashReporter). - // As a side note this function also gets called from - // WindowProcExceptionFilter. - if (g_real_terminate_process_stub == NULL) { - ::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED); - } else { - NtTerminateProcessPtr real_terminate_proc = - reinterpret_cast( - static_cast(g_real_terminate_process_stub)); - real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED); - } -} - -#ifdef _WIN64 -int CrashForExceptionInNonABICompliantCodeRange( - PEXCEPTION_RECORD ExceptionRecord, - ULONG64 EstablisherFrame, - PCONTEXT ContextRecord, - PDISPATCHER_CONTEXT DispatcherContext) { - EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord }; - if (!CrashReporter::GetInstance()) - return EXCEPTION_CONTINUE_SEARCH; - return static_cast(CrashReporter::GetInstance())-> - CrashForException(&info); -} - -struct ExceptionHandlerRecord { - RUNTIME_FUNCTION runtime_function; - UNWIND_INFO unwind_info; - unsigned char thunk[12]; -}; - -bool RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) { - ExceptionHandlerRecord* record = - reinterpret_cast(start); - - // We assume that the first page of the code range is executable and - // committed and reserved for breakpad. What could possibly go wrong? - - // All addresses are 32bit relative offsets to start. - record->runtime_function.BeginAddress = 0; - record->runtime_function.EndAddress = - base::checked_cast(size_in_bytes); - record->runtime_function.UnwindData = - offsetof(ExceptionHandlerRecord, unwind_info); - - // Create unwind info that only specifies an exception handler. - record->unwind_info.Version = 1; - record->unwind_info.Flags = UNW_FLAG_EHANDLER; - record->unwind_info.SizeOfProlog = 0; - record->unwind_info.CountOfCodes = 0; - record->unwind_info.FrameRegister = 0; - record->unwind_info.FrameOffset = 0; - record->unwind_info.ExceptionHandler = - offsetof(ExceptionHandlerRecord, thunk); - - // Hardcoded thunk. - // mov imm64, rax - record->thunk[0] = 0x48; - record->thunk[1] = 0xb8; - void* handler = &CrashForExceptionInNonABICompliantCodeRange; - memcpy(&record->thunk[2], &handler, 8); - - // jmp rax - record->thunk[10] = 0xff; - record->thunk[11] = 0xe0; - - // Protect reserved page against modifications. - DWORD old_protect; - return VirtualProtect(start, sizeof(ExceptionHandlerRecord), - PAGE_EXECUTE_READ, &old_protect) && - RtlAddFunctionTable(&record->runtime_function, 1, - reinterpret_cast(start)); -} - -void UnregisterNonABICompliantCodeRange(void* start) { - ExceptionHandlerRecord* record = - reinterpret_cast(start); - - RtlDeleteFunctionTable(&record->runtime_function); -} -#endif // _WIN64 - -} // namespace - -CrashReporterWin::CrashReporterWin() - : skip_system_crash_handler_(false), - code_range_registered_(false) { -} - -CrashReporterWin::~CrashReporterWin() { -} - -void CrashReporterWin::InitBreakpad(const std::string& product_name, - const std::string& version, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler) { - skip_system_crash_handler_ = skip_system_crash_handler; - - base::FilePath temp_dir; - if (!base::GetTempDir(&temp_dir)) { - LOG(ERROR) << "Cannot get temp directory"; - return; - } - - base::string16 pipe_name = base::ReplaceStringPlaceholders( - kPipeNameFormat, base::UTF8ToUTF16(product_name), NULL); - base::string16 wait_name = base::ReplaceStringPlaceholders( - kWaitEventFormat, base::UTF8ToUTF16(product_name), NULL); - - // Wait until the crash service is started. - HANDLE wait_event = ::CreateEventW(NULL, TRUE, FALSE, wait_name.c_str()); - if (wait_event != NULL) { - WaitForSingleObject(wait_event, 1000); - CloseHandle(wait_event); - } - - // ExceptionHandler() attaches our handler and ~ExceptionHandler() detaches - // it, so we must explicitly reset *before* we instantiate our new handler - // to allow any previous handler to detach in the correct order. - breakpad_.reset(); - - breakpad_.reset(new google_breakpad::ExceptionHandler( - temp_dir.value(), - FilterCallback, - MinidumpCallback, - this, - google_breakpad::ExceptionHandler::HANDLER_ALL, - kSmallDumpType, - pipe_name.c_str(), - GetCustomInfo(product_name, version, company_name))); - - if (!breakpad_->IsOutOfProcess()) - LOG(ERROR) << "Cannot initialize out-of-process crash handler"; - -#ifdef _WIN64 - // Hook up V8 to breakpad. - if (!code_range_registered_) { - code_range_registered_ = true; - // gin::Debug::SetCodeRangeCreatedCallback only runs the callback when - // Isolate is just created, so we have to manually run following code here. - void* code_range = nullptr; - size_t size = 0; - v8::Isolate::GetCurrent()->GetCodeRange(&code_range, &size); - if (code_range && size && - RegisterNonABICompliantCodeRange(code_range, size)) { - gin::Debug::SetCodeRangeDeletedCallback( - UnregisterNonABICompliantCodeRange); - } - } -#endif -} - -void CrashReporterWin::SetUploadParameters() { - upload_parameters_["platform"] = "win32"; -} - -int CrashReporterWin::CrashForException(EXCEPTION_POINTERS* info) { - if (breakpad_) { - breakpad_->WriteMinidumpForException(info); - TerminateProcessWithoutDump(); - } - return EXCEPTION_CONTINUE_SEARCH; -} - -// static -bool CrashReporterWin::FilterCallback(void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion) { - return true; -} - -// static -bool CrashReporterWin::MinidumpCallback(const wchar_t* dump_path, - const wchar_t* minidump_id, - void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - bool succeeded) { - CrashReporterWin* self = static_cast(context); - if (succeeded && !self->skip_system_crash_handler_) - return true; - else - return false; -} - -google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo( - const std::string& product_name, - const std::string& version, - const std::string& company_name) { - custom_info_entries_.clear(); - custom_info_entries_.reserve(2 + upload_parameters_.size()); - - custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( - L"prod", L"Electron")); - custom_info_entries_.push_back(google_breakpad::CustomInfoEntry( - L"ver", base::UTF8ToWide(version).c_str())); - - for (StringMap::const_iterator iter = upload_parameters_.begin(); - iter != upload_parameters_.end(); ++iter) { - // breakpad has hardcoded the length of name/value, and doesn't truncate - // the values itself, so we have to truncate them here otherwise weird - // things may happen. - std::wstring name = base::UTF8ToWide(iter->first); - std::wstring value = base::UTF8ToWide(iter->second); - if (name.length() > kNameMaxLength - 1) - name.resize(kNameMaxLength - 1); - if (value.length() > kValueMaxLength - 1) - value.resize(kValueMaxLength - 1); - - custom_info_entries_.push_back( - google_breakpad::CustomInfoEntry(name.c_str(), value.c_str())); - } - - custom_info_.entries = &custom_info_entries_.front(); - custom_info_.count = custom_info_entries_.size(); - return &custom_info_; -} - -// static -CrashReporterWin* CrashReporterWin::GetInstance() { - return base::Singleton::get(); -} - -// static -CrashReporter* CrashReporter::GetInstance() { - return CrashReporterWin::GetInstance(); -} - -} // namespace crash_reporter diff --git a/atom/common/crash_reporter/crash_reporter_win.h b/atom/common/crash_reporter/crash_reporter_win.h deleted file mode 100644 index 806c3de317b24..0000000000000 --- a/atom/common/crash_reporter/crash_reporter_win.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_WIN_H_ -#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_WIN_H_ - -#include -#include -#include - -#include "atom/common/crash_reporter/crash_reporter.h" -#include "base/compiler_specific.h" -#include "vendor/breakpad/src/client/windows/handler/exception_handler.h" - -namespace base { -template struct DefaultSingletonTraits; -} - -namespace crash_reporter { - -class CrashReporterWin : public CrashReporter { - public: - static CrashReporterWin* GetInstance(); - - void InitBreakpad(const std::string& product_name, - const std::string& version, - const std::string& company_name, - const std::string& submit_url, - bool auto_submit, - bool skip_system_crash_handler) override; - void SetUploadParameters() override; - - // Crashes the process after generating a dump for the provided exception. - int CrashForException(EXCEPTION_POINTERS* info); - - private: - friend struct base::DefaultSingletonTraits; - - CrashReporterWin(); - virtual ~CrashReporterWin(); - - static bool FilterCallback(void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion); - - static bool MinidumpCallback(const wchar_t* dump_path, - const wchar_t* minidump_id, - void* context, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - bool succeeded); - - // Returns the custom info structure based on parameters. - google_breakpad::CustomClientInfo* GetCustomInfo( - const std::string& product_name, - const std::string& version, - const std::string& company_name); - - // Custom information to be passed to crash handler. - std::vector custom_info_entries_; - google_breakpad::CustomClientInfo custom_info_; - - bool skip_system_crash_handler_; - bool code_range_registered_; - std::unique_ptr breakpad_; - - DISALLOW_COPY_AND_ASSIGN(CrashReporterWin); -}; - -} // namespace crash_reporter - -#endif // ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_WIN_H_ diff --git a/atom/common/crash_reporter/linux/crash_dump_handler.cc b/atom/common/crash_reporter/linux/crash_dump_handler.cc deleted file mode 100644 index 56a5e094d4463..0000000000000 --- a/atom/common/crash_reporter/linux/crash_dump_handler.cc +++ /dev/null @@ -1,746 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -// For linux_syscall_support.h. This makes it safe to call embedded system -// calls when in seccomp mode. - -#include "atom/common/crash_reporter/linux/crash_dump_handler.h" - -#include - -#include - -#include "base/posix/eintr_wrapper.h" -#include "vendor/breakpad/src/client/linux/minidump_writer/directory_reader.h" -#include "vendor/breakpad/src/common/linux/linux_libc_support.h" -#include "vendor/breakpad/src/common/memory.h" - -#include "third_party/lss/linux_syscall_support.h" - -// Some versions of gcc are prone to warn about unused return values. In cases -// where we either a) know the call cannot fail, or b) there is nothing we -// can do when a call fails, we mark the return code as ignored. This avoids -// spurious compiler warnings. -#define IGNORE_RET(x) do { if (x); } while (0) - -namespace crash_reporter { - -namespace { - -// String buffer size to use to convert a uint64_t to string. -const size_t kUint64StringSize = 21; - -// Writes the value |v| as 16 hex characters to the memory pointed at by -// |output|. -void write_uint64_hex(char* output, uint64_t v) { - static const char hextable[] = "0123456789abcdef"; - - for (int i = 15; i >= 0; --i) { - output[i] = hextable[v & 15]; - v >>= 4; - } -} - -// uint64_t version of my_int_len() from -// breakpad/src/common/linux/linux_libc_support.h. Return the length of the -// given, non-negative integer when expressed in base 10. -unsigned my_uint64_len(uint64_t i) { - if (!i) - return 1; - - unsigned len = 0; - while (i) { - len++; - i /= 10; - } - - return len; -} - -// uint64_t version of my_uitos() from -// breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative -// integer to a string (not null-terminated). -void my_uint64tos(char* output, uint64_t i, unsigned i_len) { - for (unsigned index = i_len; index; --index, i /= 10) - output[index - 1] = '0' + (i % 10); -} - -// Converts a struct timeval to milliseconds. -uint64_t kernel_timeval_to_ms(struct kernel_timeval *tv) { - uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t. - ret *= 1000; - ret += tv->tv_usec / 1000; - return ret; -} - -bool my_isxdigit(char c) { - return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f'); -} - -size_t LengthWithoutTrailingSpaces(const char* str, size_t len) { - while (len > 0 && str[len - 1] == ' ') { - len--; - } - return len; -} - -// MIME substrings. -const char g_rn[] = "\r\n"; -const char g_form_data_msg[] = "Content-Disposition: form-data; name=\""; -const char g_quote_msg[] = "\""; -const char g_dashdash_msg[] = "--"; -const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\""; -const char g_content_type_msg[] = "Content-Type: application/octet-stream"; - -// MimeWriter manages an iovec for writing MIMEs to a file. -class MimeWriter { - public: - static const int kIovCapacity = 30; - static const size_t kMaxCrashChunkSize = 64; - - MimeWriter(int fd, const char* const mime_boundary); - ~MimeWriter(); - - // Append boundary. - virtual void AddBoundary(); - - // Append end of file boundary. - virtual void AddEnd(); - - // Append key/value pair with specified sizes. - virtual void AddPairData(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size); - - // Append key/value pair. - void AddPairString(const char* msg_type, - const char* msg_data) { - AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data)); - } - - // Append key/value pair, splitting value into chunks no larger than - // |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|. - // The msg_type string will have a counter suffix to distinguish each chunk. - virtual void AddPairDataInChunks(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size, - size_t chunk_size, - bool strip_trailing_spaces); - - // Add binary file contents to be uploaded with the specified filename. - virtual void AddFileContents(const char* filename_msg, - uint8_t* file_data, - size_t file_size); - - // Flush any pending iovecs to the output file. - void Flush() { - IGNORE_RET(sys_writev(fd_, iov_, iov_index_)); - iov_index_ = 0; - } - - protected: - void AddItem(const void* base, size_t size); - // Minor performance trade-off for easier-to-maintain code. - void AddString(const char* str) { - AddItem(str, my_strlen(str)); - } - void AddItemWithoutTrailingSpaces(const void* base, size_t size); - - struct kernel_iovec iov_[kIovCapacity]; - int iov_index_; - - // Output file descriptor. - int fd_; - - const char* const mime_boundary_; - - private: - DISALLOW_COPY_AND_ASSIGN(MimeWriter); -}; - -MimeWriter::MimeWriter(int fd, const char* const mime_boundary) - : iov_index_(0), - fd_(fd), - mime_boundary_(mime_boundary) { -} - -MimeWriter::~MimeWriter() { -} - -void MimeWriter::AddBoundary() { - AddString(mime_boundary_); - AddString(g_rn); -} - -void MimeWriter::AddEnd() { - AddString(mime_boundary_); - AddString(g_dashdash_msg); - AddString(g_rn); -} - -void MimeWriter::AddPairData(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size) { - AddString(g_form_data_msg); - AddItem(msg_type, msg_type_size); - AddString(g_quote_msg); - AddString(g_rn); - AddString(g_rn); - AddItem(msg_data, msg_data_size); - AddString(g_rn); -} - -void MimeWriter::AddPairDataInChunks(const char* msg_type, - size_t msg_type_size, - const char* msg_data, - size_t msg_data_size, - size_t chunk_size, - bool strip_trailing_spaces) { - if (chunk_size > kMaxCrashChunkSize) - return; - - unsigned i = 0; - size_t done = 0, msg_length = msg_data_size; - - while (msg_length) { - char num[kUint64StringSize]; - const unsigned num_len = my_uint_len(++i); - my_uitos(num, i, num_len); - - size_t chunk_len = std::min(chunk_size, msg_length); - - AddString(g_form_data_msg); - AddItem(msg_type, msg_type_size); - AddItem(num, num_len); - AddString(g_quote_msg); - AddString(g_rn); - AddString(g_rn); - if (strip_trailing_spaces) { - AddItemWithoutTrailingSpaces(msg_data + done, chunk_len); - } else { - AddItem(msg_data + done, chunk_len); - } - AddString(g_rn); - AddBoundary(); - Flush(); - - done += chunk_len; - msg_length -= chunk_len; - } -} - -void MimeWriter::AddFileContents(const char* filename_msg, uint8_t* file_data, - size_t file_size) { - AddString(g_form_data_msg); - AddString(filename_msg); - AddString(g_rn); - AddString(g_content_type_msg); - AddString(g_rn); - AddString(g_rn); - AddItem(file_data, file_size); - AddString(g_rn); -} - -void MimeWriter::AddItem(const void* base, size_t size) { - // Check if the iovec is full and needs to be flushed to output file. - if (iov_index_ == kIovCapacity) { - Flush(); - } - iov_[iov_index_].iov_base = const_cast(base); - iov_[iov_index_].iov_len = size; - ++iov_index_; -} - -void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) { - AddItem(base, LengthWithoutTrailingSpaces(static_cast(base), - size)); -} - -void LoadDataFromFD(google_breakpad::PageAllocator* allocator, - int fd, bool close_fd, uint8_t** file_data, size_t* size) { - struct kernel_stat st; - if (sys_fstat(fd, &st) != 0) { - static const char msg[] = "Cannot upload crash dump: stat failed\n"; - WriteLog(msg, sizeof(msg) - 1); - if (close_fd) - IGNORE_RET(sys_close(fd)); - return; - } - - *file_data = reinterpret_cast(allocator->Alloc(st.st_size)); - if (!(*file_data)) { - static const char msg[] = "Cannot upload crash dump: cannot alloc\n"; - WriteLog(msg, sizeof(msg) - 1); - if (close_fd) - IGNORE_RET(sys_close(fd)); - return; - } - my_memset(*file_data, 0xf, st.st_size); - - *size = st.st_size; - int byte_read = sys_read(fd, *file_data, *size); - if (byte_read == -1) { - static const char msg[] = "Cannot upload crash dump: read failed\n"; - WriteLog(msg, sizeof(msg) - 1); - if (close_fd) - IGNORE_RET(sys_close(fd)); - return; - } - - if (close_fd) - IGNORE_RET(sys_close(fd)); -} - -void LoadDataFromFile(google_breakpad::PageAllocator* allocator, - const char* filename, - int* fd, uint8_t** file_data, size_t* size) { - // WARNING: this code runs in a compromised context. It may not call into - // libc nor allocate memory normally. - *fd = sys_open(filename, O_RDONLY, 0); - *size = 0; - - if (*fd < 0) { - static const char msg[] = "Cannot upload crash dump: failed to open\n"; - WriteLog(msg, sizeof(msg) - 1); - return; - } - - LoadDataFromFD(allocator, *fd, true, file_data, size); -} - -// Spawn the appropriate upload process for the current OS: -// - generic Linux invokes wget. -// - ChromeOS invokes crash_reporter. -// |dumpfile| is the path to the dump data file. -// |mime_boundary| is only used on Linux. -// |exe_buf| is only used on CrOS and is the crashing process' name. -void ExecUploadProcessOrTerminate(const BreakpadInfo& info, - const char* dumpfile, - const char* mime_boundary, - const char* exe_buf, - google_breakpad::PageAllocator* allocator) { - // The --header argument to wget looks like: - // --header=Content-Type: multipart/form-data; boundary=XYZ - // where the boundary has two fewer leading '-' chars - static const char header_msg[] = - "--header=Content-Type: multipart/form-data; boundary="; - char* const header = reinterpret_cast(allocator->Alloc( - sizeof(header_msg) - 1 + strlen(mime_boundary) - 2 + 1)); - memcpy(header, header_msg, sizeof(header_msg) - 1); - memcpy(header + sizeof(header_msg) - 1, mime_boundary + 2, - strlen(mime_boundary) - 2); - // We grab the NUL byte from the end of |mime_boundary|. - - // The --post-file argument to wget looks like: - // --post-file=/tmp/... - static const char post_file_msg[] = "--post-file="; - char* const post_file = reinterpret_cast(allocator->Alloc( - sizeof(post_file_msg) - 1 + strlen(dumpfile) + 1)); - memcpy(post_file, post_file_msg, sizeof(post_file_msg) - 1); - memcpy(post_file + sizeof(post_file_msg) - 1, dumpfile, strlen(dumpfile)); - - static const char kWgetBinary[] = "/usr/bin/wget"; - const char* args[] = { - kWgetBinary, - header, - post_file, - info.upload_url, - "--timeout=60", // Set a timeout so we don't hang forever. - "--tries=1", // Don't retry if the upload fails. - "--quiet", // Be silent. - "-O", // output reply to /dev/null. - "/dev/fd/3", - NULL, - }; - static const char msg[] = "Cannot upload crash dump: cannot exec " - "/usr/bin/wget\n"; - execve(args[0], const_cast(args), environ); - WriteLog(msg, sizeof(msg) - 1); - sys__exit(1); -} - -// Runs in the helper process to wait for the upload process running -// ExecUploadProcessOrTerminate() to finish. Returns the number of bytes written -// to |fd| and save the written contents to |buf|. -// |buf| needs to be big enough to hold |bytes_to_read| + 1 characters. -size_t WaitForCrashReportUploadProcess(int fd, size_t bytes_to_read, - char* buf) { - size_t bytes_read = 0; - - // Upload should finish in about 10 seconds. Add a few more 500 ms - // internals to account for process startup time. - for (size_t wait_count = 0; wait_count < 24; ++wait_count) { - struct kernel_pollfd poll_fd; - poll_fd.fd = fd; - poll_fd.events = POLLIN | POLLPRI | POLLERR; - int ret = sys_poll(&poll_fd, 1, 500); - if (ret < 0) { - // Error - break; - } else if (ret > 0) { - // There is data to read. - ssize_t len = HANDLE_EINTR( - sys_read(fd, buf + bytes_read, bytes_to_read - bytes_read)); - if (len < 0) - break; - bytes_read += len; - if (bytes_read == bytes_to_read) - break; - } - // |ret| == 0 -> timed out, continue waiting. - // or |bytes_read| < |bytes_to_read| still, keep reading. - } - buf[bytes_to_read] = 0; // Always NUL terminate the buffer. - return bytes_read; -} - -// |buf| should be |expected_len| + 1 characters in size and NULL terminated. -bool IsValidCrashReportId(const char* buf, size_t bytes_read, - size_t expected_len) { - if (bytes_read != expected_len) - return false; - for (size_t i = 0; i < bytes_read; ++i) { - if (!my_isxdigit(buf[i]) && buf[i] != '-') - return false; - } - return true; -} - -// |buf| should be |expected_len| + 1 characters in size and NULL terminated. -void HandleCrashReportId(const char* buf, size_t bytes_read, - size_t expected_len) { - if (!IsValidCrashReportId(buf, bytes_read, expected_len)) { - static const char msg[] = "Failed to get crash dump id."; - WriteLog(msg, sizeof(msg) - 1); - WriteNewline(); - - static const char id_msg[] = "Report Id: "; - WriteLog(id_msg, sizeof(id_msg) - 1); - WriteLog(buf, bytes_read); - WriteNewline(); - return; - } - - // Write crash dump id to stderr. - static const char msg[] = "Crash dump id: "; - WriteLog(msg, sizeof(msg) - 1); - WriteLog(buf, my_strlen(buf)); - WriteNewline(); - - // Write crash dump id to crash log as: seconds_since_epoch,crash_id - struct kernel_timeval tv; - if (!sys_gettimeofday(&tv, NULL)) { - uint64_t time = kernel_timeval_to_ms(&tv) / 1000; - char time_str[kUint64StringSize]; - const unsigned time_len = my_uint64_len(time); - my_uint64tos(time_str, time, time_len); - - const int kLogOpenFlags = O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC; - int log_fd = sys_open(g_crash_log_path, kLogOpenFlags, 0600); - if (log_fd > 0) { - sys_write(log_fd, time_str, time_len); - sys_write(log_fd, ",", 1); - sys_write(log_fd, buf, my_strlen(buf)); - sys_write(log_fd, "\n", 1); - IGNORE_RET(sys_close(log_fd)); - } - } -} - -} // namespace - -char g_crash_log_path[256]; - -void HandleCrashDump(const BreakpadInfo& info) { - int dumpfd; - bool keep_fd = false; - size_t dump_size; - uint8_t* dump_data; - google_breakpad::PageAllocator allocator; - const char* exe_buf = NULL; - - if (info.fd != -1) { - // Dump is provided with an open FD. - keep_fd = true; - dumpfd = info.fd; - - // The FD is pointing to the end of the file. - // Rewind, we'll read the data next. - if (lseek(dumpfd, 0, SEEK_SET) == -1) { - static const char msg[] = "Cannot upload crash dump: failed to " - "reposition minidump FD\n"; - WriteLog(msg, sizeof(msg) - 1); - IGNORE_RET(sys_close(dumpfd)); - return; - } - LoadDataFromFD(&allocator, info.fd, false, &dump_data, &dump_size); - } else { - // Dump is provided with a path. - keep_fd = false; - LoadDataFromFile( - &allocator, info.filename, &dumpfd, &dump_data, &dump_size); - } - - // We need to build a MIME block for uploading to the server. Since we are - // going to fork and run wget, it needs to be written to a temp file. - const int ufd = sys_open("/dev/urandom", O_RDONLY, 0); - if (ufd < 0) { - static const char msg[] = "Cannot upload crash dump because /dev/urandom" - " is missing\n"; - WriteLog(msg, sizeof(msg) - 1); - return; - } - - static const char temp_file_template[] = - "/tmp/chromium-upload-XXXXXXXXXXXXXXXX"; - char temp_file[sizeof(temp_file_template)]; - int temp_file_fd = -1; - if (keep_fd) { - temp_file_fd = dumpfd; - // Rewind the destination, we are going to overwrite it. - if (lseek(dumpfd, 0, SEEK_SET) == -1) { - static const char msg[] = "Cannot upload crash dump: failed to " - "reposition minidump FD (2)\n"; - WriteLog(msg, sizeof(msg) - 1); - IGNORE_RET(sys_close(dumpfd)); - return; - } - } else { - if (info.upload) { - memcpy(temp_file, temp_file_template, sizeof(temp_file_template)); - - for (unsigned i = 0; i < 10; ++i) { - uint64_t t; - sys_read(ufd, &t, sizeof(t)); - write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t); - - temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (temp_file_fd >= 0) - break; - } - - if (temp_file_fd < 0) { - static const char msg[] = "Failed to create temporary file in /tmp: " - "cannot upload crash dump\n"; - WriteLog(msg, sizeof(msg) - 1); - IGNORE_RET(sys_close(ufd)); - return; - } - } else { - temp_file_fd = sys_open(info.filename, O_WRONLY, 0600); - if (temp_file_fd < 0) { - static const char msg[] = "Failed to save crash dump: failed to open\n"; - WriteLog(msg, sizeof(msg) - 1); - IGNORE_RET(sys_close(ufd)); - return; - } - } - } - - // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL. - char mime_boundary[28 + 16 + 1]; - my_memset(mime_boundary, '-', 28); - uint64_t boundary_rand; - sys_read(ufd, &boundary_rand, sizeof(boundary_rand)); - write_uint64_hex(mime_boundary + 28, boundary_rand); - mime_boundary[28 + 16] = 0; - IGNORE_RET(sys_close(ufd)); - - // The MIME block looks like this: - // BOUNDARY \r\n - // Content-Disposition: form-data; name="prod" \r\n \r\n - // Chrome_Linux \r\n - // BOUNDARY \r\n - // Content-Disposition: form-data; name="ver" \r\n \r\n - // 1.2.3.4 \r\n - // BOUNDARY \r\n - // - // zero or one: - // Content-Disposition: form-data; name="ptime" \r\n \r\n - // abcdef \r\n - // BOUNDARY \r\n - // - // zero or one: - // Content-Disposition: form-data; name="ptype" \r\n \r\n - // abcdef \r\n - // BOUNDARY \r\n - // - // zero or one: - // Content-Disposition: form-data; name="lsb-release" \r\n \r\n - // abcdef \r\n - // BOUNDARY \r\n - // - // zero or one: - // Content-Disposition: form-data; name="oom-size" \r\n \r\n - // 1234567890 \r\n - // BOUNDARY \r\n - // - // zero or more (up to CrashKeyStorage::num_entries = 64): - // Content-Disposition: form-data; name=crash-key-name \r\n - // crash-key-value \r\n - // BOUNDARY \r\n - // - // Content-Disposition: form-data; name="dump"; filename="dump" \r\n - // Content-Type: application/octet-stream \r\n \r\n - // - // \r\n BOUNDARY -- \r\n - - MimeWriter writer(temp_file_fd, mime_boundary); - { - writer.AddBoundary(); - if (info.pid > 0) { - char pid_value_buf[kUint64StringSize]; - uint64_t pid_value_len = my_uint64_len(info.pid); - my_uint64tos(pid_value_buf, info.pid, pid_value_len); - static const char pid_key_name[] = "pid"; - writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1, - pid_value_buf, pid_value_len); - writer.AddBoundary(); - } - writer.Flush(); - } - - if (info.process_start_time > 0) { - struct kernel_timeval tv; - if (!sys_gettimeofday(&tv, NULL)) { - uint64_t time = kernel_timeval_to_ms(&tv); - if (time > info.process_start_time) { - time -= info.process_start_time; - char time_str[kUint64StringSize]; - const unsigned time_len = my_uint64_len(time); - my_uint64tos(time_str, time, time_len); - - static const char process_time_msg[] = "ptime"; - writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1, - time_str, time_len); - writer.AddBoundary(); - writer.Flush(); - } - } - } - - if (info.distro_length) { - static const char distro_msg[] = "lsb-release"; - writer.AddPairString(distro_msg, info.distro); - writer.AddBoundary(); - writer.Flush(); - } - - if (info.oom_size) { - char oom_size_str[kUint64StringSize]; - const unsigned oom_size_len = my_uint64_len(info.oom_size); - my_uint64tos(oom_size_str, info.oom_size, oom_size_len); - static const char oom_size_msg[] = "oom-size"; - writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1, - oom_size_str, oom_size_len); - writer.AddBoundary(); - writer.Flush(); - } - - if (info.crash_keys) { - CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys); - const CrashKeyStorage::Entry* entry; - while ((entry = crash_key_iterator.Next())) { - writer.AddPairString(entry->key, entry->value); - writer.AddBoundary(); - writer.Flush(); - } - } - - writer.AddFileContents(g_dump_msg, dump_data, dump_size); - writer.AddEnd(); - writer.Flush(); - - IGNORE_RET(sys_close(temp_file_fd)); - - if (!info.upload) - return; - - const pid_t child = sys_fork(); - if (!child) { - // Spawned helper process. - // - // This code is called both when a browser is crashing (in which case, - // nothing really matters any more) and when a renderer/plugin crashes, in - // which case we need to continue. - // - // Since we are a multithreaded app, if we were just to fork(), we might - // grab file descriptors which have just been created in another thread and - // hold them open for too long. - // - // Thus, we have to loop and try and close everything. - const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0); - if (fd < 0) { - for (unsigned i = 3; i < 8192; ++i) - IGNORE_RET(sys_close(i)); - } else { - google_breakpad::DirectoryReader reader(fd); - const char* name; - while (reader.GetNextEntry(&name)) { - int i; - if (my_strtoui(&i, name) && i > 2 && i != fd) - IGNORE_RET(sys_close(i)); - reader.PopEntry(); - } - - IGNORE_RET(sys_close(fd)); - } - - IGNORE_RET(sys_setsid()); - - // Leave one end of a pipe in the upload process and watch for it getting - // closed by the upload process exiting. - int fds[2]; - if (sys_pipe(fds) >= 0) { - const pid_t upload_child = sys_fork(); - if (!upload_child) { - // Upload process. - IGNORE_RET(sys_close(fds[0])); - IGNORE_RET(sys_dup2(fds[1], 3)); - ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf, - &allocator); - } - - // Helper process. - if (upload_child > 0) { - IGNORE_RET(sys_close(fds[1])); - - const size_t kCrashIdLength = 36; - char id_buf[kCrashIdLength + 1]; - size_t bytes_read = - WaitForCrashReportUploadProcess(fds[0], kCrashIdLength, id_buf); - HandleCrashReportId(id_buf, bytes_read, kCrashIdLength); - - if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) { - // Upload process is still around, kill it. - sys_kill(upload_child, SIGKILL); - } - } - } - - // Helper process. - IGNORE_RET(sys_unlink(info.filename)); - IGNORE_RET(sys_unlink(temp_file)); - sys__exit(0); - } - - // Main browser process. - if (child <= 0) - return; - (void) HANDLE_EINTR(sys_waitpid(child, NULL, 0)); -} - -size_t WriteLog(const char* buf, size_t nbytes) { - return sys_write(2, buf, nbytes); -} - -size_t WriteNewline() { - return WriteLog("\n", 1); -} - -} // namespace crash_reporter diff --git a/atom/common/crash_reporter/linux/crash_dump_handler.h b/atom/common/crash_reporter/linux/crash_dump_handler.h deleted file mode 100644 index f10c5212254ea..0000000000000 --- a/atom/common/crash_reporter/linux/crash_dump_handler.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_CRASH_REPORTER_LINUX_CRASH_DUMP_HANDLER_H_ -#define ATOM_COMMON_CRASH_REPORTER_LINUX_CRASH_DUMP_HANDLER_H_ - -#include -#include -#include - -#include "base/macros.h" -#include "vendor/breakpad/src/common/simple_string_dictionary.h" - -namespace crash_reporter { - -typedef google_breakpad::NonAllocatingMap<256, 256, 64> CrashKeyStorage; - -// BreakpadInfo describes a crash report. -// The minidump information can either be contained in a file descriptor (fd) or -// in a file (whose path is in filename). -struct BreakpadInfo { - int fd; // File descriptor to the Breakpad dump data. - const char* filename; // Path to the Breakpad dump data. - const char* distro; // Linux distro string. - unsigned distro_length; // Length of |distro|. - bool upload; // Whether to upload or save crash dump. - uint64_t process_start_time; // Uptime of the crashing process. - size_t oom_size; // Amount of memory requested if OOM. - uint64_t pid; // PID where applicable. - const char* upload_url; // URL to upload the minidump. - CrashKeyStorage* crash_keys; -}; - -void HandleCrashDump(const BreakpadInfo& info); - -size_t WriteLog(const char* buf, size_t nbytes); -size_t WriteNewline(); - -// Global variable storing the path of upload log. -extern char g_crash_log_path[256]; - -} // namespace crash_reporter - -#endif // ATOM_COMMON_CRASH_REPORTER_LINUX_CRASH_DUMP_HANDLER_H_ diff --git a/atom/common/crash_reporter/win/crash_service.cc b/atom/common/crash_reporter/win/crash_service.cc deleted file mode 100644 index 5782fd72a3fba..0000000000000 --- a/atom/common/crash_reporter/win/crash_service.cc +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/crash_reporter/win/crash_service.h" - -#include - -#include -#include // NOLINT -#include - -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/time/time.h" -#include "base/win/windows_version.h" -#include "vendor/breakpad/src/client/windows/crash_generation/client_info.h" -#include "vendor/breakpad/src/client/windows/crash_generation/crash_generation_server.h" -#include "vendor/breakpad/src/client/windows/sender/crash_report_sender.h" - -namespace breakpad { - -namespace { - -const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent"; -const wchar_t kClassNameFormat[] = L"$1CrashServiceWindow"; - -const wchar_t kTestPipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; - -const wchar_t kGoogleReportURL[] = L"https://clients2.google.com/cr/report"; -const wchar_t kCheckPointFile[] = L"crash_checkpoint.txt"; - -typedef std::map CrashMap; - -bool CustomInfoToMap(const google_breakpad::ClientInfo* client_info, - const std::wstring& reporter_tag, CrashMap* map) { - google_breakpad::CustomClientInfo info = client_info->GetCustomInfo(); - - for (uintptr_t i = 0; i < info.count; ++i) { - (*map)[info.entries[i].name] = info.entries[i].value; - } - - (*map)[L"rept"] = reporter_tag; - - return !map->empty(); -} - -bool WriteCustomInfoToFile(const std::wstring& dump_path, const CrashMap& map) { - std::wstring file_path(dump_path); - size_t last_dot = file_path.rfind(L'.'); - if (last_dot == std::wstring::npos) - return false; - file_path.resize(last_dot); - file_path += L".txt"; - - std::wofstream file(file_path.c_str(), - std::ios_base::out | std::ios_base::app | std::ios::binary); - if (!file.is_open()) - return false; - - CrashMap::const_iterator pos; - for (pos = map.begin(); pos != map.end(); ++pos) { - std::wstring line = pos->first; - line += L':'; - line += pos->second; - line += L'\n'; - file.write(line.c_str(), static_cast(line.length())); - } - return true; -} - -bool WriteReportIDToFile(const std::wstring& dump_path, - const std::wstring& report_id) { - std::wstring file_path(dump_path); - size_t last_slash = file_path.rfind(L'\\'); - if (last_slash == std::wstring::npos) - return false; - file_path.resize(last_slash); - file_path += L"\\uploads.log"; - - std::wofstream file(file_path.c_str(), - std::ios_base::out | std::ios_base::app | std::ios::binary); - if (!file.is_open()) - return false; - - int64_t seconds_since_epoch = - (base::Time::Now() - base::Time::UnixEpoch()).InSeconds(); - std::wstring line = base::Int64ToString16(seconds_since_epoch); - line += L','; - line += report_id; - line += L'\n'; - file.write(line.c_str(), static_cast(line.length())); - return true; -} - -// The window procedure task is to handle when a) the user logs off. -// b) the system shuts down or c) when the user closes the window. -LRESULT __stdcall CrashSvcWndProc(HWND hwnd, UINT message, - WPARAM wparam, LPARAM lparam) { - switch (message) { - case WM_CLOSE: - case WM_ENDSESSION: - case WM_DESTROY: - PostQuitMessage(0); - break; - default: - return DefWindowProc(hwnd, message, wparam, lparam); - } - return 0; -} - -// This is the main and only application window. -HWND g_top_window = NULL; - -bool CreateTopWindow(HINSTANCE instance, - const base::string16& application_name, - bool visible) { - base::string16 class_name = base::ReplaceStringPlaceholders( - kClassNameFormat, application_name, NULL); - - WNDCLASSEXW wcx = {0}; - wcx.cbSize = sizeof(wcx); - wcx.style = CS_HREDRAW | CS_VREDRAW; - wcx.lpfnWndProc = CrashSvcWndProc; - wcx.hInstance = instance; - wcx.lpszClassName = class_name.c_str(); - ATOM atom = ::RegisterClassExW(&wcx); - DWORD style = visible ? WS_POPUPWINDOW | WS_VISIBLE : WS_OVERLAPPED; - - // The window size is zero but being a popup window still shows in the - // task bar and can be closed using the system menu or using task manager. - HWND window = CreateWindowExW(0, wcx.lpszClassName, L"crash service", style, - CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, - NULL, NULL, instance, NULL); - if (!window) - return false; - - ::UpdateWindow(window); - VLOG(1) << "window handle is " << window; - g_top_window = window; - return true; -} - -// Simple helper class to keep the process alive until the current request -// finishes. -class ProcessingLock { - public: - ProcessingLock() { - ::InterlockedIncrement(&op_count_); - } - ~ProcessingLock() { - ::InterlockedDecrement(&op_count_); - } - static bool IsWorking() { - return (op_count_ != 0); - } - private: - static volatile LONG op_count_; -}; - -volatile LONG ProcessingLock::op_count_ = 0; - -// This structure contains the information that the worker thread needs to -// send a crash dump to the server. -struct DumpJobInfo { - DWORD pid; - CrashService* self; - CrashMap map; - std::wstring dump_path; - - DumpJobInfo(DWORD process_id, CrashService* service, - const CrashMap& crash_map, const std::wstring& path) - : pid(process_id), self(service), map(crash_map), dump_path(path) { - } -}; - -} // namespace - -// Command line switches: -const char CrashService::kMaxReports[] = "max-reports"; -const char CrashService::kNoWindow[] = "no-window"; -const char CrashService::kReporterTag[] = "reporter"; -const char CrashService::kDumpsDir[] = "dumps-dir"; -const char CrashService::kPipeName[] = "pipe-name"; -const char CrashService::kReporterURL[] = "reporter-url"; - -CrashService::CrashService() - : sender_(NULL), - dumper_(NULL), - requests_handled_(0), - requests_sent_(0), - clients_connected_(0), - clients_terminated_(0) { -} - -CrashService::~CrashService() { - base::AutoLock lock(sending_); - delete dumper_; - delete sender_; -} - -bool CrashService::Initialize(const base::string16& application_name, - const base::FilePath& operating_dir, - const base::FilePath& dumps_path) { - using google_breakpad::CrashReportSender; - using google_breakpad::CrashGenerationServer; - - std::wstring pipe_name = kTestPipeName; - int max_reports = -1; - - // The checkpoint file allows CrashReportSender to enforce the maximum - // reports per day quota. Does not seem to serve any other purpose. - base::FilePath checkpoint_path = operating_dir.Append(kCheckPointFile); - - base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess(); - - base::FilePath dumps_path_to_use = dumps_path; - - if (cmd_line.HasSwitch(kDumpsDir)) { - dumps_path_to_use = - base::FilePath(cmd_line.GetSwitchValueNative(kDumpsDir)); - } - - // We can override the send reports quota with a command line switch. - if (cmd_line.HasSwitch(kMaxReports)) - max_reports = _wtoi(cmd_line.GetSwitchValueNative(kMaxReports).c_str()); - - // Allow the global pipe name to be overridden for better testability. - if (cmd_line.HasSwitch(kPipeName)) - pipe_name = cmd_line.GetSwitchValueNative(kPipeName); - - if (max_reports > 0) { - // Create the http sender object. - sender_ = new CrashReportSender(checkpoint_path.value()); - sender_->set_max_reports_per_day(max_reports); - } - - SECURITY_ATTRIBUTES security_attributes = {0}; - SECURITY_DESCRIPTOR* security_descriptor = - reinterpret_cast( - GetSecurityDescriptorForLowIntegrity()); - DCHECK(security_descriptor != NULL); - - security_attributes.nLength = sizeof(security_attributes); - security_attributes.lpSecurityDescriptor = security_descriptor; - security_attributes.bInheritHandle = FALSE; - - // Create the OOP crash generator object. - dumper_ = new CrashGenerationServer(pipe_name, &security_attributes, - &CrashService::OnClientConnected, this, - &CrashService::OnClientDumpRequest, this, - &CrashService::OnClientExited, this, - NULL, NULL, - true, &dumps_path_to_use.value()); - - if (!dumper_) { - LOG(ERROR) << "could not create dumper"; - if (security_attributes.lpSecurityDescriptor) - LocalFree(security_attributes.lpSecurityDescriptor); - return false; - } - - if (!CreateTopWindow(::GetModuleHandleW(NULL), - application_name, - !cmd_line.HasSwitch(kNoWindow))) { - LOG(ERROR) << "could not create window"; - if (security_attributes.lpSecurityDescriptor) - LocalFree(security_attributes.lpSecurityDescriptor); - return false; - } - - reporter_tag_ = L"crash svc"; - if (cmd_line.HasSwitch(kReporterTag)) - reporter_tag_ = cmd_line.GetSwitchValueNative(kReporterTag); - - reporter_url_ = kGoogleReportURL; - if (cmd_line.HasSwitch(kReporterURL)) - reporter_url_ = cmd_line.GetSwitchValueNative(kReporterURL); - - // Log basic information. - VLOG(1) << "pipe name is " << pipe_name - << "\ndumps at " << dumps_path_to_use.value(); - - if (sender_) { - VLOG(1) << "checkpoint is " << checkpoint_path.value() - << "\nserver is " << reporter_url_ - << "\nmaximum " << sender_->max_reports_per_day() << " reports/day" - << "\nreporter is " << reporter_tag_; - } - // Start servicing clients. - if (!dumper_->Start()) { - LOG(ERROR) << "could not start dumper"; - if (security_attributes.lpSecurityDescriptor) - LocalFree(security_attributes.lpSecurityDescriptor); - return false; - } - - if (security_attributes.lpSecurityDescriptor) - LocalFree(security_attributes.lpSecurityDescriptor); - - // Create or open an event to signal the browser process that the crash - // service is initialized. - base::string16 wait_name = base::ReplaceStringPlaceholders( - kWaitEventFormat, application_name, NULL); - HANDLE wait_event = ::CreateEventW(NULL, TRUE, TRUE, wait_name.c_str()); - ::SetEvent(wait_event); - - return true; -} - -void CrashService::OnClientConnected(void* context, - const google_breakpad::ClientInfo* client_info) { - ProcessingLock lock; - VLOG(1) << "client start. pid = " << client_info->pid(); - CrashService* self = static_cast(context); - ::InterlockedIncrement(&self->clients_connected_); -} - -void CrashService::OnClientExited(void* context, - const google_breakpad::ClientInfo* client_info) { - ProcessingLock processing_lock; - VLOG(1) << "client end. pid = " << client_info->pid(); - CrashService* self = static_cast(context); - ::InterlockedIncrement(&self->clients_terminated_); - - if (!self->sender_) - return; - - // When we are instructed to send reports we need to exit if there are - // no more clients to service. The next client that runs will start us. - // Only chrome.exe starts crash_service with a non-zero max_reports. - if (self->clients_connected_ > self->clients_terminated_) - return; - if (self->sender_->max_reports_per_day() > 0) { - // Wait for the other thread to send crashes, if applicable. The sender - // thread takes the sending_ lock, so the sleep is just to give it a - // chance to start. - ::Sleep(1000); - base::AutoLock lock(self->sending_); - // Some people can restart chrome very fast, check again if we have - // a new client before exiting for real. - if (self->clients_connected_ == self->clients_terminated_) { - VLOG(1) << "zero clients. exiting"; - ::PostMessage(g_top_window, WM_CLOSE, 0, 0); - } - } -} - -void CrashService::OnClientDumpRequest(void* context, - const google_breakpad::ClientInfo* client_info, - const std::wstring* file_path) { - ProcessingLock lock; - - if (!file_path) { - LOG(ERROR) << "dump with no file path"; - return; - } - if (!client_info) { - LOG(ERROR) << "dump with no client info"; - return; - } - - CrashService* self = static_cast(context); - if (!self) { - LOG(ERROR) << "dump with no context"; - return; - } - - CrashMap map; - CustomInfoToMap(client_info, self->reporter_tag_, &map); - - // Move dump file to the directory under client breakpad dump location. - base::FilePath dump_location = base::FilePath(*file_path); - CrashMap::const_iterator it = map.find(L"breakpad-dump-location"); - if (it != map.end()) { - base::FilePath alternate_dump_location = base::FilePath(it->second); - base::CreateDirectoryW(alternate_dump_location); - alternate_dump_location = alternate_dump_location.Append( - dump_location.BaseName()); - base::Move(dump_location, alternate_dump_location); - dump_location = alternate_dump_location; - } - - DWORD pid = client_info->pid(); - VLOG(1) << "dump for pid = " << pid << " is " << dump_location.value(); - - if (!WriteCustomInfoToFile(dump_location.value(), map)) { - LOG(ERROR) << "could not write custom info file"; - } - - if (!self->sender_) - return; - - // Send the crash dump using a worker thread. This operation has retry - // logic in case there is no internet connection at the time. - DumpJobInfo* dump_job = new DumpJobInfo(pid, self, map, - dump_location.value()); - if (!::QueueUserWorkItem(&CrashService::AsyncSendDump, - dump_job, WT_EXECUTELONGFUNCTION)) { - LOG(ERROR) << "could not queue job"; - } -} - -// We are going to try sending the report several times. If we can't send, -// we sleep from one minute to several hours depending on the retry round. -DWORD CrashService::AsyncSendDump(void* context) { - if (!context) - return 0; - - DumpJobInfo* info = static_cast(context); - - std::wstring report_id = L""; - - const DWORD kOneMinute = 60*1000; - const DWORD kOneHour = 60*kOneMinute; - - const DWORD kSleepSchedule[] = { - 24*kOneHour, - 8*kOneHour, - 4*kOneHour, - kOneHour, - 15*kOneMinute, - 0}; - - int retry_round = arraysize(kSleepSchedule) - 1; - - do { - ::Sleep(kSleepSchedule[retry_round]); - { - // Take the server lock while sending. This also prevent early - // termination of the service object. - base::AutoLock lock(info->self->sending_); - VLOG(1) << "trying to send report for pid = " << info->pid; - std::map file_map; - file_map[L"upload_file_minidump"] = info->dump_path; - google_breakpad::ReportResult send_result - = info->self->sender_->SendCrashReport(info->self->reporter_url_, - info->map, - file_map, - &report_id); - switch (send_result) { - case google_breakpad::RESULT_FAILED: - report_id = L""; - break; - case google_breakpad::RESULT_REJECTED: - report_id = L""; - ++info->self->requests_handled_; - retry_round = 0; - break; - case google_breakpad::RESULT_SUCCEEDED: - ++info->self->requests_sent_; - ++info->self->requests_handled_; - retry_round = 0; - WriteReportIDToFile(info->dump_path, report_id); - break; - case google_breakpad::RESULT_THROTTLED: - report_id = L""; - break; - default: - report_id = L""; - break; - } - } - - VLOG(1) << "dump for pid =" << info->pid << " crash2 id =" << report_id; - --retry_round; - } while (retry_round >= 0); - - if (!::DeleteFileW(info->dump_path.c_str())) - LOG(WARNING) << "could not delete " << info->dump_path; - - delete info; - return 0; -} - -int CrashService::ProcessingLoop() { - MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - VLOG(1) << "session ending.."; - while (ProcessingLock::IsWorking()) { - ::Sleep(50); - } - - VLOG(1) << "clients connected :" << clients_connected_ - << "\nclients terminated :" << clients_terminated_ - << "\ndumps serviced :" << requests_handled_ - << "\ndumps reported :" << requests_sent_; - - return static_cast(msg.wParam); -} - -PSECURITY_DESCRIPTOR CrashService::GetSecurityDescriptorForLowIntegrity() { - // Build the SDDL string for the label. - std::wstring sddl = L"S:(ML;;NW;;;S-1-16-4096)"; - - DWORD error = ERROR_SUCCESS; - PSECURITY_DESCRIPTOR sec_desc = NULL; - - PACL sacl = NULL; - BOOL sacl_present = FALSE; - BOOL sacl_defaulted = FALSE; - - if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl.c_str(), - SDDL_REVISION, - &sec_desc, NULL)) { - if (::GetSecurityDescriptorSacl(sec_desc, &sacl_present, &sacl, - &sacl_defaulted)) { - return sec_desc; - } - } - - return NULL; -} - -} // namespace breakpad diff --git a/atom/common/crash_reporter/win/crash_service.h b/atom/common/crash_reporter/win/crash_service.h deleted file mode 100644 index c05e0d5bf6e45..0000000000000 --- a/atom/common/crash_reporter/win/crash_service.h +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_H_ -#define ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_H_ - -#include - -#include "base/macros.h" -#include "base/files/file_path.h" -#include "base/synchronization/lock.h" - -namespace google_breakpad { - -class CrashReportSender; -class CrashGenerationServer; -class ClientInfo; - -} - -namespace breakpad { - -// This class implements an out-of-process crash server. It uses breakpad's -// CrashGenerationServer and CrashReportSender to generate and then send the -// crash dumps. Internally, it uses OS specific pipe to allow applications to -// register for crash dumps and later on when a registered application crashes -// it will signal an event that causes this code to wake up and perform a -// crash dump on the signaling process. The dump is then stored on disk and -// possibly sent to the crash2 servers. -class CrashService { - public: - CrashService(); - ~CrashService(); - - // Starts servicing crash dumps. Returns false if it failed. Do not use - // other members in that case. |operating_dir| is where the CrashService - // should store breakpad's checkpoint file. |dumps_path| is the directory - // where the crash dumps should be stored. - bool Initialize(const base::string16& application_name, - const base::FilePath& operating_dir, - const base::FilePath& dumps_path); - - // Command line switches: - // - // --max-reports= - // Allows to override the maximum number for reports per day. Normally - // the crash dumps are never sent so if you want to send any you must - // specify a positive number here. - static const char kMaxReports[]; - // --no-window - // Does not create a visible window on the desktop. The window does not have - // any other functionality other than allowing the crash service to be - // gracefully closed. - static const char kNoWindow[]; - // --reporter= - // Allows to specify a custom string that appears on the detail crash report - // page in the crash server. This should be a 25 chars or less string. - // The default tag if not specified is 'crash svc'. - static const char kReporterTag[]; - // --dumps-dir= - // Override the directory to which crash dump files will be written. - static const char kDumpsDir[]; - // --pipe-name= - // Override the name of the Windows named pipe on which we will - // listen for crash dump request messages. - static const char kPipeName[]; - // --reporter-url= - // Override the URL to which crash reports will be sent to. - static const char kReporterURL[]; - - // Returns number of crash dumps handled. - int requests_handled() const { - return requests_handled_; - } - // Returns number of crash clients registered. - int clients_connected() const { - return clients_connected_; - } - // Returns number of crash clients terminated. - int clients_terminated() const { - return clients_terminated_; - } - - // Starts the processing loop. This function does not return unless the - // user is logging off or the user closes the crash service window. The - // return value is a good number to pass in ExitProcess(). - int ProcessingLoop(); - - private: - static void OnClientConnected(void* context, - const google_breakpad::ClientInfo* client_info); - - static void OnClientDumpRequest( - void* context, - const google_breakpad::ClientInfo* client_info, - const std::wstring* file_path); - - static void OnClientExited(void* context, - const google_breakpad::ClientInfo* client_info); - - // This routine sends the crash dump to the server. It takes the sending_ - // lock when it is performing the send. - static DWORD __stdcall AsyncSendDump(void* context); - - // Returns the security descriptor which access to low integrity processes - // The caller is supposed to free the security descriptor by calling - // LocalFree. - PSECURITY_DESCRIPTOR GetSecurityDescriptorForLowIntegrity(); - - google_breakpad::CrashGenerationServer* dumper_; - google_breakpad::CrashReportSender* sender_; - - // the extra tag sent to the server with each dump. - std::wstring reporter_tag_; - - // receiver URL of crash reports. - std::wstring reporter_url_; - - // clients serviced statistics: - int requests_handled_; - int requests_sent_; - volatile LONG clients_connected_; - volatile LONG clients_terminated_; - base::Lock sending_; - - DISALLOW_COPY_AND_ASSIGN(CrashService); -}; - -} // namespace breakpad - -#endif // ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_H_ diff --git a/atom/common/crash_reporter/win/crash_service_main.cc b/atom/common/crash_reporter/win/crash_service_main.cc deleted file mode 100644 index c6325f090ade7..0000000000000 --- a/atom/common/crash_reporter/win/crash_service_main.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/crash_reporter/win/crash_service_main.h" - -#include "atom/common/crash_reporter/win/crash_service.h" -#include "base/at_exit.h" -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/strings/string_util.h" - -namespace crash_service { - -namespace { - -const char kApplicationName[] = "application-name"; - -const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service"; -const wchar_t kStandardLogFile[] = L"operation_log.txt"; - -void InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, - unsigned int, uintptr_t) { - // noop. -} - -bool GetCrashServiceDirectory(const std::wstring& application_name, - base::FilePath* dir) { - base::FilePath temp_dir; - if (!base::GetTempDir(&temp_dir)) - return false; - temp_dir = temp_dir.Append(application_name + L" Crashes"); - if (!base::PathExists(temp_dir)) { - if (!base::CreateDirectory(temp_dir)) - return false; - } - *dir = temp_dir; - return true; -} - -} // namespace. - -int Main(const wchar_t* cmd) { - // Ignore invalid parameter errors. - _set_invalid_parameter_handler(InvalidParameterHandler); - - // Initialize all Chromium things. - base::AtExitManager exit_manager; - base::CommandLine::Init(0, NULL); - base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess(); - - // Use the application's name as pipe name and output directory. - if (!cmd_line.HasSwitch(kApplicationName)) { - LOG(ERROR) << "Application's name must be specified with --" - << kApplicationName; - return 1; - } - std::wstring application_name = cmd_line.GetSwitchValueNative( - kApplicationName); - - // We use/create a directory under the user's temp folder, for logging. - base::FilePath operating_dir; - GetCrashServiceDirectory(application_name, &operating_dir); - base::FilePath log_file = operating_dir.Append(kStandardLogFile); - - // Logging to stderr (to help with debugging failures on the - // buildbots) and to a file. - logging::LoggingSettings settings; - settings.logging_dest = logging::LOG_TO_ALL; - settings.log_file = log_file.value().c_str(); - logging::InitLogging(settings); - // Logging with pid, tid and timestamp. - logging::SetLogItems(true, true, true, false); - - VLOG(1) << "Session start. cmdline is [" << cmd << "]"; - - // Setting the crash reporter. - base::string16 pipe_name = base::ReplaceStringPlaceholders(kPipeNameFormat, - application_name, - NULL); - cmd_line.AppendSwitch("no-window"); - cmd_line.AppendSwitchASCII("max-reports", "128"); - cmd_line.AppendSwitchASCII("reporter", ATOM_PROJECT_NAME "-crash-service"); - cmd_line.AppendSwitchNative("pipe-name", pipe_name); - - breakpad::CrashService crash_service; - if (!crash_service.Initialize(application_name, operating_dir, - operating_dir)) - return 2; - - VLOG(1) << "Ready to process crash requests"; - - // Enter the message loop. - int retv = crash_service.ProcessingLoop(); - // Time to exit. - VLOG(1) << "Session end. return code is " << retv; - return retv; -} - -} // namespace crash_service diff --git a/atom/common/crash_reporter/win/crash_service_main.h b/atom/common/crash_reporter/win/crash_service_main.h deleted file mode 100644 index b536313dbc321..0000000000000 --- a/atom/common/crash_reporter/win/crash_service_main.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_MAIN_H_ -#define ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_MAIN_H_ - -namespace crash_service { - -// Program entry, should be called by main(); -int Main(const wchar_t* cmd_line); - -} // namespace crash_service - -#endif // ATOM_COMMON_CRASH_REPORTER_WIN_CRASH_SERVICE_MAIN_H_ diff --git a/atom/common/draggable_region.cc b/atom/common/draggable_region.cc deleted file mode 100644 index f57719448a088..0000000000000 --- a/atom/common/draggable_region.cc +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/draggable_region.h" - -namespace atom { - -DraggableRegion::DraggableRegion() - : draggable(false) { -} - -} // namespace atom diff --git a/atom/common/draggable_region.h b/atom/common/draggable_region.h deleted file mode 100644 index a007c8cb9fe54..0000000000000 --- a/atom/common/draggable_region.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_DRAGGABLE_REGION_H_ -#define ATOM_COMMON_DRAGGABLE_REGION_H_ - -#include "ui/gfx/geometry/rect.h" - -namespace atom { - -struct DraggableRegion { - bool draggable; - gfx::Rect bounds; - - DraggableRegion(); -}; - -} // namespace atom - -#endif // ATOM_COMMON_DRAGGABLE_REGION_H_ diff --git a/atom/common/google_api_key.h b/atom/common/google_api_key.h deleted file mode 100644 index dc38272ec611f..0000000000000 --- a/atom/common/google_api_key.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_GOOGLE_API_KEY_H_ -#define ATOM_COMMON_GOOGLE_API_KEY_H_ - -#ifndef GOOGLEAPIS_API_KEY -#define GOOGLEAPIS_API_KEY "AIzaSyAQfxPJiounkhOjODEO5ZieffeBv6yft2Q" -#endif - -#endif // ATOM_COMMON_GOOGLE_API_KEY_H_ diff --git a/atom/common/key_weak_map.h b/atom/common/key_weak_map.h deleted file mode 100644 index 8e879d656e850..0000000000000 --- a/atom/common/key_weak_map.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_KEY_WEAK_MAP_H_ -#define ATOM_COMMON_KEY_WEAK_MAP_H_ - -#include -#include -#include - -#include "base/macros.h" -#include "v8/include/v8.h" - -namespace atom { - -// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer. -template -class KeyWeakMap { - public: - // Records the key and self, used by SetWeak. - struct KeyObject { - K key; - KeyWeakMap* self; - }; - - KeyWeakMap() {} - virtual ~KeyWeakMap() { - for (auto& p : map_) - p.second.second.ClearWeak(); - } - - // Sets the object to WeakMap with the given |key|. - void Set(v8::Isolate* isolate, const K& key, v8::Local object) { - KeyObject key_object = {key, this}; - auto& p = map_[key] = - std::make_pair(key_object, v8::Global(isolate, object)); - p.second.SetWeak(&(p.first), OnObjectGC, v8::WeakCallbackType::kParameter); - } - - // Gets the object from WeakMap by its |key|. - v8::MaybeLocal Get(v8::Isolate* isolate, const K& key) { - auto iter = map_.find(key); - if (iter == map_.end()) - return v8::MaybeLocal(); - else - return v8::Local::New(isolate, iter->second.second); - } - - // Whethere there is an object with |key| in this WeakMap. - bool Has(const K& key) const { - return map_.find(key) != map_.end(); - } - - // Returns all objects. - std::vector> Values(v8::Isolate* isolate) const { - std::vector> keys; - keys.reserve(map_.size()); - for (const auto& it : map_) - keys.emplace_back(v8::Local::New(isolate, it.second.second)); - return keys; - } - - // Remove object with |key| in the WeakMap. - void Remove(const K& key) { - auto iter = map_.find(key); - if (iter == map_.end()) - return; - - iter->second.second.ClearWeak(); - map_.erase(iter); - } - - private: - static void OnObjectGC( - const v8::WeakCallbackInfo::KeyObject>& data) { - KeyWeakMap::KeyObject* key_object = data.GetParameter(); - key_object->self->Remove(key_object->key); - } - - // Map of stored objects. - std::unordered_map< - K, std::pair>> map_; - - DISALLOW_COPY_AND_ASSIGN(KeyWeakMap); -}; - -} // namespace atom - -#endif // ATOM_COMMON_KEY_WEAK_MAP_H_ diff --git a/atom/common/keyboard_util.cc b/atom/common/keyboard_util.cc deleted file mode 100644 index c8e9628f3bcca..0000000000000 --- a/atom/common/keyboard_util.cc +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include - -#include "atom/common/keyboard_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" - -namespace atom { - -namespace { - -// Return key code of the char, and also determine whether the SHIFT key is -// pressed. -ui::KeyboardCode KeyboardCodeFromCharCode(base::char16 c, bool* shifted) { - c = base::ToLowerASCII(c); - *shifted = false; - switch (c) { - case 0x08: return ui::VKEY_BACK; - case 0x7F: return ui::VKEY_DELETE; - case 0x09: return ui::VKEY_TAB; - case 0x0D: return ui::VKEY_RETURN; - case 0x1B: return ui::VKEY_ESCAPE; - case ' ': return ui::VKEY_SPACE; - - case 'a': return ui::VKEY_A; - case 'b': return ui::VKEY_B; - case 'c': return ui::VKEY_C; - case 'd': return ui::VKEY_D; - case 'e': return ui::VKEY_E; - case 'f': return ui::VKEY_F; - case 'g': return ui::VKEY_G; - case 'h': return ui::VKEY_H; - case 'i': return ui::VKEY_I; - case 'j': return ui::VKEY_J; - case 'k': return ui::VKEY_K; - case 'l': return ui::VKEY_L; - case 'm': return ui::VKEY_M; - case 'n': return ui::VKEY_N; - case 'o': return ui::VKEY_O; - case 'p': return ui::VKEY_P; - case 'q': return ui::VKEY_Q; - case 'r': return ui::VKEY_R; - case 's': return ui::VKEY_S; - case 't': return ui::VKEY_T; - case 'u': return ui::VKEY_U; - case 'v': return ui::VKEY_V; - case 'w': return ui::VKEY_W; - case 'x': return ui::VKEY_X; - case 'y': return ui::VKEY_Y; - case 'z': return ui::VKEY_Z; - - case ')': *shifted = true; case '0': return ui::VKEY_0; - case '!': *shifted = true; case '1': return ui::VKEY_1; - case '@': *shifted = true; case '2': return ui::VKEY_2; - case '#': *shifted = true; case '3': return ui::VKEY_3; - case '$': *shifted = true; case '4': return ui::VKEY_4; - case '%': *shifted = true; case '5': return ui::VKEY_5; - case '^': *shifted = true; case '6': return ui::VKEY_6; - case '&': *shifted = true; case '7': return ui::VKEY_7; - case '*': *shifted = true; case '8': return ui::VKEY_8; - case '(': *shifted = true; case '9': return ui::VKEY_9; - - case ':': *shifted = true; case ';': return ui::VKEY_OEM_1; - case '+': *shifted = true; case '=': return ui::VKEY_OEM_PLUS; - case '<': *shifted = true; case ',': return ui::VKEY_OEM_COMMA; - case '_': *shifted = true; case '-': return ui::VKEY_OEM_MINUS; - case '>': *shifted = true; case '.': return ui::VKEY_OEM_PERIOD; - case '?': *shifted = true; case '/': return ui::VKEY_OEM_2; - case '~': *shifted = true; case '`': return ui::VKEY_OEM_3; - case '{': *shifted = true; case '[': return ui::VKEY_OEM_4; - case '|': *shifted = true; case '\\': return ui::VKEY_OEM_5; - case '}': *shifted = true; case ']': return ui::VKEY_OEM_6; - case '"': *shifted = true; case '\'': return ui::VKEY_OEM_7; - - default: return ui::VKEY_UNKNOWN; - } -} - -// Return key code represented by |str|. -ui::KeyboardCode KeyboardCodeFromKeyIdentifier(const std::string& s, - bool* shifted) { - std::string str = base::ToLowerASCII(s); - if (str == "ctrl" || str == "control") { - return ui::VKEY_CONTROL; - } else if (str == "super" || str == "cmd" || str == "command" || - str == "meta") { - return ui::VKEY_COMMAND; - } else if (str == "commandorcontrol" || str == "cmdorctrl") { -#if defined(OS_MACOSX) - return ui::VKEY_COMMAND; -#else - return ui::VKEY_CONTROL; -#endif - } else if (str == "alt" || str == "option") { - return ui::VKEY_MENU; - } else if (str == "shift") { - return ui::VKEY_SHIFT; - } else if (str == "altgr") { - return ui::VKEY_ALTGR; - } else if (str == "plus") { - *shifted = true; - return ui::VKEY_OEM_PLUS; - } else if (str == "tab") { - return ui::VKEY_TAB; - } else if (str == "space") { - return ui::VKEY_SPACE; - } else if (str == "backspace") { - return ui::VKEY_BACK; - } else if (str == "delete") { - return ui::VKEY_DELETE; - } else if (str == "insert") { - return ui::VKEY_INSERT; - } else if (str == "enter" || str == "return") { - return ui::VKEY_RETURN; - } else if (str == "up") { - return ui::VKEY_UP; - } else if (str == "down") { - return ui::VKEY_DOWN; - } else if (str == "left") { - return ui::VKEY_LEFT; - } else if (str == "right") { - return ui::VKEY_RIGHT; - } else if (str == "home") { - return ui::VKEY_HOME; - } else if (str == "end") { - return ui::VKEY_END; - } else if (str == "pageup") { - return ui::VKEY_PRIOR; - } else if (str == "pagedown") { - return ui::VKEY_NEXT; - } else if (str == "esc" || str == "escape") { - return ui::VKEY_ESCAPE; - } else if (str == "volumemute") { - return ui::VKEY_VOLUME_MUTE; - } else if (str == "volumeup") { - return ui::VKEY_VOLUME_UP; - } else if (str == "volumedown") { - return ui::VKEY_VOLUME_DOWN; - } else if (str == "medianexttrack") { - return ui::VKEY_MEDIA_NEXT_TRACK; - } else if (str == "mediaprevioustrack") { - return ui::VKEY_MEDIA_PREV_TRACK; - } else if (str == "mediastop") { - return ui::VKEY_MEDIA_STOP; - } else if (str == "mediaplaypause") { - return ui::VKEY_MEDIA_PLAY_PAUSE; - } else if (str == "printscreen") { - return ui::VKEY_SNAPSHOT; - } else if (str.size() > 1 && str[0] == 'f') { - // F1 - F24. - int n; - if (base::StringToInt(str.c_str() + 1, &n) && n > 0 && n < 25) { - return static_cast(ui::VKEY_F1 + n - 1); - } else { - LOG(WARNING) << str << "is not available on keyboard"; - return ui::VKEY_UNKNOWN; - } - } else { - if (str.size() > 2) - LOG(WARNING) << "Invalid accelerator token: " << str; - return ui::VKEY_UNKNOWN; - } -} - -} // namespace - -ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted) { - if (str.size() == 1) - return KeyboardCodeFromCharCode(str[0], shifted); - else - return KeyboardCodeFromKeyIdentifier(str, shifted); -} - -} // namespace atom diff --git a/atom/common/keyboard_util.h b/atom/common/keyboard_util.h deleted file mode 100644 index c9d1b809e8f7c..0000000000000 --- a/atom/common/keyboard_util.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_KEYBOARD_UTIL_H_ -#define ATOM_COMMON_KEYBOARD_UTIL_H_ - -#include - -#include "ui/events/keycodes/keyboard_codes.h" - -namespace atom { - -// Return key code of the |str|, and also determine whether the SHIFT key is -// pressed. -ui::KeyboardCode KeyboardCodeFromStr(const std::string& str, bool* shifted); - -} // namespace atom - -#endif // ATOM_COMMON_KEYBOARD_UTIL_H_ diff --git a/atom/common/linux/application_info.cc b/atom/common/linux/application_info.cc deleted file mode 100644 index 053bd4bb8634c..0000000000000 --- a/atom/common/linux/application_info.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include - -#include "atom/common/atom_version.h" - -namespace brightray { - -std::string GetApplicationName() { - return ATOM_PRODUCT_NAME; -} - -std::string GetApplicationVersion() { - return ATOM_VERSION_STRING; -} - -} // namespace brightray diff --git a/atom/common/mouse_util.cc b/atom/common/mouse_util.cc deleted file mode 100644 index 69aadaa7a0464..0000000000000 --- a/atom/common/mouse_util.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include -#include "atom/common/mouse_util.h" - -using Cursor = blink::WebCursorInfo::Type; - -namespace atom { - -std::string CursorTypeToString(const content::WebCursor::CursorInfo& info) { - switch (info.type) { - case Cursor::TypePointer: return "default"; - case Cursor::TypeCross: return "crosshair"; - case Cursor::TypeHand: return "pointer"; - case Cursor::TypeIBeam: return "text"; - case Cursor::TypeWait: return "wait"; - case Cursor::TypeHelp: return "help"; - case Cursor::TypeEastResize: return "e-resize"; - case Cursor::TypeNorthResize: return "n-resize"; - case Cursor::TypeNorthEastResize: return "ne-resize"; - case Cursor::TypeNorthWestResize: return "nw-resize"; - case Cursor::TypeSouthResize: return "s-resize"; - case Cursor::TypeSouthEastResize: return "se-resize"; - case Cursor::TypeSouthWestResize: return "sw-resize"; - case Cursor::TypeWestResize: return "w-resize"; - case Cursor::TypeNorthSouthResize: return "ns-resize"; - case Cursor::TypeEastWestResize: return "ew-resize"; - case Cursor::TypeNorthEastSouthWestResize: return "nesw-resize"; - case Cursor::TypeNorthWestSouthEastResize: return "nwse-resize"; - case Cursor::TypeColumnResize: return "col-resize"; - case Cursor::TypeRowResize: return "row-resize"; - case Cursor::TypeMiddlePanning: return "m-panning"; - case Cursor::TypeEastPanning: return "e-panning"; - case Cursor::TypeNorthPanning: return "n-panning"; - case Cursor::TypeNorthEastPanning: return "ne-panning"; - case Cursor::TypeNorthWestPanning: return "nw-panning"; - case Cursor::TypeSouthPanning: return "s-panning"; - case Cursor::TypeSouthEastPanning: return "se-panning"; - case Cursor::TypeSouthWestPanning: return "sw-panning"; - case Cursor::TypeWestPanning: return "w-panning"; - case Cursor::TypeMove: return "move"; - case Cursor::TypeVerticalText: return "vertical-text"; - case Cursor::TypeCell: return "cell"; - case Cursor::TypeContextMenu: return "context-menu"; - case Cursor::TypeAlias: return "alias"; - case Cursor::TypeProgress: return "progress"; - case Cursor::TypeNoDrop: return "nodrop"; - case Cursor::TypeCopy: return "copy"; - case Cursor::TypeNone: return "none"; - case Cursor::TypeNotAllowed: return "not-allowed"; - case Cursor::TypeZoomIn: return "zoom-in"; - case Cursor::TypeZoomOut: return "zoom-out"; - case Cursor::TypeGrab: return "grab"; - case Cursor::TypeGrabbing: return "grabbing"; - case Cursor::TypeCustom: return "custom"; - default: return "default"; - } -} - -} // namespace atom diff --git a/atom/common/mouse_util.h b/atom/common/mouse_util.h deleted file mode 100644 index 2fd937422dacb..0000000000000 --- a/atom/common/mouse_util.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_MOUSE_UTIL_H_ -#define ATOM_COMMON_MOUSE_UTIL_H_ - -#include -#include "content/common/cursors/webcursor.h" -#include "ipc/ipc_message_macros.h" - -// IPC macros similar to the already existing ones in the chromium source. -// We need these to listen to the cursor change IPC message while still -// letting chromium handle the actual cursor change by setting handled = false. -#define IPC_MESSAGE_HANDLER_CODE(msg_class, member_func, code) \ - IPC_MESSAGE_FORWARD_CODE(msg_class, this, \ - _IpcMessageHandlerClass::member_func, code) - -#define IPC_MESSAGE_FORWARD_CODE(msg_class, obj, member_func, code) \ - case msg_class::ID: { \ - TRACK_RUN_IN_THIS_SCOPED_REGION(member_func); \ - if (!msg_class::Dispatch(&ipc_message__, obj, this, param__, \ - &member_func)) \ - ipc_message__.set_dispatch_error(); \ - code; \ - } \ - break; - -namespace atom { - -// Returns the cursor's type as a string. -std::string CursorTypeToString(const content::WebCursor::CursorInfo& info); - -} // namespace atom - -#endif // ATOM_COMMON_MOUSE_UTIL_H_ diff --git a/atom/common/native_mate_converters/accelerator_converter.cc b/atom/common/native_mate_converters/accelerator_converter.cc deleted file mode 100644 index 15eaafda2e3d5..0000000000000 --- a/atom/common/native_mate_converters/accelerator_converter.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/native_mate_converters/accelerator_converter.h" - -#include - -#include "atom/browser/ui/accelerator_util.h" - -namespace mate { - -// static -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, ui::Accelerator* out) { - std::string keycode; - if (!ConvertFromV8(isolate, val, &keycode)) - return false; - return accelerator_util::StringToAccelerator(keycode, out); -} - -} // namespace mate diff --git a/atom/common/native_mate_converters/accelerator_converter.h b/atom/common/native_mate_converters/accelerator_converter.h deleted file mode 100644 index 499077c08e287..0000000000000 --- a/atom/common/native_mate_converters/accelerator_converter.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_ACCELERATOR_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_ACCELERATOR_CONVERTER_H_ - -#include "native_mate/converter.h" - -namespace ui { -class Accelerator; -} - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - ui::Accelerator* out); -}; - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_ACCELERATOR_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/blink_converter.cc b/atom/common/native_mate_converters/blink_converter.cc deleted file mode 100644 index 7a72219416e0c..0000000000000 --- a/atom/common/native_mate_converters/blink_converter.cc +++ /dev/null @@ -1,426 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/native_mate_converters/blink_converter.h" - -#include -#include -#include - -#include "atom/common/keyboard_util.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "content/public/browser/native_web_keyboard_event.h" -#include "native_mate/dictionary.h" -#include "third_party/WebKit/public/web/WebCache.h" -#include "third_party/WebKit/public/web/WebDeviceEmulationParams.h" -#include "third_party/WebKit/public/web/WebFindOptions.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" -#include "ui/base/clipboard/clipboard.h" - -namespace { - -template -int VectorToBitArray(const std::vector& vec) { - int bits = 0; - for (const T& item : vec) - bits |= item; - return bits; -} - -} // namespace - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Handle val, - base::char16* out) { - base::string16 code = base::UTF8ToUTF16(V8ToString(val)); - if (code.length() != 1) - return false; - *out = code[0]; - return true; - } -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Handle val, - blink::WebInputEvent::Type* out) { - std::string type = base::ToLowerASCII(V8ToString(val)); - if (type == "mousedown") - *out = blink::WebInputEvent::MouseDown; - else if (type == "mouseup") - *out = blink::WebInputEvent::MouseUp; - else if (type == "mousemove") - *out = blink::WebInputEvent::MouseMove; - else if (type == "mouseenter") - *out = blink::WebInputEvent::MouseEnter; - else if (type == "mouseleave") - *out = blink::WebInputEvent::MouseLeave; - else if (type == "contextmenu") - *out = blink::WebInputEvent::ContextMenu; - else if (type == "mousewheel") - *out = blink::WebInputEvent::MouseWheel; - else if (type == "keydown") - *out = blink::WebInputEvent::RawKeyDown; - else if (type == "keyup") - *out = blink::WebInputEvent::KeyUp; - else if (type == "char") - *out = blink::WebInputEvent::Char; - else if (type == "touchstart") - *out = blink::WebInputEvent::TouchStart; - else if (type == "touchmove") - *out = blink::WebInputEvent::TouchMove; - else if (type == "touchend") - *out = blink::WebInputEvent::TouchEnd; - else if (type == "touchcancel") - *out = blink::WebInputEvent::TouchCancel; - return true; - } -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Handle val, - blink::WebMouseEvent::Button* out) { - std::string button = base::ToLowerASCII(V8ToString(val)); - if (button == "left") - *out = blink::WebMouseEvent::Button::ButtonLeft; - else if (button == "middle") - *out = blink::WebMouseEvent::Button::ButtonMiddle; - else if (button == "right") - *out = blink::WebMouseEvent::Button::ButtonRight; - else - return false; - return true; - } -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Handle val, - blink::WebInputEvent::Modifiers* out) { - std::string modifier = base::ToLowerASCII(V8ToString(val)); - if (modifier == "shift") - *out = blink::WebInputEvent::ShiftKey; - else if (modifier == "control" || modifier == "ctrl") - *out = blink::WebInputEvent::ControlKey; - else if (modifier == "alt") - *out = blink::WebInputEvent::AltKey; - else if (modifier == "meta" || modifier == "command" || modifier == "cmd") - *out = blink::WebInputEvent::MetaKey; - else if (modifier == "iskeypad") - *out = blink::WebInputEvent::IsKeyPad; - else if (modifier == "isautorepeat") - *out = blink::WebInputEvent::IsAutoRepeat; - else if (modifier == "leftbuttondown") - *out = blink::WebInputEvent::LeftButtonDown; - else if (modifier == "middlebuttondown") - *out = blink::WebInputEvent::MiddleButtonDown; - else if (modifier == "rightbuttondown") - *out = blink::WebInputEvent::RightButtonDown; - else if (modifier == "capslock") - *out = blink::WebInputEvent::CapsLockOn; - else if (modifier == "numlock") - *out = blink::WebInputEvent::NumLockOn; - else if (modifier == "left") - *out = blink::WebInputEvent::IsLeft; - else if (modifier == "right") - *out = blink::WebInputEvent::IsRight; - return true; - } -}; - -int GetWebInputEventType(v8::Isolate* isolate, v8::Local val) { - blink::WebInputEvent::Type type = blink::WebInputEvent::Undefined; - mate::Dictionary dict; - ConvertFromV8(isolate, val, &dict) && dict.Get("type", &type); - return type; -} - -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, - blink::WebInputEvent* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - if (!dict.Get("type", &out->type)) - return false; - std::vector modifiers; - if (dict.Get("modifiers", &modifiers)) - out->modifiers = VectorToBitArray(modifiers); - out->timeStampSeconds = base::Time::Now().ToDoubleT(); - return true; -} - -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, - blink::WebKeyboardEvent* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - if (!ConvertFromV8(isolate, val, static_cast(out))) - return false; - - std::string str; - bool shifted = false; - if (dict.Get("keyCode", &str)) - out->windowsKeyCode = atom::KeyboardCodeFromStr(str, &shifted); - else - return false; - - if (shifted) - out->modifiers |= blink::WebInputEvent::ShiftKey; - out->setKeyIdentifierFromWindowsKeyCode(); - if ((out->type == blink::WebInputEvent::Char || - out->type == blink::WebInputEvent::RawKeyDown)) { - // Make sure to not read beyond the buffer in case some bad code doesn't - // NULL-terminate it (this is called from plugins). - size_t text_length_cap = blink::WebKeyboardEvent::textLengthCap; - base::string16 text16 = base::UTF8ToUTF16(str); - - memset(out->text, 0, text_length_cap); - memset(out->unmodifiedText, 0, text_length_cap); - for (size_t i = 0; i < std::min(text_length_cap, text16.size()); ++i) { - out->text[i] = text16[i]; - out->unmodifiedText[i] = text16[i]; - } - } - return true; -} - -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, - content::NativeWebKeyboardEvent* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - if (!ConvertFromV8(isolate, val, static_cast(out))) - return false; - dict.Get("skipInBrowser", &out->skip_in_browser); - return true; -} - -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, blink::WebMouseEvent* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - if (!ConvertFromV8(isolate, val, static_cast(out))) - return false; - if (!dict.Get("x", &out->x) || !dict.Get("y", &out->y)) - return false; - if (!dict.Get("button", &out->button)) - out->button = blink::WebMouseEvent::Button::ButtonLeft; - dict.Get("globalX", &out->globalX); - dict.Get("globalY", &out->globalY); - dict.Get("movementX", &out->movementX); - dict.Get("movementY", &out->movementY); - dict.Get("clickCount", &out->clickCount); - return true; -} - -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, - blink::WebMouseWheelEvent* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - if (!ConvertFromV8(isolate, val, static_cast(out))) - return false; - dict.Get("deltaX", &out->deltaX); - dict.Get("deltaY", &out->deltaY); - dict.Get("wheelTicksX", &out->wheelTicksX); - dict.Get("wheelTicksY", &out->wheelTicksY); - dict.Get("accelerationRatioX", &out->accelerationRatioX); - dict.Get("accelerationRatioY", &out->accelerationRatioY); - dict.Get("hasPreciseScrollingDeltas", &out->hasPreciseScrollingDeltas); - dict.Get("canScroll", &out->canScroll); - return true; -} - -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, blink::WebFloatPoint* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - return dict.Get("x", &out->x) && dict.Get("y", &out->y); -} - -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, blink::WebPoint* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - return dict.Get("x", &out->x) && dict.Get("y", &out->y); -} - -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, blink::WebSize* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - return dict.Get("width", &out->width) && dict.Get("height", &out->height); -} - -bool Converter::FromV8( - v8::Isolate* isolate, v8::Local val, - blink::WebDeviceEmulationParams* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - - std::string screen_position; - if (dict.Get("screenPosition", &screen_position)) { - screen_position = base::ToLowerASCII(screen_position); - if (screen_position == "mobile") - out->screenPosition = blink::WebDeviceEmulationParams::Mobile; - else if (screen_position == "desktop") - out->screenPosition = blink::WebDeviceEmulationParams::Desktop; - else - return false; - } - - dict.Get("screenSize", &out->screenSize); - dict.Get("viewPosition", &out->viewPosition); - dict.Get("deviceScaleFactor", &out->deviceScaleFactor); - dict.Get("viewSize", &out->viewSize); - dict.Get("fitToView", &out->fitToView); - dict.Get("offset", &out->offset); - dict.Get("scale", &out->scale); - return true; -} - -bool Converter::FromV8( - v8::Isolate* isolate, - v8::Local val, - blink::WebFindOptions* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - - dict.Get("forward", &out->forward); - dict.Get("matchCase", &out->matchCase); - dict.Get("findNext", &out->findNext); - dict.Get("wordStart", &out->wordStart); - dict.Get("medialCapitalAsWordStart", &out->medialCapitalAsWordStart); - return true; -} - -// static -v8::Local Converter::ToV8( - v8::Isolate* isolate, const blink::WebContextMenuData::MediaType& in) { - switch (in) { - case blink::WebContextMenuData::MediaTypeImage: - return mate::StringToV8(isolate, "image"); - case blink::WebContextMenuData::MediaTypeVideo: - return mate::StringToV8(isolate, "video"); - case blink::WebContextMenuData::MediaTypeAudio: - return mate::StringToV8(isolate, "audio"); - case blink::WebContextMenuData::MediaTypeCanvas: - return mate::StringToV8(isolate, "canvas"); - case blink::WebContextMenuData::MediaTypeFile: - return mate::StringToV8(isolate, "file"); - case blink::WebContextMenuData::MediaTypePlugin: - return mate::StringToV8(isolate, "plugin"); - default: - return mate::StringToV8(isolate, "none"); - } -} - -// static -v8::Local Converter::ToV8( - v8::Isolate* isolate, - const blink::WebContextMenuData::InputFieldType& in) { - switch (in) { - case blink::WebContextMenuData::InputFieldTypePlainText: - return mate::StringToV8(isolate, "plainText"); - case blink::WebContextMenuData::InputFieldTypePassword: - return mate::StringToV8(isolate, "password"); - case blink::WebContextMenuData::InputFieldTypeOther: - return mate::StringToV8(isolate, "other"); - default: - return mate::StringToV8(isolate, "none"); - } -} - -v8::Local EditFlagsToV8(v8::Isolate* isolate, int editFlags) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("canUndo", - !!(editFlags & blink::WebContextMenuData::CanUndo)); - dict.Set("canRedo", - !!(editFlags & blink::WebContextMenuData::CanRedo)); - dict.Set("canCut", - !!(editFlags & blink::WebContextMenuData::CanCut)); - dict.Set("canCopy", - !!(editFlags & blink::WebContextMenuData::CanCopy)); - - bool pasteFlag = false; - if (editFlags & blink::WebContextMenuData::CanPaste) { - std::vector types; - bool ignore; - ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes( - ui::CLIPBOARD_TYPE_COPY_PASTE, &types, &ignore); - pasteFlag = !types.empty(); - } - dict.Set("canPaste", pasteFlag); - - dict.Set("canDelete", - !!(editFlags & blink::WebContextMenuData::CanDelete)); - dict.Set("canSelectAll", - !!(editFlags & blink::WebContextMenuData::CanSelectAll)); - - return mate::ConvertToV8(isolate, dict); -} - -v8::Local MediaFlagsToV8(v8::Isolate* isolate, int mediaFlags) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("inError", - !!(mediaFlags & blink::WebContextMenuData::MediaInError)); - dict.Set("isPaused", - !!(mediaFlags & blink::WebContextMenuData::MediaPaused)); - dict.Set("isMuted", - !!(mediaFlags & blink::WebContextMenuData::MediaMuted)); - dict.Set("hasAudio", - !!(mediaFlags & blink::WebContextMenuData::MediaHasAudio)); - dict.Set("isLooping", - (mediaFlags & blink::WebContextMenuData::MediaLoop) != 0); - dict.Set("isControlsVisible", - (mediaFlags & blink::WebContextMenuData::MediaControls) != 0); - dict.Set("canToggleControls", - !!(mediaFlags & blink::WebContextMenuData::MediaCanToggleControls)); - dict.Set("canRotate", - !!(mediaFlags & blink::WebContextMenuData::MediaCanRotate)); - return mate::ConvertToV8(isolate, dict); -} - -v8::Local Converter::ToV8( - v8::Isolate* isolate, - const blink::WebCache::ResourceTypeStat& stat) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("count", static_cast(stat.count)); - dict.Set("size", static_cast(stat.size)); - dict.Set("liveSize", static_cast(stat.liveSize)); - dict.Set("decodedSize", static_cast(stat.decodedSize)); - dict.Set("purgedSize", static_cast(stat.purgedSize)); - dict.Set("purgeableSize", static_cast(stat.purgeableSize)); - return dict.GetHandle(); -} - -v8::Local Converter::ToV8( - v8::Isolate* isolate, - const blink::WebCache::ResourceTypeStats& stats) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("images", stats.images); - dict.Set("scripts", stats.scripts); - dict.Set("cssStyleSheets", stats.cssStyleSheets); - dict.Set("xslStyleSheets", stats.xslStyleSheets); - dict.Set("fonts", stats.fonts); - dict.Set("other", stats.other); - return dict.GetHandle(); -} - -} // namespace mate diff --git a/atom/common/native_mate_converters/blink_converter.h b/atom/common/native_mate_converters/blink_converter.h deleted file mode 100644 index 78275ab62ec94..0000000000000 --- a/atom/common/native_mate_converters/blink_converter.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_ - -#include "native_mate/converter.h" -#include "third_party/WebKit/public/web/WebCache.h" -#include "third_party/WebKit/public/web/WebContextMenuData.h" - -namespace blink { -class WebInputEvent; -class WebMouseEvent; -class WebMouseWheelEvent; -class WebKeyboardEvent; -struct WebDeviceEmulationParams; -struct WebFindOptions; -struct WebFloatPoint; -struct WebPoint; -struct WebSize; -} // namespace blink - -namespace content { -struct NativeWebKeyboardEvent; -} - -namespace mate { - -int GetWebInputEventType(v8::Isolate* isolate, v8::Local val); - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebInputEvent* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebKeyboardEvent* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - content::NativeWebKeyboardEvent* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebMouseEvent* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebMouseWheelEvent* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebFloatPoint* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebPoint* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebSize* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebDeviceEmulationParams* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::WebFindOptions* out); -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const blink::WebContextMenuData::MediaType& in); -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const blink::WebContextMenuData::InputFieldType& in); -}; - -template<> -struct Converter { - static v8::Local ToV8( - v8::Isolate* isolate, - const blink::WebCache::ResourceTypeStat& stat); -}; - -template<> -struct Converter { - static v8::Local ToV8( - v8::Isolate* isolate, - const blink::WebCache::ResourceTypeStats& stats); -}; - -v8::Local EditFlagsToV8(v8::Isolate* isolate, int editFlags); -v8::Local MediaFlagsToV8(v8::Isolate* isolate, int mediaFlags); - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/callback.cc b/atom/common/native_mate_converters/callback.cc deleted file mode 100644 index dc6d30fd23d72..0000000000000 --- a/atom/common/native_mate_converters/callback.cc +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/native_mate_converters/callback.h" - -#include "content/public/browser/browser_thread.h" - -using content::BrowserThread; - -namespace mate { - -namespace internal { - -namespace { - -struct TranslaterHolder { - Translater translater; -}; - -// Cached JavaScript version of |CallTranslater|. -v8::Persistent g_call_translater; - -void CallTranslater(v8::Local external, - v8::Local state, - mate::Arguments* args) { - v8::Isolate* isolate = args->isolate(); - - // Check if the callback has already been called. - v8::Local called_symbol = mate::StringToSymbol(isolate, "called"); - if (state->Has(called_symbol)) { - args->ThrowError("callback can only be called for once"); - return; - } else { - state->Set(called_symbol, v8::Boolean::New(isolate, true)); - } - - TranslaterHolder* holder = static_cast(external->Value()); - holder->translater.Run(args); - delete holder; -} - -// func.bind(func, arg1). -// NB(zcbenz): Using C++11 version crashes VS. -v8::Local BindFunctionWith(v8::Isolate* isolate, - v8::Local context, - v8::Local func, - v8::Local arg1, - v8::Local arg2) { - v8::MaybeLocal bind = func->Get(mate::StringToV8(isolate, "bind")); - CHECK(!bind.IsEmpty()); - v8::Local bind_func = - v8::Local::Cast(bind.ToLocalChecked()); - v8::Local converted[] = { func, arg1, arg2 }; - return bind_func->Call( - context, func, arraysize(converted), converted).ToLocalChecked(); -} - -} // namespace - -// Destroy the class on UI thread when possible. -struct DeleteOnUIThread { - template - static void Destruct(const T* x) { - if (Locker::IsBrowserProcess() && - !BrowserThread::CurrentlyOn(BrowserThread::UI)) { - BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, x); - } else { - delete x; - } - } -}; - -// Like v8::Global, but ref-counted. -template -class RefCountedGlobal : public base::RefCountedThreadSafe, - DeleteOnUIThread> { - public: - RefCountedGlobal(v8::Isolate* isolate, v8::Local value) - : handle_(isolate, v8::Local::Cast(value)) { - } - - bool IsAlive() const { - return !handle_.IsEmpty(); - } - - v8::Local NewHandle(v8::Isolate* isolate) const { - return v8::Local::New(isolate, handle_); - } - - private: - v8::Global handle_; - - DISALLOW_COPY_AND_ASSIGN(RefCountedGlobal); -}; - -SafeV8Function::SafeV8Function(v8::Isolate* isolate, v8::Local value) - : v8_function_(new RefCountedGlobal(isolate, value)) { -} - -SafeV8Function::SafeV8Function(const SafeV8Function& other) - : v8_function_(other.v8_function_) { -} - -SafeV8Function::~SafeV8Function() { -} - -bool SafeV8Function::IsAlive() const { - return v8_function_.get() && v8_function_->IsAlive(); -} - -v8::Local SafeV8Function::NewHandle(v8::Isolate* isolate) const { - return v8_function_->NewHandle(isolate); -} - -v8::Local CreateFunctionFromTranslater( - v8::Isolate* isolate, const Translater& translater) { - // The FunctionTemplate is cached. - if (g_call_translater.IsEmpty()) - g_call_translater.Reset( - isolate, - mate::CreateFunctionTemplate(isolate, base::Bind(&CallTranslater))); - - v8::Local call_translater = - v8::Local::New(isolate, g_call_translater); - auto* holder = new TranslaterHolder; - holder->translater = translater; - return BindFunctionWith(isolate, - isolate->GetCurrentContext(), - call_translater->GetFunction(), - v8::External::New(isolate, holder), - v8::Object::New(isolate)); -} - -} // namespace internal - -} // namespace mate diff --git a/atom/common/native_mate_converters/callback.h b/atom/common/native_mate_converters/callback.h deleted file mode 100644 index decc36eb5767b..0000000000000 --- a/atom/common/native_mate_converters/callback.h +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. All rights reserved. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_ - -#include - -#include "atom/common/api/locker.h" -#include "base/bind.h" -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "native_mate/function_template.h" -#include "native_mate/scoped_persistent.h" - -namespace mate { - -namespace internal { - -template -class RefCountedGlobal; - -// Manages the V8 function with RAII. -class SafeV8Function { - public: - SafeV8Function(v8::Isolate* isolate, v8::Local value); - SafeV8Function(const SafeV8Function& other); - ~SafeV8Function(); - - bool IsAlive() const; - v8::Local NewHandle(v8::Isolate* isolate) const; - - private: - scoped_refptr> v8_function_; -}; - -// Helper to invoke a V8 function with C++ parameters. -template -struct V8FunctionInvoker {}; - -template -struct V8FunctionInvoker(ArgTypes...)> { - static v8::Local Go(v8::Isolate* isolate, - const SafeV8Function& function, - ArgTypes... raw) { - Locker locker(isolate); - v8::EscapableHandleScope handle_scope(isolate); - if (!function.IsAlive()) - return v8::Null(isolate); - v8::MicrotasksScope script_scope(isolate, - v8::MicrotasksScope::kRunMicrotasks); - v8::Local holder = function.NewHandle(isolate); - v8::Local context = holder->CreationContext(); - v8::Context::Scope context_scope(context); - std::vector> args = { ConvertToV8(isolate, raw)... }; - v8::Local ret(holder->Call(holder, args.size(), &args.front())); - return handle_scope.Escape(ret); - } -}; - -template -struct V8FunctionInvoker { - static void Go(v8::Isolate* isolate, - const SafeV8Function& function, - ArgTypes... raw) { - Locker locker(isolate); - v8::HandleScope handle_scope(isolate); - if (!function.IsAlive()) - return; - v8::MicrotasksScope script_scope(isolate, - v8::MicrotasksScope::kRunMicrotasks); - v8::Local holder = function.NewHandle(isolate); - v8::Local context = holder->CreationContext(); - v8::Context::Scope context_scope(context); - std::vector> args = { ConvertToV8(isolate, raw)... }; - holder->Call(holder, args.size(), &args.front()); - } -}; - -template -struct V8FunctionInvoker { - static ReturnType Go(v8::Isolate* isolate, - const SafeV8Function& function, - ArgTypes... raw) { - Locker locker(isolate); - v8::HandleScope handle_scope(isolate); - ReturnType ret = ReturnType(); - if (!function.IsAlive()) - return ret; - v8::MicrotasksScope script_scope(isolate, - v8::MicrotasksScope::kRunMicrotasks); - v8::Local holder = function.NewHandle(isolate); - v8::Local context = holder->CreationContext(); - v8::Context::Scope context_scope(context); - std::vector> args = { ConvertToV8(isolate, raw)... }; - v8::Local result; - auto maybe_result = - holder->Call(context, holder, args.size(), &args.front()); - if (maybe_result.ToLocal(&result)) - Converter::FromV8(isolate, result, &ret); - return ret; - } -}; - -// Helper to pass a C++ funtion to JavaScript. -using Translater = base::Callback; -v8::Local CreateFunctionFromTranslater( - v8::Isolate* isolate, const Translater& translater); - -// Calls callback with Arguments. -template -struct NativeFunctionInvoker {}; - -template -struct NativeFunctionInvoker { - static void Go(base::Callback val, Arguments* args) { - using Indices = typename IndicesGenerator::type; - Invoker invoker(args, 0); - if (invoker.IsOK()) - invoker.DispatchToCallback(val); - } -}; - -} // namespace internal - -template -struct Converter> { - static v8::Local ToV8(v8::Isolate* isolate, - const base::Callback& val) { - // We don't use CreateFunctionTemplate here because it creates a new - // FunctionTemplate everytime, which is cached by V8 and causes leaks. - internal::Translater translater = base::Bind( - &internal::NativeFunctionInvoker::Go, val); - return internal::CreateFunctionFromTranslater(isolate, translater); - } - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - base::Callback* out) { - if (!val->IsFunction()) - return false; - - *out = base::Bind(&internal::V8FunctionInvoker::Go, - isolate, internal::SafeV8Function(isolate, val)); - return true; - } -}; - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_CALLBACK_H_ diff --git a/atom/common/native_mate_converters/content_converter.cc b/atom/common/native_mate_converters/content_converter.cc deleted file mode 100644 index 824065882e820..0000000000000 --- a/atom/common/native_mate_converters/content_converter.cc +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/native_mate_converters/content_converter.h" - -#include -#include - -#include "atom/browser/api/atom_api_web_contents.h" -#include "atom/browser/web_contents_permission_helper.h" -#include "atom/common/native_mate_converters/blink_converter.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "atom/common/native_mate_converters/ui_base_types_converter.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/context_menu_params.h" -#include "native_mate/dictionary.h" - -namespace { - -void ExecuteCommand(content::WebContents* web_contents, - int action, - const content::CustomContextMenuContext& context) { - web_contents->ExecuteCustomContextMenuCommand(action, context); -} - -// Forward declaration for nested recursive call. -v8::Local MenuToV8(v8::Isolate* isolate, - content::WebContents* web_contents, - const content::CustomContextMenuContext& context, - const std::vector& menu); - -v8::Local MenuItemToV8( - v8::Isolate* isolate, - content::WebContents* web_contents, - const content::CustomContextMenuContext& context, - const content::MenuItem& item) { - mate::Dictionary v8_item = mate::Dictionary::CreateEmpty(isolate); - switch (item.type) { - case content::MenuItem::CHECKABLE_OPTION: - case content::MenuItem::GROUP: - v8_item.Set("checked", item.checked); - case content::MenuItem::OPTION: - case content::MenuItem::SUBMENU: - v8_item.Set("label", item.label); - v8_item.Set("enabled", item.enabled); - default: - v8_item.Set("type", item.type); - } - if (item.type == content::MenuItem::SUBMENU) - v8_item.Set("submenu", - MenuToV8(isolate, web_contents, context, item.submenu)); - else if (item.action > 0) - v8_item.Set("click", - base::Bind(ExecuteCommand, web_contents, item.action, context)); - return v8_item.GetHandle(); -} - -v8::Local MenuToV8(v8::Isolate* isolate, - content::WebContents* web_contents, - const content::CustomContextMenuContext& context, - const std::vector& menu) { - std::vector> v8_menu; - for (const auto& menu_item : menu) - v8_menu.push_back(MenuItemToV8(isolate, web_contents, context, menu_item)); - return mate::ConvertToV8(isolate, v8_menu); -} - -} // namespace - -namespace mate { - -// static -v8::Local Converter::ToV8( - v8::Isolate* isolate, const content::MenuItem::Type& val) { - switch (val) { - case content::MenuItem::CHECKABLE_OPTION: - return StringToV8(isolate, "checkbox"); - case content::MenuItem::GROUP: - return StringToV8(isolate, "radio"); - case content::MenuItem::SEPARATOR: - return StringToV8(isolate, "separator"); - case content::MenuItem::SUBMENU: - return StringToV8(isolate, "submenu"); - case content::MenuItem::OPTION: - default: - return StringToV8(isolate, "normal"); - } -} - -// static -v8::Local Converter::ToV8( - v8::Isolate* isolate, const ContextMenuParamsWithWebContents& val) { - const auto& params = val.first; - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("x", params.x); - dict.Set("y", params.y); - dict.Set("linkURL", params.link_url); - dict.Set("linkText", params.link_text); - dict.Set("pageURL", params.page_url); - dict.Set("frameURL", params.frame_url); - dict.Set("srcURL", params.src_url); - dict.Set("mediaType", params.media_type); - dict.Set("mediaFlags", MediaFlagsToV8(isolate, params.media_flags)); - dict.Set("hasImageContents", params.has_image_contents); - dict.Set("isEditable", params.is_editable); - dict.Set("editFlags", EditFlagsToV8(isolate, params.edit_flags)); - dict.Set("selectionText", params.selection_text); - dict.Set("titleText", params.title_text); - dict.Set("misspelledWord", params.misspelled_word); - dict.Set("frameCharset", params.frame_charset); - dict.Set("inputFieldType", params.input_field_type); - dict.Set("menuSourceType", params.source_type); - - if (params.custom_context.is_pepper_menu) - dict.Set("menu", MenuToV8(isolate, val.second, params.custom_context, - params.custom_items)); - return mate::ConvertToV8(isolate, dict); -} - -// static -bool Converter::FromV8( - v8::Isolate* isolate, - v8::Local val, - blink::mojom::PermissionStatus* out) { - bool result; - if (!ConvertFromV8(isolate, val, &result)) - return false; - - if (result) - *out = blink::mojom::PermissionStatus::GRANTED; - else - *out = blink::mojom::PermissionStatus::DENIED; - - return true; -} - -// static -v8::Local Converter::ToV8( - v8::Isolate* isolate, const content::PermissionType& val) { - using PermissionType = atom::WebContentsPermissionHelper::PermissionType; - switch (val) { - case content::PermissionType::MIDI_SYSEX: - return StringToV8(isolate, "midiSysex"); - case content::PermissionType::PUSH_MESSAGING: - return StringToV8(isolate, "pushMessaging"); - case content::PermissionType::NOTIFICATIONS: - return StringToV8(isolate, "notifications"); - case content::PermissionType::GEOLOCATION: - return StringToV8(isolate, "geolocation"); - case content::PermissionType::AUDIO_CAPTURE: - case content::PermissionType::VIDEO_CAPTURE: - return StringToV8(isolate, "media"); - case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER: - return StringToV8(isolate, "mediaKeySystem"); - case content::PermissionType::MIDI: - return StringToV8(isolate, "midi"); - default: - break; - } - - if (val == (content::PermissionType)(PermissionType::POINTER_LOCK)) - return StringToV8(isolate, "pointerLock"); - else if (val == (content::PermissionType)(PermissionType::FULLSCREEN)) - return StringToV8(isolate, "fullscreen"); - else if (val == (content::PermissionType)(PermissionType::OPEN_EXTERNAL)) - return StringToV8(isolate, "openExternal"); - - return StringToV8(isolate, "unknown"); -} - -// static -bool Converter::FromV8( - v8::Isolate* isolate, - v8::Local val, - content::StopFindAction* out) { - std::string action; - if (!ConvertFromV8(isolate, val, &action)) - return false; - - if (action == "clearSelection") - *out = content::STOP_FIND_ACTION_CLEAR_SELECTION; - else if (action == "keepSelection") - *out = content::STOP_FIND_ACTION_KEEP_SELECTION; - else if (action == "activateSelection") - *out = content::STOP_FIND_ACTION_ACTIVATE_SELECTION; - else - return false; - - return true; -} - -// static -v8::Local Converter::ToV8( - v8::Isolate* isolate, content::WebContents* val) { - if (!val) - return v8::Null(isolate); - return atom::api::WebContents::CreateFrom(isolate, val).ToV8(); -} - -// static -bool Converter::FromV8( - v8::Isolate* isolate, - v8::Local val, - content::WebContents** out) { - atom::api::WebContents* web_contents = nullptr; - if (!ConvertFromV8(isolate, val, &web_contents) || !web_contents) - return false; - - *out = web_contents->web_contents(); - return true; -} - -} // namespace mate diff --git a/atom/common/native_mate_converters/content_converter.h b/atom/common/native_mate_converters/content_converter.h deleted file mode 100644 index 522961a7e96c5..0000000000000 --- a/atom/common/native_mate_converters/content_converter.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_CONTENT_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_CONTENT_CONVERTER_H_ - -#include - -#include "content/public/browser/permission_type.h" -#include "content/public/common/menu_item.h" -#include "content/public/common/stop_find_action.h" -#include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h" -#include "native_mate/converter.h" - -namespace content { -struct ContextMenuParams; -class WebContents; -} - -using ContextMenuParamsWithWebContents = - std::pair; - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const content::MenuItem::Type& val); -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const ContextMenuParamsWithWebContents& val); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - blink::mojom::PermissionStatus* out); -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const content::PermissionType& val); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - content::StopFindAction* out); -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - content::WebContents* val); - static bool FromV8(v8::Isolate* isolate, v8::Local val, - content::WebContents** out); -}; - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_CONTENT_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/file_path_converter.h b/atom/common/native_mate_converters/file_path_converter.h deleted file mode 100644 index 7df1289e243be..0000000000000 --- a/atom/common/native_mate_converters/file_path_converter.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_FILE_PATH_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_FILE_PATH_CONVERTER_H_ - -#include - -#include "atom/common/native_mate_converters/string16_converter.h" -#include "base/files/file_path.h" - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const base::FilePath& val) { - return Converter::ToV8(isolate, val.value()); - } - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - base::FilePath* out) { - if (val->IsNull()) - return true; - - base::FilePath::StringType path; - if (Converter::FromV8(isolate, val, &path)) { - *out = base::FilePath(path); - return true; - } else { - return false; - } - } -}; - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_FILE_PATH_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/gfx_converter.cc b/atom/common/native_mate_converters/gfx_converter.cc deleted file mode 100644 index db6a181cc96f4..0000000000000 --- a/atom/common/native_mate_converters/gfx_converter.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/native_mate_converters/gfx_converter.h" - -#include "native_mate/dictionary.h" -#include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/size.h" -#include "ui/display/display.h" -#include "ui/display/screen.h" - -namespace mate { - -v8::Local Converter::ToV8(v8::Isolate* isolate, - const gfx::Point& val) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.SetHidden("simple", true); - dict.Set("x", val.x()); - dict.Set("y", val.y()); - return dict.GetHandle(); -} - -bool Converter::FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::Point* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - int x, y; - if (!dict.Get("x", &x) || !dict.Get("y", &y)) - return false; - *out = gfx::Point(x, y); - return true; -} - -v8::Local Converter::ToV8(v8::Isolate* isolate, - const gfx::Size& val) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.SetHidden("simple", true); - dict.Set("width", val.width()); - dict.Set("height", val.height()); - return dict.GetHandle(); -} - -bool Converter::FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::Size* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - int width, height; - if (!dict.Get("width", &width) || !dict.Get("height", &height)) - return false; - *out = gfx::Size(width, height); - return true; -} - -v8::Local Converter::ToV8(v8::Isolate* isolate, - const gfx::Rect& val) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.SetHidden("simple", true); - dict.Set("x", val.x()); - dict.Set("y", val.y()); - dict.Set("width", val.width()); - dict.Set("height", val.height()); - return dict.GetHandle(); -} - -bool Converter::FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::Rect* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - int x, y, width, height; - if (!dict.Get("x", &x) || !dict.Get("y", &y) || - !dict.Get("width", &width) || !dict.Get("height", &height)) - return false; - *out = gfx::Rect(x, y, width, height); - return true; -} - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const display::Display::TouchSupport& val) { - switch (val) { - case display::Display::TOUCH_SUPPORT_AVAILABLE: - return StringToV8(isolate, "available"); - case display::Display::TOUCH_SUPPORT_UNAVAILABLE: - return StringToV8(isolate, "unavailable"); - default: - return StringToV8(isolate, "unknown"); - } - } -}; - -v8::Local Converter::ToV8( - v8::Isolate* isolate, const display::Display& val) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.SetHidden("simple", true); - dict.Set("id", val.id()); - dict.Set("bounds", val.bounds()); - dict.Set("workArea", val.work_area()); - dict.Set("size", val.size()); - dict.Set("workAreaSize", val.work_area_size()); - dict.Set("scaleFactor", val.device_scale_factor()); - dict.Set("rotation", val.RotationAsDegree()); - dict.Set("touchSupport", val.touch_support()); - return dict.GetHandle(); -} - -} // namespace mate diff --git a/atom/common/native_mate_converters/gfx_converter.h b/atom/common/native_mate_converters/gfx_converter.h deleted file mode 100644 index 1797710962eac..0000000000000 --- a/atom/common/native_mate_converters/gfx_converter.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_GFX_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_GFX_CONVERTER_H_ - -#include "native_mate/converter.h" - -namespace display { -class Display; -} - -namespace gfx { -class Point; -class Size; -class Rect; -} - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const gfx::Point& val); - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::Point* out); -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const gfx::Size& val); - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::Size* out); -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const gfx::Rect& val); - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::Rect* out); -}; - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const display::Display& val); - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - display::Display* out); -}; - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_GFX_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/gurl_converter.h b/atom/common/native_mate_converters/gurl_converter.h deleted file mode 100644 index 34408913b789a..0000000000000 --- a/atom/common/native_mate_converters/gurl_converter.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_GURL_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_GURL_CONVERTER_H_ - -#include - -#include "native_mate/converter.h" -#include "url/gurl.h" - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const GURL& val) { - return ConvertToV8(isolate, val.spec()); - } - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - GURL* out) { - std::string url; - if (Converter::FromV8(isolate, val, &url)) { - *out = GURL(url); - return true; - } else { - return false; - } - } -}; - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_GURL_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/image_converter.cc b/atom/common/native_mate_converters/image_converter.cc deleted file mode 100644 index cfb1938a138fd..0000000000000 --- a/atom/common/native_mate_converters/image_converter.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/native_mate_converters/image_converter.h" - -#include "atom/common/api/atom_api_native_image.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "ui/gfx/image/image_skia.h" - -namespace mate { - -bool Converter::FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::ImageSkia* out) { - gfx::Image image; - if (!ConvertFromV8(isolate, val, &image)) - return false; - - *out = image.AsImageSkia(); - return true; -} - -bool Converter::FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::Image* out) { - if (val->IsNull()) - return true; - - Handle native_image; - if (!ConvertFromV8(isolate, val, &native_image)) - return false; - - *out = native_image->image(); - return true; -} - -v8::Local Converter::ToV8(v8::Isolate* isolate, - const gfx::Image& val) { - return ConvertToV8(isolate, atom::api::NativeImage::Create(isolate, val)); -} - -} // namespace mate diff --git a/atom/common/native_mate_converters/image_converter.h b/atom/common/native_mate_converters/image_converter.h deleted file mode 100644 index be52288eb0491..0000000000000 --- a/atom/common/native_mate_converters/image_converter.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_IMAGE_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_IMAGE_CONVERTER_H_ - -#include "native_mate/converter.h" - -namespace gfx { -class Image; -class ImageSkia; -} - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::ImageSkia* out); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - gfx::Image* out); - static v8::Local ToV8(v8::Isolate* isolate, - const gfx::Image& val); -}; - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_IMAGE_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/net_converter.cc b/atom/common/native_mate_converters/net_converter.cc deleted file mode 100644 index e79e09df10b2a..0000000000000 --- a/atom/common/native_mate_converters/net_converter.cc +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/native_mate_converters/net_converter.h" - -#include -#include - -#include "atom/common/node_includes.h" -#include "atom/common/native_mate_converters/gurl_converter.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "base/values.h" -#include "base/strings/string_number_conversions.h" -#include "native_mate/dictionary.h" -#include "net/base/upload_bytes_element_reader.h" -#include "net/base/upload_data_stream.h" -#include "net/base/upload_element_reader.h" -#include "net/base/upload_file_element_reader.h" -#include "net/cert/x509_certificate.h" -#include "net/http/http_response_headers.h" -#include "net/url_request/url_request.h" - -namespace mate { - -// static -v8::Local Converter::ToV8( - v8::Isolate* isolate, const net::AuthChallengeInfo* val) { - mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); - dict.Set("isProxy", val->is_proxy); - dict.Set("scheme", val->scheme); - dict.Set("host", val->challenger.host()); - dict.Set("port", static_cast(val->challenger.port())); - dict.Set("realm", val->realm); - return mate::ConvertToV8(isolate, dict); -} - -// static -v8::Local Converter>::ToV8( - v8::Isolate* isolate, const scoped_refptr& val) { - mate::Dictionary dict(isolate, v8::Object::New(isolate)); - std::string encoded_data; - net::X509Certificate::GetPEMEncoded( - val->os_cert_handle(), &encoded_data); - auto buffer = node::Buffer::Copy(isolate, - encoded_data.data(), - encoded_data.size()).ToLocalChecked(); - dict.Set("data", buffer); - dict.Set("issuerName", val->issuer().GetDisplayName()); - dict.Set("subjectName", val->subject().GetDisplayName()); - dict.Set("serialNumber", base::HexEncode(val->serial_number().data(), - val->serial_number().size())); - dict.Set("validStart", val->valid_start().ToDoubleT()); - dict.Set("validExpiry", val->valid_expiry().ToDoubleT()); - dict.Set("fingerprint", - net::HashValue( - val->CalculateFingerprint256(val->os_cert_handle())).ToString()); - - return dict.GetHandle(); -} - -} // namespace mate - -namespace atom { - -void FillRequestDetails(base::DictionaryValue* details, - const net::URLRequest* request) { - details->SetString("method", request->method()); - std::string url; - if (!request->url_chain().empty()) url = request->url().spec(); - details->SetStringWithoutPathExpansion("url", url); - details->SetString("referrer", request->referrer()); - std::unique_ptr list(new base::ListValue); - GetUploadData(list.get(), request); - if (!list->empty()) - details->Set("uploadData", std::move(list)); -} - -void GetUploadData(base::ListValue* upload_data_list, - const net::URLRequest* request) { - const net::UploadDataStream* upload_data = request->get_upload(); - if (!upload_data) - return; - const std::vector>* readers = - upload_data->GetElementReaders(); - for (const auto& reader : *readers) { - std::unique_ptr upload_data_dict( - new base::DictionaryValue); - if (reader->AsBytesReader()) { - const net::UploadBytesElementReader* bytes_reader = - reader->AsBytesReader(); - std::unique_ptr bytes( - base::BinaryValue::CreateWithCopiedBuffer(bytes_reader->bytes(), - bytes_reader->length())); - upload_data_dict->Set("bytes", std::move(bytes)); - } else if (reader->AsFileReader()) { - const net::UploadFileElementReader* file_reader = - reader->AsFileReader(); - auto file_path = file_reader->path().AsUTF8Unsafe(); - upload_data_dict->SetStringWithoutPathExpansion("file", file_path); - } - upload_data_list->Append(std::move(upload_data_dict)); - } -} - -} // namespace atom diff --git a/atom/common/native_mate_converters/net_converter.h b/atom/common/native_mate_converters/net_converter.h deleted file mode 100644 index 37e42806955df..0000000000000 --- a/atom/common/native_mate_converters/net_converter.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_ - -#include "base/memory/ref_counted.h" -#include "native_mate/converter.h" - -namespace base { -class DictionaryValue; -class ListValue; -} - -namespace net { -class AuthChallengeInfo; -class URLRequest; -class X509Certificate; -} - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const net::AuthChallengeInfo* val); -}; - -template<> -struct Converter> { - static v8::Local ToV8(v8::Isolate* isolate, - const scoped_refptr& val); -}; - -} // namespace mate - -namespace atom { - -void FillRequestDetails(base::DictionaryValue* details, - const net::URLRequest* request); - -void GetUploadData(base::ListValue* upload_data_list, - const net::URLRequest* request); - -} // namespace atom - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_NET_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/string16_converter.h b/atom/common/native_mate_converters/string16_converter.h deleted file mode 100644 index e2a5b8ca489eb..0000000000000 --- a/atom/common/native_mate_converters/string16_converter.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_STRING16_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_STRING16_CONVERTER_H_ - -#include "base/strings/string16.h" -#include "native_mate/converter.h" - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const base::string16& val) { - return MATE_STRING_NEW_FROM_UTF16( - isolate, reinterpret_cast(val.data()), val.size()); - } - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - base::string16* out) { - if (!val->IsString()) - return false; - - v8::String::Value s(val); - out->assign(reinterpret_cast(*s), s.length()); - return true; - } -}; - -inline v8::Local StringToV8( - v8::Isolate* isolate, - const base::string16& input) { - return ConvertToV8(isolate, input).As(); -} - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_STRING16_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/ui_base_types_converter.h b/atom/common/native_mate_converters/ui_base_types_converter.h deleted file mode 100644 index ad3390566c888..0000000000000 --- a/atom/common/native_mate_converters/ui_base_types_converter.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_UI_BASE_TYPES_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_UI_BASE_TYPES_CONVERTER_H_ - -#include "native_mate/converter.h" -#include "ui/base/ui_base_types.h" - -namespace mate { - -template<> -struct Converter { - static v8::Local ToV8(v8::Isolate* isolate, - const ui::MenuSourceType& in) { - switch (in) { - case ui::MENU_SOURCE_MOUSE: - return mate::StringToV8(isolate, "mouse"); - case ui::MENU_SOURCE_KEYBOARD: - return mate::StringToV8(isolate, "keyboard"); - case ui::MENU_SOURCE_TOUCH: - return mate::StringToV8(isolate, "touch"); - case ui::MENU_SOURCE_TOUCH_EDIT_MENU: - return mate::StringToV8(isolate, "touchMenu"); - default: - return mate::StringToV8(isolate, "none"); - } - } -}; - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_UI_BASE_TYPES_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/v8_value_converter.cc b/atom/common/native_mate_converters/v8_value_converter.cc deleted file mode 100644 index 6d159d4daf398..0000000000000 --- a/atom/common/native_mate_converters/v8_value_converter.cc +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/native_mate_converters/v8_value_converter.h" - -#include -#include -#include -#include - -#include "base/logging.h" -#include "base/values.h" -#include "native_mate/dictionary.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace { - -const int kMaxRecursionDepth = 100; - -} // namespace - -// The state of a call to FromV8Value. -class V8ValueConverter::FromV8ValueState { - public: - // Level scope which updates the current depth of some FromV8ValueState. - class Level { - public: - explicit Level(FromV8ValueState* state) : state_(state) { - state_->max_recursion_depth_--; - } - ~Level() { - state_->max_recursion_depth_++; - } - - private: - FromV8ValueState* state_; - }; - - FromV8ValueState() : max_recursion_depth_(kMaxRecursionDepth) {} - - // If |handle| is not in |unique_map_|, then add it to |unique_map_| and - // return true. - // - // Otherwise do nothing and return false. Here "A is unique" means that no - // other handle B in the map points to the same object as A. Note that A can - // be unique even if there already is another handle with the same identity - // hash (key) in the map, because two objects can have the same hash. - bool UpdateAndCheckUniqueness(v8::Local handle) { - typedef HashToHandleMap::const_iterator Iterator; - int hash = handle->GetIdentityHash(); - // We only compare using == with handles to objects with the same identity - // hash. Different hash obviously means different objects, but two objects - // in a couple of thousands could have the same identity hash. - std::pair range = unique_map_.equal_range(hash); - for (auto it = range.first; it != range.second; ++it) { - // Operator == for handles actually compares the underlying objects. - if (it->second == handle) - return false; - } - unique_map_.insert(std::make_pair(hash, handle)); - return true; - } - - bool HasReachedMaxRecursionDepth() { - return max_recursion_depth_ < 0; - } - - private: - typedef std::multimap > HashToHandleMap; - HashToHandleMap unique_map_; - - int max_recursion_depth_; -}; - -V8ValueConverter::V8ValueConverter() - : reg_exp_allowed_(false), - function_allowed_(false), - strip_null_from_objects_(false) {} - -void V8ValueConverter::SetRegExpAllowed(bool val) { - reg_exp_allowed_ = val; -} - -void V8ValueConverter::SetFunctionAllowed(bool val) { - function_allowed_ = val; -} - -void V8ValueConverter::SetStripNullFromObjects(bool val) { - strip_null_from_objects_ = val; -} - -v8::Local V8ValueConverter::ToV8Value( - const base::Value* value, v8::Local context) const { - v8::Context::Scope context_scope(context); - v8::EscapableHandleScope handle_scope(context->GetIsolate()); - return handle_scope.Escape(ToV8ValueImpl(context->GetIsolate(), value)); -} - -base::Value* V8ValueConverter::FromV8Value( - v8::Local val, - v8::Local context) const { - v8::Context::Scope context_scope(context); - v8::HandleScope handle_scope(context->GetIsolate()); - FromV8ValueState state; - return FromV8ValueImpl(&state, val, context->GetIsolate()); -} - -v8::Local V8ValueConverter::ToV8ValueImpl( - v8::Isolate* isolate, const base::Value* value) const { - switch (value->GetType()) { - case base::Value::TYPE_NULL: - return v8::Null(isolate); - - case base::Value::TYPE_BOOLEAN: { - bool val = false; - value->GetAsBoolean(&val); - return v8::Boolean::New(isolate, val); - } - - case base::Value::TYPE_INTEGER: { - int val = 0; - value->GetAsInteger(&val); - return v8::Integer::New(isolate, val); - } - - case base::Value::TYPE_DOUBLE: { - double val = 0.0; - value->GetAsDouble(&val); - return v8::Number::New(isolate, val); - } - - case base::Value::TYPE_STRING: { - std::string val; - value->GetAsString(&val); - return v8::String::NewFromUtf8( - isolate, val.c_str(), v8::String::kNormalString, val.length()); - } - - case base::Value::TYPE_LIST: - return ToV8Array(isolate, static_cast(value)); - - case base::Value::TYPE_DICTIONARY: - return ToV8Object(isolate, - static_cast(value)); - - case base::Value::TYPE_BINARY: - return ToArrayBuffer(isolate, - static_cast(value)); - - default: - LOG(ERROR) << "Unexpected value type: " << value->GetType(); - return v8::Null(isolate); - } -} - -v8::Local V8ValueConverter::ToV8Array( - v8::Isolate* isolate, const base::ListValue* val) const { - v8::Local result(v8::Array::New(isolate, val->GetSize())); - - for (size_t i = 0; i < val->GetSize(); ++i) { - const base::Value* child = nullptr; - val->Get(i, &child); - - v8::Local child_v8 = ToV8ValueImpl(isolate, child); - - v8::TryCatch try_catch; - result->Set(static_cast(i), child_v8); - if (try_catch.HasCaught()) - LOG(ERROR) << "Setter for index " << i << " threw an exception."; - } - - return result; -} - -v8::Local V8ValueConverter::ToV8Object( - v8::Isolate* isolate, const base::DictionaryValue* val) const { - mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate); - result.SetHidden("simple", true); - - for (base::DictionaryValue::Iterator iter(*val); - !iter.IsAtEnd(); iter.Advance()) { - const std::string& key = iter.key(); - v8::Local child_v8 = ToV8ValueImpl(isolate, &iter.value()); - - v8::TryCatch try_catch; - result.Set(key, child_v8); - if (try_catch.HasCaught()) { - LOG(ERROR) << "Setter for property " << key.c_str() << " threw an " - << "exception."; - } - } - - return result.GetHandle(); -} - -v8::Local V8ValueConverter::ToArrayBuffer( - v8::Isolate* isolate, const base::BinaryValue* value) const { - return node::Buffer::Copy(isolate, - value->GetBuffer(), - value->GetSize()).ToLocalChecked(); -} - -base::Value* V8ValueConverter::FromV8ValueImpl( - FromV8ValueState* state, - v8::Local val, - v8::Isolate* isolate) const { - FromV8ValueState::Level state_level(state); - if (state->HasReachedMaxRecursionDepth()) - return nullptr; - - if (val->IsNull()) - return base::Value::CreateNullValue().release(); - - if (val->IsBoolean()) - return new base::FundamentalValue(val->ToBoolean()->Value()); - - if (val->IsInt32()) - return new base::FundamentalValue(val->ToInt32()->Value()); - - if (val->IsNumber()) - return new base::FundamentalValue(val->ToNumber()->Value()); - - if (val->IsString()) { - v8::String::Utf8Value utf8(val->ToString()); - return new base::StringValue(std::string(*utf8, utf8.length())); - } - - if (val->IsUndefined()) - // JSON.stringify ignores undefined. - return nullptr; - - if (val->IsDate()) { - v8::Date* date = v8::Date::Cast(*val); - v8::Local toISOString = - date->Get(v8::String::NewFromUtf8(isolate, "toISOString")); - if (toISOString->IsFunction()) { - v8::Local result = - toISOString.As()->Call(val, 0, nullptr); - if (!result.IsEmpty()) { - v8::String::Utf8Value utf8(result->ToString()); - return new base::StringValue(std::string(*utf8, utf8.length())); - } - } - } - - if (val->IsRegExp()) { - if (!reg_exp_allowed_) - // JSON.stringify converts to an object. - return FromV8Object(val->ToObject(), state, isolate); - return new base::StringValue(*v8::String::Utf8Value(val->ToString())); - } - - // v8::Value doesn't have a ToArray() method for some reason. - if (val->IsArray()) - return FromV8Array(val.As(), state, isolate); - - if (val->IsFunction()) { - if (!function_allowed_) - // JSON.stringify refuses to convert function(){}. - return nullptr; - return FromV8Object(val->ToObject(), state, isolate); - } - - if (node::Buffer::HasInstance(val)) { - return FromNodeBuffer(val, state, isolate); - } - - if (val->IsObject()) { - return FromV8Object(val->ToObject(), state, isolate); - } - - LOG(ERROR) << "Unexpected v8 value type encountered."; - return nullptr; -} - -base::Value* V8ValueConverter::FromV8Array( - v8::Local val, - FromV8ValueState* state, - v8::Isolate* isolate) const { - if (!state->UpdateAndCheckUniqueness(val)) - return base::Value::CreateNullValue().release(); - - std::unique_ptr scope; - // If val was created in a different context than our current one, change to - // that context, but change back after val is converted. - if (!val->CreationContext().IsEmpty() && - val->CreationContext() != isolate->GetCurrentContext()) - scope.reset(new v8::Context::Scope(val->CreationContext())); - - auto* result = new base::ListValue(); - - // Only fields with integer keys are carried over to the ListValue. - for (uint32_t i = 0; i < val->Length(); ++i) { - v8::TryCatch try_catch; - v8::Local child_v8 = val->Get(i); - if (try_catch.HasCaught()) { - LOG(ERROR) << "Getter for index " << i << " threw an exception."; - child_v8 = v8::Null(isolate); - } - - if (!val->HasRealIndexedProperty(i)) - continue; - - base::Value* child = FromV8ValueImpl(state, child_v8, isolate); - if (child) - result->Append(child); - else - // JSON.stringify puts null in places where values don't serialize, for - // example undefined and functions. Emulate that behavior. - result->Append(base::Value::CreateNullValue()); - } - return result; -} - -base::Value* V8ValueConverter::FromNodeBuffer( - v8::Local value, - FromV8ValueState* state, - v8::Isolate* isolate) const { - return base::BinaryValue::CreateWithCopiedBuffer( - node::Buffer::Data(value), node::Buffer::Length(value)); -} - -base::Value* V8ValueConverter::FromV8Object( - v8::Local val, - FromV8ValueState* state, - v8::Isolate* isolate) const { - if (!state->UpdateAndCheckUniqueness(val)) - return base::Value::CreateNullValue().release(); - - std::unique_ptr scope; - // If val was created in a different context than our current one, change to - // that context, but change back after val is converted. - if (!val->CreationContext().IsEmpty() && - val->CreationContext() != isolate->GetCurrentContext()) - scope.reset(new v8::Context::Scope(val->CreationContext())); - - std::unique_ptr result(new base::DictionaryValue()); - v8::Local property_names(val->GetOwnPropertyNames()); - - for (uint32_t i = 0; i < property_names->Length(); ++i) { - v8::Local key(property_names->Get(i)); - - // Extend this test to cover more types as necessary and if sensible. - if (!key->IsString() && - !key->IsNumber()) { - NOTREACHED() << "Key \"" << *v8::String::Utf8Value(key) << "\" " - "is neither a string nor a number"; - continue; - } - - // Skip all callbacks: crbug.com/139933 - if (val->HasRealNamedCallbackProperty(key->ToString())) - continue; - - v8::String::Utf8Value name_utf8(key->ToString()); - - v8::TryCatch try_catch; - v8::Local child_v8 = val->Get(key); - - if (try_catch.HasCaught()) { - LOG(ERROR) << "Getter for property " << *name_utf8 - << " threw an exception."; - child_v8 = v8::Null(isolate); - } - - std::unique_ptr child( - FromV8ValueImpl(state, child_v8, isolate)); - if (!child.get()) - // JSON.stringify skips properties whose values don't serialize, for - // example undefined and functions. Emulate that behavior. - continue; - - // Strip null if asked (and since undefined is turned into null, undefined - // too). The use case for supporting this is JSON-schema support, - // specifically for extensions, where "optional" JSON properties may be - // represented as null, yet due to buggy legacy code elsewhere isn't - // treated as such (potentially causing crashes). For example, the - // "tabs.create" function takes an object as its first argument with an - // optional "windowId" property. - // - // Given just - // - // tabs.create({}) - // - // this will work as expected on code that only checks for the existence of - // a "windowId" property (such as that legacy code). However given - // - // tabs.create({windowId: null}) - // - // there *is* a "windowId" property, but since it should be an int, code - // on the browser which doesn't additionally check for null will fail. - // We can avoid all bugs related to this by stripping null. - if (strip_null_from_objects_ && child->IsType(base::Value::TYPE_NULL)) - continue; - - result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()), - child.release()); - } - - return result.release(); -} - -} // namespace atom diff --git a/atom/common/native_mate_converters/v8_value_converter.h b/atom/common/native_mate_converters/v8_value_converter.h deleted file mode 100644 index 632587022d144..0000000000000 --- a/atom/common/native_mate_converters/v8_value_converter.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_V8_VALUE_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_V8_VALUE_CONVERTER_H_ - -#include "base/macros.h" -#include "base/compiler_specific.h" -#include "v8/include/v8.h" - -namespace base { -class BinaryValue; -class DictionaryValue; -class ListValue; -class Value; -} - -namespace atom { - -class V8ValueConverter { - public: - V8ValueConverter(); - - void SetRegExpAllowed(bool val); - void SetFunctionAllowed(bool val); - void SetStripNullFromObjects(bool val); - v8::Local ToV8Value(const base::Value* value, - v8::Local context) const; - base::Value* FromV8Value(v8::Local value, - v8::Local context) const; - - private: - class FromV8ValueState; - - v8::Local ToV8ValueImpl(v8::Isolate* isolate, - const base::Value* value) const; - v8::Local ToV8Array(v8::Isolate* isolate, - const base::ListValue* list) const; - v8::Local ToV8Object( - v8::Isolate* isolate, - const base::DictionaryValue* dictionary) const; - v8::Local ToArrayBuffer( - v8::Isolate* isolate, - const base::BinaryValue* value) const; - - base::Value* FromV8ValueImpl(FromV8ValueState* state, - v8::Local value, - v8::Isolate* isolate) const; - base::Value* FromV8Array(v8::Local array, - FromV8ValueState* state, - v8::Isolate* isolate) const; - base::Value* FromNodeBuffer(v8::Local value, - FromV8ValueState* state, - v8::Isolate* isolate) const; - base::Value* FromV8Object(v8::Local object, - FromV8ValueState* state, - v8::Isolate* isolate) const; - - // If true, we will convert RegExp JavaScript objects to string. - bool reg_exp_allowed_; - - // If true, we will convert Function JavaScript objects to dictionaries. - bool function_allowed_; - - // If true, undefined and null values are ignored when converting v8 objects - // into Values. - bool strip_null_from_objects_; - - DISALLOW_COPY_AND_ASSIGN(V8ValueConverter); -}; - -} // namespace atom - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_V8_VALUE_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/value_converter.cc b/atom/common/native_mate_converters/value_converter.cc deleted file mode 100644 index c3c7ae0383c5c..0000000000000 --- a/atom/common/native_mate_converters/value_converter.cc +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/native_mate_converters/value_converter.h" - -#include "atom/common/native_mate_converters/v8_value_converter.h" -#include "base/values.h" - -namespace mate { - -bool Converter::FromV8(v8::Isolate* isolate, - v8::Local val, - base::DictionaryValue* out) { - std::unique_ptr converter(new atom::V8ValueConverter); - std::unique_ptr value(converter->FromV8Value( - val, isolate->GetCurrentContext())); - if (value && value->IsType(base::Value::TYPE_DICTIONARY)) { - out->Swap(static_cast(value.get())); - return true; - } else { - return false; - } -} - -v8::Local Converter::ToV8( - v8::Isolate* isolate, - const base::DictionaryValue& val) { - std::unique_ptr converter(new atom::V8ValueConverter); - return converter->ToV8Value(&val, isolate->GetCurrentContext()); -} - -bool Converter::FromV8(v8::Isolate* isolate, - v8::Local val, - base::ListValue* out) { - std::unique_ptr converter(new atom::V8ValueConverter); - std::unique_ptr value(converter->FromV8Value( - val, isolate->GetCurrentContext())); - if (value->IsType(base::Value::TYPE_LIST)) { - out->Swap(static_cast(value.get())); - return true; - } else { - return false; - } -} - -v8::Local Converter::ToV8( - v8::Isolate* isolate, - const base::ListValue& val) { - std::unique_ptr converter(new atom::V8ValueConverter); - return converter->ToV8Value(&val, isolate->GetCurrentContext()); -} - -} // namespace mate diff --git a/atom/common/native_mate_converters/value_converter.h b/atom/common/native_mate_converters/value_converter.h deleted file mode 100644 index 013dd99cc7980..0000000000000 --- a/atom/common/native_mate_converters/value_converter.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NATIVE_MATE_CONVERTERS_VALUE_CONVERTER_H_ -#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_VALUE_CONVERTER_H_ - -#include "native_mate/converter.h" - -namespace base { -class DictionaryValue; -class ListValue; -} - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - base::DictionaryValue* out); - static v8::Local ToV8(v8::Isolate* isolate, - const base::DictionaryValue& val); -}; - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - base::ListValue* out); - static v8::Local ToV8(v8::Isolate* isolate, - const base::ListValue& val); -}; - -} // namespace mate - -#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_VALUE_CONVERTER_H_ diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc deleted file mode 100644 index 2207046d8e02a..0000000000000 --- a/atom/common/node_bindings.cc +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/node_bindings.h" - -#include -#include - -#include "atom/common/api/event_emitter_caller.h" -#include "atom/common/api/locker.h" -#include "atom/common/atom_command_line.h" -#include "atom/common/native_mate_converters/file_path_converter.h" -#include "base/command_line.h" -#include "base/base_paths.h" -#include "base/environment.h" -#include "base/files/file_path.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/common/content_paths.h" -#include "native_mate/dictionary.h" - -#include "atom/common/node_includes.h" - -using content::BrowserThread; - -// Force all builtin modules to be referenced so they can actually run their -// DSO constructors, see http://git.io/DRIqCg. -#define REFERENCE_MODULE(name) \ - extern "C" void _register_ ## name(void); \ - void (*fp_register_ ## name)(void) = _register_ ## name -// Electron's builtin modules. -REFERENCE_MODULE(atom_browser_app); -REFERENCE_MODULE(atom_browser_auto_updater); -REFERENCE_MODULE(atom_browser_content_tracing); -REFERENCE_MODULE(atom_browser_dialog); -REFERENCE_MODULE(atom_browser_debugger); -REFERENCE_MODULE(atom_browser_desktop_capturer); -REFERENCE_MODULE(atom_browser_download_item); -REFERENCE_MODULE(atom_browser_menu); -REFERENCE_MODULE(atom_browser_power_monitor); -REFERENCE_MODULE(atom_browser_power_save_blocker); -REFERENCE_MODULE(atom_browser_protocol); -REFERENCE_MODULE(atom_browser_global_shortcut); -REFERENCE_MODULE(atom_browser_render_process_preferences); -REFERENCE_MODULE(atom_browser_session); -REFERENCE_MODULE(atom_browser_system_preferences); -REFERENCE_MODULE(atom_browser_tray); -REFERENCE_MODULE(atom_browser_web_contents); -REFERENCE_MODULE(atom_browser_web_view_manager); -REFERENCE_MODULE(atom_browser_window); -REFERENCE_MODULE(atom_common_asar); -REFERENCE_MODULE(atom_common_clipboard); -REFERENCE_MODULE(atom_common_crash_reporter); -REFERENCE_MODULE(atom_common_native_image); -REFERENCE_MODULE(atom_common_screen); -REFERENCE_MODULE(atom_common_shell); -REFERENCE_MODULE(atom_common_v8_util); -REFERENCE_MODULE(atom_renderer_ipc); -REFERENCE_MODULE(atom_renderer_web_frame); -#undef REFERENCE_MODULE - -// The "v8::Function::kLineOffsetNotFound" is exported in node.dll, but the -// linker can not find it, could be a bug of VS. -#if defined(OS_WIN) && !defined(DEBUG) -namespace v8 { -const int Function::kLineOffsetNotFound = -1; -} -#endif - -namespace atom { - -namespace { - -// Convert the given vector to an array of C-strings. The strings in the -// returned vector are only guaranteed valid so long as the vector of strings -// is not modified. -std::unique_ptr StringVectorToArgArray( - const std::vector& vector) { - std::unique_ptr array(new const char*[vector.size()]); - for (size_t i = 0; i < vector.size(); ++i) { - array[i] = vector[i].c_str(); - } - return array; -} - -base::FilePath GetResourcesPath(bool is_browser) { - auto command_line = base::CommandLine::ForCurrentProcess(); - base::FilePath exec_path(command_line->GetProgram()); - PathService::Get(base::FILE_EXE, &exec_path); - - base::FilePath resources_path = -#if defined(OS_MACOSX) - is_browser ? exec_path.DirName().DirName().Append("Resources") : - exec_path.DirName().DirName().DirName().DirName().DirName() - .Append("Resources"); -#else - exec_path.DirName().Append(FILE_PATH_LITERAL("resources")); -#endif - return resources_path; -} - -} // namespace - -NodeBindings::NodeBindings(bool is_browser) - : is_browser_(is_browser), - message_loop_(nullptr), - uv_loop_(uv_default_loop()), - embed_closed_(false), - uv_env_(nullptr), - weak_factory_(this) { -} - -NodeBindings::~NodeBindings() { - // Quit the embed thread. - embed_closed_ = true; - uv_sem_post(&embed_sem_); - WakeupEmbedThread(); - - // Wait for everything to be done. - uv_thread_join(&embed_thread_); - - // Clear uv. - uv_sem_destroy(&embed_sem_); -} - -void NodeBindings::Initialize() { - // Open node's error reporting system for browser process. - node::g_standalone_mode = is_browser_; - node::g_upstream_node_mode = false; - -#if defined(OS_LINUX) - // Get real command line in renderer process forked by zygote. - if (!is_browser_) - AtomCommandLine::InitializeFromCommandLine(); -#endif - - // Init node. - // (we assume node::Init would not modify the parameters under embedded mode). - node::Init(nullptr, nullptr, nullptr, nullptr); - -#if defined(OS_WIN) - // uv_init overrides error mode to suppress the default crash dialog, bring - // it back if user wants to show it. - std::unique_ptr env(base::Environment::Create()); - if (env->HasVar("ELECTRON_DEFAULT_ERROR_MODE")) - SetErrorMode(0); -#endif -} - -node::Environment* NodeBindings::CreateEnvironment( - v8::Handle context) { - auto args = AtomCommandLine::argv(); - - // Feed node the path to initialization script. - base::FilePath::StringType process_type = is_browser_ ? - FILE_PATH_LITERAL("browser") : FILE_PATH_LITERAL("renderer"); - base::FilePath resources_path = GetResourcesPath(is_browser_); - base::FilePath script_path = - resources_path.Append(FILE_PATH_LITERAL("electron.asar")) - .Append(process_type) - .Append(FILE_PATH_LITERAL("init.js")); - std::string script_path_str = script_path.AsUTF8Unsafe(); - args.insert(args.begin() + 1, script_path_str.c_str()); - - std::unique_ptr c_argv = StringVectorToArgArray(args); - node::Environment* env = node::CreateEnvironment( - context->GetIsolate(), uv_default_loop(), context, - args.size(), c_argv.get(), 0, nullptr); - - // Node turns off AutorunMicrotasks, but we need it in web pages to match the - // behavior of Chrome. - if (!is_browser_) - context->GetIsolate()->SetAutorunMicrotasks(true); - - mate::Dictionary process(context->GetIsolate(), env->process_object()); - process.Set("type", process_type); - process.Set("resourcesPath", resources_path); - // Do not set DOM globals for renderer process. - if (!is_browser_) - process.Set("_noBrowserGlobals", resources_path); - // The path to helper app. - base::FilePath helper_exec_path; - PathService::Get(content::CHILD_PROCESS_EXE, &helper_exec_path); - process.Set("helperExecPath", helper_exec_path); - return env; -} - -void NodeBindings::LoadEnvironment(node::Environment* env) { - node::LoadEnvironment(env); - mate::EmitEvent(env->isolate(), env->process_object(), "loaded"); -} - -void NodeBindings::PrepareMessageLoop() { - DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // Add dummy handle for libuv, otherwise libuv would quit when there is - // nothing to do. - uv_async_init(uv_loop_, &dummy_uv_handle_, nullptr); - - // Start worker that will interrupt main loop when having uv events. - uv_sem_init(&embed_sem_, 0); - uv_thread_create(&embed_thread_, EmbedThreadRunner, this); -} - -void NodeBindings::RunMessageLoop() { - DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // The MessageLoop should have been created, remember the one in main thread. - message_loop_ = base::MessageLoop::current(); - - // Run uv loop for once to give the uv__io_poll a chance to add all events. - UvRunOnce(); -} - -void NodeBindings::UvRunOnce() { - DCHECK(!is_browser_ || BrowserThread::CurrentlyOn(BrowserThread::UI)); - - node::Environment* env = uv_env(); - - // Use Locker in browser process. - mate::Locker locker(env->isolate()); - v8::HandleScope handle_scope(env->isolate()); - - // Enter node context while dealing with uv events. - v8::Context::Scope context_scope(env->context()); - - // Perform microtask checkpoint after running JavaScript. - v8::MicrotasksScope script_scope(env->isolate(), - v8::MicrotasksScope::kRunMicrotasks); - - // Deal with uv events. - int r = uv_run(uv_loop_, UV_RUN_NOWAIT); - if (r == 0) - message_loop_->QuitWhenIdle(); // Quit from uv. - - // Tell the worker thread to continue polling. - uv_sem_post(&embed_sem_); -} - -void NodeBindings::WakeupMainThread() { - DCHECK(message_loop_); - message_loop_->PostTask(FROM_HERE, base::Bind(&NodeBindings::UvRunOnce, - weak_factory_.GetWeakPtr())); -} - -void NodeBindings::WakeupEmbedThread() { - uv_async_send(&dummy_uv_handle_); -} - -// static -void NodeBindings::EmbedThreadRunner(void *arg) { - NodeBindings* self = static_cast(arg); - - while (true) { - // Wait for the main loop to deal with events. - uv_sem_wait(&self->embed_sem_); - if (self->embed_closed_) - break; - - // Wait for something to happen in uv loop. - // Note that the PollEvents() is implemented by derived classes, so when - // this class is being destructed the PollEvents() would not be available - // anymore. Because of it we must make sure we only invoke PollEvents() - // when this class is alive. - self->PollEvents(); - if (self->embed_closed_) - break; - - // Deal with event in main thread. - self->WakeupMainThread(); - } -} - -} // namespace atom diff --git a/atom/common/node_bindings.h b/atom/common/node_bindings.h deleted file mode 100644 index 16d512d3bed03..0000000000000 --- a/atom/common/node_bindings.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NODE_BINDINGS_H_ -#define ATOM_COMMON_NODE_BINDINGS_H_ - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "v8/include/v8.h" -#include "vendor/node/deps/uv/include/uv.h" - -namespace base { -class MessageLoop; -} - -namespace node { -class Environment; -} - -namespace atom { - -class NodeBindings { - public: - static NodeBindings* Create(bool is_browser); - - virtual ~NodeBindings(); - - // Setup V8, libuv. - void Initialize(); - - // Create the environment and load node.js. - node::Environment* CreateEnvironment(v8::Handle context); - - // Load node.js in the environment. - void LoadEnvironment(node::Environment* env); - - // Prepare for message loop integration. - void PrepareMessageLoop(); - - // Do message loop integration. - virtual void RunMessageLoop(); - - // Gets/sets the environment to wrap uv loop. - void set_uv_env(node::Environment* env) { uv_env_ = env; } - node::Environment* uv_env() const { return uv_env_; } - - protected: - explicit NodeBindings(bool is_browser); - - // Called to poll events in new thread. - virtual void PollEvents() = 0; - - // Run the libuv loop for once. - void UvRunOnce(); - - // Make the main thread run libuv loop. - void WakeupMainThread(); - - // Interrupt the PollEvents. - void WakeupEmbedThread(); - - // Are we running in browser. - bool is_browser_; - - // Main thread's MessageLoop. - base::MessageLoop* message_loop_; - - // Main thread's libuv loop. - uv_loop_t* uv_loop_; - - private: - // Thread to poll uv events. - static void EmbedThreadRunner(void *arg); - - // Whether the libuv loop has ended. - bool embed_closed_; - - // Dummy handle to make uv's loop not quit. - uv_async_t dummy_uv_handle_; - - // Thread for polling events. - uv_thread_t embed_thread_; - - // Semaphore to wait for main loop in the embed thread. - uv_sem_t embed_sem_; - - // Environment that to wrap the uv loop. - node::Environment* uv_env_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(NodeBindings); -}; - -} // namespace atom - -#endif // ATOM_COMMON_NODE_BINDINGS_H_ diff --git a/atom/common/node_bindings_linux.cc b/atom/common/node_bindings_linux.cc deleted file mode 100644 index 34b9ea952365e..0000000000000 --- a/atom/common/node_bindings_linux.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/node_bindings_linux.h" - -#include - -namespace atom { - -NodeBindingsLinux::NodeBindingsLinux(bool is_browser) - : NodeBindings(is_browser), - epoll_(epoll_create(1)) { - int backend_fd = uv_backend_fd(uv_loop_); - struct epoll_event ev = { 0 }; - ev.events = EPOLLIN; - ev.data.fd = backend_fd; - epoll_ctl(epoll_, EPOLL_CTL_ADD, backend_fd, &ev); -} - -NodeBindingsLinux::~NodeBindingsLinux() { -} - -void NodeBindingsLinux::RunMessageLoop() { - // Get notified when libuv's watcher queue changes. - uv_loop_->data = this; - uv_loop_->on_watcher_queue_updated = OnWatcherQueueChanged; - - NodeBindings::RunMessageLoop(); -} - -// static -void NodeBindingsLinux::OnWatcherQueueChanged(uv_loop_t* loop) { - NodeBindingsLinux* self = static_cast(loop->data); - - // We need to break the io polling in the epoll thread when loop's watcher - // queue changes, otherwise new events cannot be notified. - self->WakeupEmbedThread(); -} - -void NodeBindingsLinux::PollEvents() { - int timeout = uv_backend_timeout(uv_loop_); - - // Wait for new libuv events. - int r; - do { - struct epoll_event ev; - r = epoll_wait(epoll_, &ev, 1, timeout); - } while (r == -1 && errno == EINTR); -} - -// static -NodeBindings* NodeBindings::Create(bool is_browser) { - return new NodeBindingsLinux(is_browser); -} - -} // namespace atom diff --git a/atom/common/node_bindings_linux.h b/atom/common/node_bindings_linux.h deleted file mode 100644 index 3bbea9f9dd0a3..0000000000000 --- a/atom/common/node_bindings_linux.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NODE_BINDINGS_LINUX_H_ -#define ATOM_COMMON_NODE_BINDINGS_LINUX_H_ - -#include "base/compiler_specific.h" -#include "atom/common/node_bindings.h" - -namespace atom { - -class NodeBindingsLinux : public NodeBindings { - public: - explicit NodeBindingsLinux(bool is_browser); - virtual ~NodeBindingsLinux(); - - void RunMessageLoop() override; - - private: - // Called when uv's watcher queue changes. - static void OnWatcherQueueChanged(uv_loop_t* loop); - - void PollEvents() override; - - // Epoll to poll for uv's backend fd. - int epoll_; - - DISALLOW_COPY_AND_ASSIGN(NodeBindingsLinux); -}; - -} // namespace atom - -#endif // ATOM_COMMON_NODE_BINDINGS_LINUX_H_ diff --git a/atom/common/node_bindings_mac.cc b/atom/common/node_bindings_mac.cc deleted file mode 100644 index cbcbdba360508..0000000000000 --- a/atom/common/node_bindings_mac.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/node_bindings_mac.h" - -#include -#include -#include -#include -#include - -#include "atom/common/node_includes.h" - -namespace atom { - -NodeBindingsMac::NodeBindingsMac(bool is_browser) - : NodeBindings(is_browser) { -} - -NodeBindingsMac::~NodeBindingsMac() { -} - -void NodeBindingsMac::RunMessageLoop() { - // Get notified when libuv's watcher queue changes. - uv_loop_->data = this; - uv_loop_->on_watcher_queue_updated = OnWatcherQueueChanged; - - NodeBindings::RunMessageLoop(); -} - -// static -void NodeBindingsMac::OnWatcherQueueChanged(uv_loop_t* loop) { - NodeBindingsMac* self = static_cast(loop->data); - - // We need to break the io polling in the kqueue thread when loop's watcher - // queue changes, otherwise new events cannot be notified. - self->WakeupEmbedThread(); -} - -void NodeBindingsMac::PollEvents() { - struct timeval tv; - int timeout = uv_backend_timeout(uv_loop_); - if (timeout != -1) { - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - } - - fd_set readset; - int fd = uv_backend_fd(uv_loop_); - FD_ZERO(&readset); - FD_SET(fd, &readset); - - // Wait for new libuv events. - int r; - do { - r = select(fd + 1, &readset, nullptr, nullptr, - timeout == -1 ? nullptr : &tv); - } while (r == -1 && errno == EINTR); -} - -// static -NodeBindings* NodeBindings::Create(bool is_browser) { - return new NodeBindingsMac(is_browser); -} - -} // namespace atom diff --git a/atom/common/node_bindings_mac.h b/atom/common/node_bindings_mac.h deleted file mode 100644 index 96c79ec6f0df4..0000000000000 --- a/atom/common/node_bindings_mac.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NODE_BINDINGS_MAC_H_ -#define ATOM_COMMON_NODE_BINDINGS_MAC_H_ - -#include "atom/common/node_bindings.h" -#include "base/compiler_specific.h" - -namespace atom { - -class NodeBindingsMac : public NodeBindings { - public: - explicit NodeBindingsMac(bool is_browser); - virtual ~NodeBindingsMac(); - - void RunMessageLoop() override; - - private: - // Called when uv's watcher queue changes. - static void OnWatcherQueueChanged(uv_loop_t* loop); - - void PollEvents() override; - - DISALLOW_COPY_AND_ASSIGN(NodeBindingsMac); -}; - -} // namespace atom - -#endif // ATOM_COMMON_NODE_BINDINGS_MAC_H_ diff --git a/atom/common/node_bindings_win.cc b/atom/common/node_bindings_win.cc deleted file mode 100644 index b8de4f59da3b7..0000000000000 --- a/atom/common/node_bindings_win.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/node_bindings_win.h" - -#include - -#include "base/logging.h" - -extern "C" { -#include "vendor/node/deps/uv/src/win/internal.h" -} - -namespace atom { - -NodeBindingsWin::NodeBindingsWin(bool is_browser) - : NodeBindings(is_browser) { -} - -NodeBindingsWin::~NodeBindingsWin() { -} - -void NodeBindingsWin::PollEvents() { - // If there are other kinds of events pending, uv_backend_timeout will - // instruct us not to wait. - DWORD bytes, timeout; - ULONG_PTR key; - OVERLAPPED* overlapped; - - timeout = uv_backend_timeout(uv_loop_); - - GetQueuedCompletionStatus(uv_loop_->iocp, - &bytes, - &key, - &overlapped, - timeout); - - // Give the event back so libuv can deal with it. - if (overlapped != NULL) - PostQueuedCompletionStatus(uv_loop_->iocp, - bytes, - key, - overlapped); -} - -// static -NodeBindings* NodeBindings::Create(bool is_browser) { - return new NodeBindingsWin(is_browser); -} - -} // namespace atom diff --git a/atom/common/node_bindings_win.h b/atom/common/node_bindings_win.h deleted file mode 100644 index 3950098e5ebfb..0000000000000 --- a/atom/common/node_bindings_win.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NODE_BINDINGS_WIN_H_ -#define ATOM_COMMON_NODE_BINDINGS_WIN_H_ - -#include "atom/common/node_bindings.h" -#include "base/compiler_specific.h" - -namespace atom { - -class NodeBindingsWin : public NodeBindings { - public: - explicit NodeBindingsWin(bool is_browser); - virtual ~NodeBindingsWin(); - - private: - void PollEvents() override; - - DISALLOW_COPY_AND_ASSIGN(NodeBindingsWin); -}; - -} // namespace atom - -#endif // ATOM_COMMON_NODE_BINDINGS_WIN_H_ diff --git a/atom/common/node_includes.h b/atom/common/node_includes.h deleted file mode 100644 index 01efa6b154709..0000000000000 --- a/atom/common/node_includes.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_NODE_INCLUDES_H_ -#define ATOM_COMMON_NODE_INCLUDES_H_ - -#include "base/logging.h" - -// Include common headers for using node APIs. - -#define BUILDING_NODE_EXTENSION - -#undef ASSERT -#undef CHECK -#undef CHECK_EQ -#undef CHECK_NE -#undef CHECK_GE -#undef CHECK_GT -#undef CHECK_LE -#undef CHECK_LT -#undef UNLIKELY -#undef DISALLOW_COPY_AND_ASSIGN -#undef NO_RETURN -#undef arraysize -#undef debug_string // This is defined in macOS 10.9 SDK in AssertMacros.h. -#include "vendor/node/src/env.h" -#include "vendor/node/src/env-inl.h" -#include "vendor/node/src/node.h" -#include "vendor/node/src/node_buffer.h" -#include "vendor/node/src/node_internals.h" - -#endif // ATOM_COMMON_NODE_INCLUDES_H_ diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc deleted file mode 100644 index 6b514599f085c..0000000000000 --- a/atom/common/options_switches.cc +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/options_switches.h" - -namespace atom { - -namespace options { - -const char kTitle[] = "title"; -const char kIcon[] = "icon"; -const char kFrame[] = "frame"; -const char kShow[] = "show"; -const char kCenter[] = "center"; -const char kX[] = "x"; -const char kY[] = "y"; -const char kWidth[] = "width"; -const char kHeight[] = "height"; -const char kMinWidth[] = "minWidth"; -const char kMinHeight[] = "minHeight"; -const char kMaxWidth[] = "maxWidth"; -const char kMaxHeight[] = "maxHeight"; -const char kResizable[] = "resizable"; -const char kMovable[] = "movable"; -const char kMinimizable[] = "minimizable"; -const char kMaximizable[] = "maximizable"; -const char kFullScreenable[] = "fullscreenable"; -const char kClosable[] = "closable"; -const char kFullscreen[] = "fullscreen"; - -// Whether the window should show in taskbar. -const char kSkipTaskbar[] = "skipTaskbar"; - -// Start with the kiosk mode, see Opera's page for description: -// http://www.opera.com/support/mastering/kiosk/ -const char kKiosk[] = "kiosk"; - -// Make windows stays on the top of all other windows. -const char kAlwaysOnTop[] = "alwaysOnTop"; - -// Enable the NSView to accept first mouse event. -const char kAcceptFirstMouse[] = "acceptFirstMouse"; - -// Whether window size should include window frame. -const char kUseContentSize[] = "useContentSize"; - -// The requested title bar style for the window -const char kTitleBarStyle[] = "titleBarStyle"; - -// The menu bar is hidden unless "Alt" is pressed. -const char kAutoHideMenuBar[] = "autoHideMenuBar"; - -// Enable window to be resized larger than screen. -const char kEnableLargerThanScreen[] = "enableLargerThanScreen"; - -// Forces to use dark theme on Linux. -const char kDarkTheme[] = "darkTheme"; - -// Whether the window should be transparent. -const char kTransparent[] = "transparent"; - -// Window type hint. -const char kType[] = "type"; - -// Disable auto-hiding cursor. -const char kDisableAutoHideCursor[] = "disableAutoHideCursor"; - -// Use the macOS' standard window instead of the textured window. -const char kStandardWindow[] = "standardWindow"; - -// Default browser window background color. -const char kBackgroundColor[] = "backgroundColor"; - -// Whether the window should have a shadow. -const char kHasShadow[] = "hasShadow"; - -// Whether the window can be activated. -const char kFocusable[] = "focusable"; - -// The WebPreferences. -const char kWebPreferences[] = "webPreferences"; - -// The factor of which page should be zoomed. -const char kZoomFactor[] = "zoomFactor"; - -// Script that will be loaded by guest WebContents before other scripts. -const char kPreloadScript[] = "preload"; - -// Like --preload, but the passed argument is an URL. -const char kPreloadURL[] = "preloadURL"; - -// Enable the node integration. -const char kNodeIntegration[] = "nodeIntegration"; - -// Instancd ID of guest WebContents. -const char kGuestInstanceID[] = "guestInstanceId"; - -// Web runtime features. -const char kExperimentalFeatures[] = "experimentalFeatures"; -const char kExperimentalCanvasFeatures[] = "experimentalCanvasFeatures"; - -// Opener window's ID. -const char kOpenerID[] = "openerId"; - -// Enable the rubber banding effect. -const char kScrollBounce[] = "scrollBounce"; - -// Enable blink features. -// TODO(kevinsawicki) Rename to enableBlinkFeatures in 2.0 -const char kBlinkFeatures[] = "blinkFeatures"; - -// Disable blink features. -const char kDisableBlinkFeatures[] = "disableBlinkFeatures"; - -} // namespace options - -namespace switches { - -// Enable plugins. -const char kEnablePlugins[] = "enable-plugins"; - -// Ppapi Flash path. -const char kPpapiFlashPath[] = "ppapi-flash-path"; - -// Ppapi Flash version. -const char kPpapiFlashVersion[] = "ppapi-flash-version"; - -// Disable HTTP cache. -const char kDisableHttpCache[] = "disable-http-cache"; - -// The list of standard schemes. -const char kStandardSchemes[] = "standard-schemes"; - -// Register schemes to handle service worker. -const char kRegisterServiceWorkerSchemes[] = "register-service-worker-schemes"; - -// The minimum SSL/TLS version ("tls1", "tls1.1", or "tls1.2") that -// TLS fallback will accept. -const char kSSLVersionFallbackMin[] = "ssl-version-fallback-min"; - -// Comma-separated list of SSL cipher suites to disable. -const char kCipherSuiteBlacklist[] = "cipher-suite-blacklist"; - -// The browser process app model ID -const char kAppUserModelId[] = "app-user-model-id"; - -// The command line switch versions of the options. -const char kBackgroundColor[] = "background-color"; -const char kZoomFactor[] = "zoom-factor"; -const char kPreloadScript[] = "preload"; -const char kPreloadURL[] = "preload-url"; -const char kNodeIntegration[] = "node-integration"; -const char kGuestInstanceID[] = "guest-instance-id"; -const char kOpenerID[] = "opener-id"; -const char kScrollBounce[] = "scroll-bounce"; - -// Widevine options -// Path to Widevine CDM binaries. -const char kWidevineCdmPath[] = "widevine-cdm-path"; -// Widevine CDM version. -const char kWidevineCdmVersion[] = "widevine-cdm-version"; - -} // namespace switches - -} // namespace atom diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h deleted file mode 100644 index 54c638772887d..0000000000000 --- a/atom/common/options_switches.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_OPTIONS_SWITCHES_H_ -#define ATOM_COMMON_OPTIONS_SWITCHES_H_ - -namespace atom { - -namespace options { - -extern const char kTitle[]; -extern const char kIcon[]; -extern const char kFrame[]; -extern const char kShow[]; -extern const char kCenter[]; -extern const char kX[]; -extern const char kY[]; -extern const char kWidth[]; -extern const char kHeight[]; -extern const char kMinWidth[]; -extern const char kMinHeight[]; -extern const char kMaxWidth[]; -extern const char kMaxHeight[]; -extern const char kResizable[]; -extern const char kMovable[]; -extern const char kMinimizable[]; -extern const char kMaximizable[]; -extern const char kFullScreenable[]; -extern const char kClosable[]; -extern const char kFullscreen[]; -extern const char kSkipTaskbar[]; -extern const char kKiosk[]; -extern const char kAlwaysOnTop[]; -extern const char kAcceptFirstMouse[]; -extern const char kUseContentSize[]; -extern const char kTitleBarStyle[]; -extern const char kAutoHideMenuBar[]; -extern const char kEnableLargerThanScreen[]; -extern const char kDarkTheme[]; -extern const char kTransparent[]; -extern const char kType[]; -extern const char kDisableAutoHideCursor[]; -extern const char kStandardWindow[]; -extern const char kBackgroundColor[]; -extern const char kHasShadow[]; -extern const char kFocusable[]; -extern const char kWebPreferences[]; - -// WebPreferences. -extern const char kZoomFactor[]; -extern const char kPreloadScript[]; -extern const char kPreloadURL[]; -extern const char kNodeIntegration[]; -extern const char kGuestInstanceID[]; -extern const char kExperimentalFeatures[]; -extern const char kExperimentalCanvasFeatures[]; -extern const char kOpenerID[]; -extern const char kScrollBounce[]; -extern const char kBlinkFeatures[]; -extern const char kDisableBlinkFeatures[]; - -} // namespace options - - -// Following are actually command line switches, should be moved to other files. - -namespace switches { - -extern const char kEnablePlugins[]; -extern const char kPpapiFlashPath[]; -extern const char kPpapiFlashVersion[]; -extern const char kDisableHttpCache[]; -extern const char kStandardSchemes[]; -extern const char kRegisterServiceWorkerSchemes[]; -extern const char kSSLVersionFallbackMin[]; -extern const char kCipherSuiteBlacklist[]; -extern const char kAppUserModelId[]; - -extern const char kBackgroundColor[]; -extern const char kZoomFactor[]; -extern const char kPreloadScript[]; -extern const char kPreloadURL[]; -extern const char kNodeIntegration[]; -extern const char kGuestInstanceID[]; -extern const char kOpenerID[]; -extern const char kScrollBounce[]; - -extern const char kWidevineCdmPath[]; -extern const char kWidevineCdmVersion[]; - -} // namespace switches - -} // namespace atom - -#endif // ATOM_COMMON_OPTIONS_SWITCHES_H_ diff --git a/atom/common/platform_util.h b/atom/common/platform_util.h deleted file mode 100644 index 262f0a2e6e497..0000000000000 --- a/atom/common/platform_util.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_COMMON_PLATFORM_UTIL_H_ -#define ATOM_COMMON_PLATFORM_UTIL_H_ - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include "base/strings/string16.h" -#endif - -class GURL; - -namespace base { -class FilePath; -} - -namespace platform_util { - -// Show the given file in a file manager. If possible, select the file. -// Must be called from the UI thread. -void ShowItemInFolder(const base::FilePath& full_path); - -// Open the given file in the desktop's default manner. -// Must be called from the UI thread. -void OpenItem(const base::FilePath& full_path); - -// Open the given external protocol URL in the desktop's default manner. -// (For example, mailto: URLs in the default mail user agent.) -bool OpenExternal( -#if defined(OS_WIN) - const base::string16& url, -#else - const GURL& url, -#endif - bool activate); - -// Move a file to trash. -bool MoveItemToTrash(const base::FilePath& full_path); - -void Beep(); - -} // namespace platform_util - -#endif // ATOM_COMMON_PLATFORM_UTIL_H_ diff --git a/atom/common/platform_util_linux.cc b/atom/common/platform_util_linux.cc deleted file mode 100644 index 9811c8760d066..0000000000000 --- a/atom/common/platform_util_linux.cc +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/platform_util.h" - -#include - -#include "base/files/file_util.h" -#include "base/process/kill.h" -#include "base/process/launch.h" -#include "url/gurl.h" - -namespace { - -bool XDGUtil(const std::string& util, - const std::string& arg, - const bool wait_for_exit) { - std::vector argv; - argv.push_back(util); - argv.push_back(arg); - - base::LaunchOptions options; - options.allow_new_privs = true; - // xdg-open can fall back on mailcap which eventually might plumb through - // to a command that needs a terminal. Set the environment variable telling - // it that we definitely don't have a terminal available and that it should - // bring up a new terminal if necessary. See "man mailcap". - options.environ["MM_NOTTTY"] = "1"; - - base::Process process = base::LaunchProcess(argv, options); - if (!process.IsValid()) - return false; - - if (!wait_for_exit) { - base::EnsureProcessGetsReaped(process.Pid()); - return true; - } - - int exit_code = -1; - if (!process.WaitForExit(&exit_code)) - return false; - - return (exit_code == 0); -} - -bool XDGOpen(const std::string& path, const bool wait_for_exit) { - return XDGUtil("xdg-open", path, wait_for_exit); -} - -bool XDGEmail(const std::string& email, const bool wait_for_exit) { - return XDGUtil("xdg-email", email, wait_for_exit); -} - -} // namespace - -namespace platform_util { - -// TODO(estade): It would be nice to be able to select the file in the file -// manager, but that probably requires extending xdg-open. For now just -// show the folder. -void ShowItemInFolder(const base::FilePath& full_path) { - base::FilePath dir = full_path.DirName(); - if (!base::DirectoryExists(dir)) - return; - - XDGOpen(dir.value(), true); -} - -void OpenItem(const base::FilePath& full_path) { - XDGOpen(full_path.value(), true); -} - -bool OpenExternal(const GURL& url, bool activate) { - // Don't wait for exit, since we don't want to wait for the browser/email - // client window to close before returning - if (url.SchemeIs("mailto")) - return XDGEmail(url.spec(), false); - else - return XDGOpen(url.spec(), false); -} - -bool MoveItemToTrash(const base::FilePath& full_path) { - return XDGUtil("gvfs-trash", full_path.value(), true); -} - -void Beep() { - // echo '\a' > /dev/console - FILE* console = fopen("/dev/console", "r"); - if (console == NULL) - return; - fprintf(console, "\a"); - fclose(console); -} - -} // namespace platform_util diff --git a/atom/common/platform_util_mac.mm b/atom/common/platform_util_mac.mm deleted file mode 100644 index d0146b11e0857..0000000000000 --- a/atom/common/platform_util_mac.mm +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/platform_util.h" - -#include -#import - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/mac/mac_logging.h" -#include "base/mac/scoped_aedesc.h" -#include "base/strings/sys_string_conversions.h" -#include "net/base/mac/url_conversions.h" -#include "url/gurl.h" - -namespace platform_util { - -void ShowItemInFolder(const base::FilePath& path) { - // The API only takes absolute path. - base::FilePath full_path = - path.IsAbsolute() ? path : base::MakeAbsoluteFilePath(path); - - DCHECK([NSThread isMainThread]); - NSString* path_string = base::SysUTF8ToNSString(full_path.value()); - if (!path_string || ![[NSWorkspace sharedWorkspace] selectFile:path_string - inFileViewerRootedAtPath:@""]) - LOG(WARNING) << "NSWorkspace failed to select file " << full_path.value(); -} - -// This function opens a file. This doesn't use LaunchServices or NSWorkspace -// because of two bugs: -// 1. Incorrect app activation with com.apple.quarantine: -// http://crbug.com/32921 -// 2. Silent no-op for unassociated file types: http://crbug.com/50263 -// Instead, an AppleEvent is constructed to tell the Finder to open the -// document. -void OpenItem(const base::FilePath& full_path) { - DCHECK([NSThread isMainThread]); - NSString* path_string = base::SysUTF8ToNSString(full_path.value()); - if (!path_string) - return; - - // Create the target of this AppleEvent, the Finder. - base::mac::ScopedAEDesc address; - const OSType finderCreatorCode = 'MACS'; - OSErr status = AECreateDesc(typeApplSignature, // type - &finderCreatorCode, // data - sizeof(finderCreatorCode), // dataSize - address.OutPointer()); // result - if (status != noErr) { - OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE target"; - return; - } - - // Build the AppleEvent data structure that instructs Finder to open files. - base::mac::ScopedAEDesc theEvent; - status = AECreateAppleEvent(kCoreEventClass, // theAEEventClass - kAEOpenDocuments, // theAEEventID - address, // target - kAutoGenerateReturnID, // returnID - kAnyTransactionID, // transactionID - theEvent.OutPointer()); // result - if (status != noErr) { - OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE event"; - return; - } - - // Create the list of files (only ever one) to open. - base::mac::ScopedAEDesc fileList; - status = AECreateList(NULL, // factoringPtr - 0, // factoredSize - false, // isRecord - fileList.OutPointer()); // resultList - if (status != noErr) { - OSSTATUS_LOG(WARNING, status) << "Could not create OpenItem() AE file list"; - return; - } - - // Add the single path to the file list. C-style cast to avoid both a - // static_cast and a const_cast to get across the toll-free bridge. - CFURLRef pathURLRef = (CFURLRef)[NSURL fileURLWithPath:path_string]; - FSRef pathRef; - if (CFURLGetFSRef(pathURLRef, &pathRef)) { - status = AEPutPtr(fileList.OutPointer(), // theAEDescList - 0, // index - typeFSRef, // typeCode - &pathRef, // dataPtr - sizeof(pathRef)); // dataSize - if (status != noErr) { - OSSTATUS_LOG(WARNING, status) - << "Could not add file path to AE list in OpenItem()"; - return; - } - } else { - LOG(WARNING) << "Could not get FSRef for path URL in OpenItem()"; - return; - } - - // Attach the file list to the AppleEvent. - status = AEPutParamDesc(theEvent.OutPointer(), // theAppleEvent - keyDirectObject, // theAEKeyword - fileList); // theAEDesc - if (status != noErr) { - OSSTATUS_LOG(WARNING, status) - << "Could not put the AE file list the path in OpenItem()"; - return; - } - - // Send the actual event. Do not care about the reply. - base::mac::ScopedAEDesc reply; - status = AESend(theEvent, // theAppleEvent - reply.OutPointer(), // reply - kAENoReply + kAEAlwaysInteract, // sendMode - kAENormalPriority, // sendPriority - kAEDefaultTimeout, // timeOutInTicks - NULL, // idleProc - NULL); // filterProc - if (status != noErr) { - OSSTATUS_LOG(WARNING, status) - << "Could not send AE to Finder in OpenItem()"; - } -} - -bool OpenExternal(const GURL& url, bool activate) { - DCHECK([NSThread isMainThread]); - NSURL* ns_url = net::NSURLWithGURL(url); - if (!ns_url) { - return false; - } - - CFURLRef openingApp = NULL; - OSStatus status = LSGetApplicationForURL((CFURLRef)ns_url, - kLSRolesAll, - NULL, - &openingApp); - if (status != noErr) { - return false; - } - CFRelease(openingApp); // NOT A BUG; LSGetApplicationForURL retains for us - - NSUInteger launchOptions = NSWorkspaceLaunchDefault; - if (!activate) - launchOptions |= NSWorkspaceLaunchWithoutActivation; - - return [[NSWorkspace sharedWorkspace] openURLs: @[ns_url] - withAppBundleIdentifier: nil - options: launchOptions - additionalEventParamDescriptor: NULL - launchIdentifiers: NULL]; -} - -bool MoveItemToTrash(const base::FilePath& full_path) { - NSString* path_string = base::SysUTF8ToNSString(full_path.value()); - BOOL status = [[NSFileManager defaultManager] - trashItemAtURL:[NSURL fileURLWithPath:path_string] - resultingItemURL:nil - error:nil]; - if (!path_string || !status) - LOG(WARNING) << "NSWorkspace failed to move file " << full_path.value() - << " to trash"; - return status; -} - -void Beep() { - NSBeep(); -} - -} // namespace platform_util diff --git a/atom/common/platform_util_win.cc b/atom/common/platform_util_win.cc deleted file mode 100644 index 0795fcb72bffb..0000000000000 --- a/atom/common/platform_util_win.cc +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/platform_util.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/registry.h" -#include "base/win/scoped_co_mem.h" -#include "base/win/scoped_com_initializer.h" -#include "base/win/scoped_comptr.h" -#include "base/win/windows_version.h" -#include "ui/base/win/shell.h" -#include "url/gurl.h" - -namespace { - -// Old ShellExecute crashes the process when the command for a given scheme -// is empty. This function tells if it is. -bool ValidateShellCommandForScheme(const std::string& scheme) { - base::win::RegKey key; - base::string16 registry_path = base::ASCIIToUTF16(scheme) + - L"\\shell\\open\\command"; - key.Open(HKEY_CLASSES_ROOT, registry_path.c_str(), KEY_READ); - if (!key.Valid()) - return false; - DWORD size = 0; - key.ReadValue(NULL, NULL, &size, NULL); - if (size <= 2) - return false; - return true; -} - -// Required COM implementation of IFileOperationProgressSink so we can -// precheck files before deletion to make sure they can be move to the -// Recycle Bin. -class DeleteFileProgressSink : public IFileOperationProgressSink { - public: - DeleteFileProgressSink(); - - private: - ULONG STDMETHODCALLTYPE AddRef(void); - ULONG STDMETHODCALLTYPE Release(void); - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObj); - HRESULT STDMETHODCALLTYPE StartOperations(void); - HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT); - HRESULT STDMETHODCALLTYPE PreRenameItem( - DWORD, IShellItem*, LPCWSTR); - HRESULT STDMETHODCALLTYPE PostRenameItem( - DWORD, IShellItem*, LPCWSTR, HRESULT, IShellItem*); - HRESULT STDMETHODCALLTYPE PreMoveItem( - DWORD, IShellItem*, IShellItem*, LPCWSTR); - HRESULT STDMETHODCALLTYPE PostMoveItem( - DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*); - HRESULT STDMETHODCALLTYPE PreCopyItem( - DWORD, IShellItem*, IShellItem*, LPCWSTR); - HRESULT STDMETHODCALLTYPE PostCopyItem( - DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*); - HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD, IShellItem*); - HRESULT STDMETHODCALLTYPE PostDeleteItem( - DWORD, IShellItem*, HRESULT, IShellItem*); - HRESULT STDMETHODCALLTYPE PreNewItem( - DWORD, IShellItem*, LPCWSTR); - HRESULT STDMETHODCALLTYPE PostNewItem( - DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*); - HRESULT STDMETHODCALLTYPE UpdateProgress(UINT, UINT); - HRESULT STDMETHODCALLTYPE ResetTimer(void); - HRESULT STDMETHODCALLTYPE PauseTimer(void); - HRESULT STDMETHODCALLTYPE ResumeTimer(void); - - ULONG m_cRef; -}; - -DeleteFileProgressSink::DeleteFileProgressSink() { - m_cRef = 0; -} - -HRESULT DeleteFileProgressSink::PreDeleteItem(DWORD dwFlags, IShellItem*) { - if (!(dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE)) { - // TSF_DELETE_RECYCLE_IF_POSSIBLE will not be set for items that cannot be - // recycled. In this case, we abort the delete operation. This bubbles - // up and stops the Delete in IFileOperation. - return E_ABORT; - } - // Returns S_OK if successful, or an error value otherwise. In the case of an - // error value, the delete operation and all subsequent operations pending - // from the call to IFileOperation are canceled. - return S_OK; -} - -HRESULT DeleteFileProgressSink::QueryInterface(REFIID riid, LPVOID* ppvObj) { - // Always set out parameter to NULL, validating it first. - if (!ppvObj) - return E_INVALIDARG; - *ppvObj = nullptr; - if (riid == IID_IUnknown || riid == IID_IFileOperationProgressSink) { - // Increment the reference count and return the pointer. - *ppvObj = reinterpret_cast(this); - AddRef(); - return NOERROR; - } - return E_NOINTERFACE; -} - -ULONG DeleteFileProgressSink::AddRef() { - InterlockedIncrement(&m_cRef); - return m_cRef; -} - -ULONG DeleteFileProgressSink::Release() { - // Decrement the object's internal counter. - ULONG ulRefCount = InterlockedDecrement(&m_cRef); - if (0 == m_cRef) { - delete this; - } - return ulRefCount; -} - -HRESULT DeleteFileProgressSink::StartOperations() { - return S_OK; -} - -HRESULT DeleteFileProgressSink::FinishOperations(HRESULT) { - return S_OK; -} - -HRESULT DeleteFileProgressSink::PreRenameItem(DWORD, IShellItem*, LPCWSTR) { - return S_OK; -} - -HRESULT DeleteFileProgressSink::PostRenameItem( - DWORD, IShellItem*, __RPC__in_string LPCWSTR, HRESULT, IShellItem*) { - return E_NOTIMPL; -} - -HRESULT DeleteFileProgressSink::PreMoveItem( - DWORD, IShellItem*, IShellItem*, LPCWSTR) { - return E_NOTIMPL; -} - -HRESULT DeleteFileProgressSink::PostMoveItem( - DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) { - return E_NOTIMPL; -} - -HRESULT DeleteFileProgressSink::PreCopyItem( - DWORD, IShellItem*, IShellItem*, LPCWSTR) { - return E_NOTIMPL; -} - -HRESULT DeleteFileProgressSink::PostCopyItem( - DWORD, IShellItem*, IShellItem*, LPCWSTR, HRESULT, IShellItem*) { - return E_NOTIMPL; -} - -HRESULT DeleteFileProgressSink::PostDeleteItem( - DWORD, IShellItem*, HRESULT, IShellItem*) { - return S_OK; -} - -HRESULT DeleteFileProgressSink::PreNewItem( - DWORD dwFlags, IShellItem*, LPCWSTR) { - return E_NOTIMPL; -} - -HRESULT DeleteFileProgressSink::PostNewItem( - DWORD, IShellItem*, LPCWSTR, LPCWSTR, DWORD, HRESULT, IShellItem*) { - return E_NOTIMPL; -} - -HRESULT DeleteFileProgressSink::UpdateProgress(UINT, UINT) { - return S_OK; -} - -HRESULT DeleteFileProgressSink::ResetTimer() { - return S_OK; -} - -HRESULT DeleteFileProgressSink::PauseTimer() { - return S_OK; -} - -HRESULT DeleteFileProgressSink::ResumeTimer() { - return S_OK; -} - -} // namespace - -namespace platform_util { - -void ShowItemInFolder(const base::FilePath& full_path) { - base::win::ScopedCOMInitializer com_initializer; - if (!com_initializer.succeeded()) - return; - - base::FilePath dir = full_path.DirName().AsEndingWithSeparator(); - // ParseDisplayName will fail if the directory is "C:", it must be "C:\\". - if (dir.empty()) - return; - - typedef HRESULT (WINAPI *SHOpenFolderAndSelectItemsFuncPtr)( - PCIDLIST_ABSOLUTE pidl_Folder, - UINT cidl, - PCUITEMID_CHILD_ARRAY pidls, - DWORD flags); - - static SHOpenFolderAndSelectItemsFuncPtr open_folder_and_select_itemsPtr = - NULL; - static bool initialize_open_folder_proc = true; - if (initialize_open_folder_proc) { - initialize_open_folder_proc = false; - // The SHOpenFolderAndSelectItems API is exposed by shell32 version 6 - // and does not exist in Win2K. We attempt to retrieve this function export - // from shell32 and if it does not exist, we just invoke ShellExecute to - // open the folder thus losing the functionality to select the item in - // the process. - HMODULE shell32_base = GetModuleHandle(L"shell32.dll"); - if (!shell32_base) { - NOTREACHED() << " " << __FUNCTION__ << "(): Can't open shell32.dll"; - return; - } - open_folder_and_select_itemsPtr = - reinterpret_cast - (GetProcAddress(shell32_base, "SHOpenFolderAndSelectItems")); - } - if (!open_folder_and_select_itemsPtr) { - ui::win::OpenFolderViaShell(dir); - return; - } - - base::win::ScopedComPtr desktop; - HRESULT hr = SHGetDesktopFolder(desktop.Receive()); - if (FAILED(hr)) - return; - - base::win::ScopedCoMem dir_item; - hr = desktop->ParseDisplayName(NULL, NULL, - const_cast(dir.value().c_str()), - NULL, &dir_item, NULL); - if (FAILED(hr)) { - ui::win::OpenFolderViaShell(dir); - return; - } - - base::win::ScopedCoMem file_item; - hr = desktop->ParseDisplayName(NULL, NULL, - const_cast(full_path.value().c_str()), - NULL, &file_item, NULL); - if (FAILED(hr)) { - ui::win::OpenFolderViaShell(dir); - return; - } - - const ITEMIDLIST* highlight[] = { file_item }; - - hr = (*open_folder_and_select_itemsPtr)(dir_item, arraysize(highlight), - highlight, NULL); - - if (FAILED(hr)) { - // On some systems, the above call mysteriously fails with "file not - // found" even though the file is there. In these cases, ShellExecute() - // seems to work as a fallback (although it won't select the file). - if (hr == ERROR_FILE_NOT_FOUND) { - ui::win::OpenFolderViaShell(dir); - } else { - LPTSTR message = NULL; - DWORD message_length = FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - 0, hr, 0, reinterpret_cast(&message), 0, NULL); - LOG(WARNING) << " " << __FUNCTION__ - << "(): Can't open full_path = \"" - << full_path.value() << "\"" - << " hr = " << hr - << " " << reinterpret_cast(&message); - if (message) - LocalFree(message); - - ui::win::OpenFolderViaShell(dir); - } - } -} - -void OpenItem(const base::FilePath& full_path) { - if (base::DirectoryExists(full_path)) - ui::win::OpenFolderViaShell(full_path); - else - ui::win::OpenFileViaShell(full_path); -} - -bool OpenExternal(const base::string16& url, bool activate) { - // Quote the input scheme to be sure that the command does not have - // parameters unexpected by the external program. This url should already - // have been escaped. - base::string16 escaped_url = L"\"" + url + L"\""; - - if (reinterpret_cast(ShellExecuteW(NULL, L"open", - escaped_url.c_str(), NULL, NULL, - SW_SHOWNORMAL)) <= 32) { - // We fail to execute the call. We could display a message to the user. - // TODO(nsylvain): we should also add a dialog to warn on errors. See - // bug 1136923. - return false; - } - return true; -} - -bool MoveItemToTrash(const base::FilePath& path) { - base::win::ScopedCOMInitializer com_initializer; - if (!com_initializer.succeeded()) - return false; - - base::win::ScopedComPtr pfo; - if (FAILED(pfo.CreateInstance(CLSID_FileOperation))) - return false; - - // Elevation prompt enabled for UAC protected files. This overrides the - // SILENT, NO_UI and NOERRORUI flags. - - if (base::win::GetVersion() >= base::win::VERSION_WIN8) { - // Windows 8 introduces the flag RECYCLEONDELETE and deprecates the - // ALLOWUNDO in favor of ADDUNDORECORD. - if (FAILED(pfo->SetOperationFlags(FOF_NO_UI | - FOFX_ADDUNDORECORD | - FOF_NOERRORUI | - FOF_SILENT | - FOFX_SHOWELEVATIONPROMPT | - FOFX_RECYCLEONDELETE))) - return false; - } else { - // For Windows 7 and Vista, RecycleOnDelete is the default behavior. - if (FAILED(pfo->SetOperationFlags(FOF_NO_UI | - FOF_ALLOWUNDO | - FOF_NOERRORUI | - FOF_SILENT | - FOFX_SHOWELEVATIONPROMPT))) - return false; - } - - // Create an IShellItem from the supplied source path. - base::win::ScopedComPtr delete_item; - if (FAILED(SHCreateItemFromParsingName(path.value().c_str(), - NULL, - IID_PPV_ARGS(delete_item.Receive())))) - return false; - - base::win::ScopedComPtr delete_sink( - new DeleteFileProgressSink); - if (!delete_sink) - return false; - - // Processes the queued command DeleteItem. This will trigger - // the DeleteFileProgressSink to check for Recycle Bin. - return SUCCEEDED(pfo->DeleteItem(delete_item.get(), delete_sink.get())) && - SUCCEEDED(pfo->PerformOperations()); -} - -void Beep() { - MessageBeep(MB_OK); -} - -} // namespace platform_util diff --git a/atom/common/resources/mac/Info.plist b/atom/common/resources/mac/Info.plist deleted file mode 100644 index 7b56a46470ea0..0000000000000 --- a/atom/common/resources/mac/Info.plist +++ /dev/null @@ -1,16 +0,0 @@ - - - - - CFBundleIdentifier - ${ATOM_BUNDLE_ID} - CFBundleName - ${PRODUCT_NAME} - CFBundleExecutable - ${PRODUCT_NAME} - CFBundlePackageType - FMWK - NSSupportsAutomaticGraphicsSwitching - - - diff --git a/atom/node/osfhandle.cc b/atom/node/osfhandle.cc deleted file mode 100644 index 33403dc52371f..0000000000000 --- a/atom/node/osfhandle.cc +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "osfhandle.h" - -#include - -namespace node { - -int open_osfhandle(intptr_t osfhandle, int flags) { - return _open_osfhandle(osfhandle, flags); -} - -int close(int fd) { - return _close(fd); -} - -} // namespace node diff --git a/atom/node/osfhandle.h b/atom/node/osfhandle.h deleted file mode 100644 index 3933236e5091b..0000000000000 --- a/atom/node/osfhandle.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_NODE_OSFHANDLE_H_ -#define ATOM_NODE_OSFHANDLE_H_ - -#include - -namespace node { - -// The _open_osfhandle and _close functions on Windows are provided by the -// Visual C++ library, so the fd returned by them can only be used in the -// same instance of VC++ library. -// However Electron is linking with VC++ library statically, so electron.exe -// shares a different instance of VC++ library with node.exe. This results -// in fd created in electron.exe not usable in node.dll, so we have to ensure -// we always create fd in one instance of VC++ library. -// Followings wrappers are compiled in node.dll, and all code in electron.exe -// should call these wrappers instead of calling _open_osfhandle directly. -__declspec(dllexport) int open_osfhandle(intptr_t osfhandle, int flags); -__declspec(dllexport) int close(int fd); - -} // namespace node - -#endif // ATOM_NODE_OSFHANDLE_H_ diff --git a/atom/renderer/api/atom_api_renderer_ipc.cc b/atom/renderer/api/atom_api_renderer_ipc.cc deleted file mode 100644 index 49f917292bb22..0000000000000 --- a/atom/renderer/api/atom_api_renderer_ipc.cc +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/common/api/api_messages.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_includes.h" -#include "content/public/renderer/render_view.h" -#include "native_mate/dictionary.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebView.h" - -using content::RenderView; -using blink::WebLocalFrame; -using blink::WebView; - -namespace { - -RenderView* GetCurrentRenderView() { - WebLocalFrame* frame = WebLocalFrame::frameForCurrentContext(); - if (!frame) - return nullptr; - - WebView* view = frame->view(); - if (!view) - return nullptr; // can happen during closing. - - return RenderView::FromWebView(view); -} - -void Send(mate::Arguments* args, - const base::string16& channel, - const base::ListValue& arguments) { - RenderView* render_view = GetCurrentRenderView(); - if (render_view == nullptr) - return; - - bool success = render_view->Send(new AtomViewHostMsg_Message( - render_view->GetRoutingID(), channel, arguments)); - - if (!success) - args->ThrowError("Unable to send AtomViewHostMsg_Message"); -} - -base::string16 SendSync(mate::Arguments* args, - const base::string16& channel, - const base::ListValue& arguments) { - base::string16 json; - - RenderView* render_view = GetCurrentRenderView(); - if (render_view == nullptr) - return json; - - IPC::SyncMessage* message = new AtomViewHostMsg_Message_Sync( - render_view->GetRoutingID(), channel, arguments, &json); - bool success = render_view->Send(message); - - if (!success) - args->ThrowError("Unable to send AtomViewHostMsg_Message_Sync"); - - return json; -} - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("send", &Send); - dict.SetMethod("sendSync", &SendSync); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_renderer_ipc, Initialize) diff --git a/atom/renderer/api/atom_api_spell_check_client.cc b/atom/renderer/api/atom_api_spell_check_client.cc deleted file mode 100644 index 08f36efce5819..0000000000000 --- a/atom/renderer/api/atom_api_spell_check_client.cc +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/renderer/api/atom_api_spell_check_client.h" - -#include -#include - -#include "atom/common/native_mate_converters/string16_converter.h" -#include "base/logging.h" -#include "native_mate/converter.h" -#include "native_mate/dictionary.h" -#include "third_party/icu/source/common/unicode/uscript.h" -#include "third_party/WebKit/public/web/WebTextCheckingCompletion.h" -#include "third_party/WebKit/public/web/WebTextCheckingResult.h" - -namespace atom { - -namespace api { - -namespace { - -bool HasWordCharacters(const base::string16& text, int index) { - const base::char16* data = text.data(); - int length = text.length(); - while (index < length) { - uint32_t code = 0; - U16_NEXT(data, index, length, code); - UErrorCode error = U_ZERO_ERROR; - if (uscript_getScript(code, &error) != USCRIPT_COMMON) - return true; - } - return false; -} - -} // namespace - -SpellCheckClient::SpellCheckClient(const std::string& language, - bool auto_spell_correct_turned_on, - v8::Isolate* isolate, - v8::Local provider) - : isolate_(isolate), - provider_(isolate, provider) { - character_attributes_.SetDefaultLanguage(language); - - // Persistent the method. - mate::Dictionary dict(isolate, provider); - dict.Get("spellCheck", &spell_check_); -} - -SpellCheckClient::~SpellCheckClient() {} - -void SpellCheckClient::spellCheck( - const blink::WebString& text, - int& misspelling_start, - int& misspelling_len, - blink::WebVector* optional_suggestions) { - std::vector results; - SpellCheckText(base::string16(text), true, &results); - if (results.size() == 1) { - misspelling_start = results[0].location; - misspelling_len = results[0].length; - } -} - -void SpellCheckClient::checkTextOfParagraph( - const blink::WebString& text, - blink::WebTextCheckingTypeMask mask, - blink::WebVector* results) { - if (!results) - return; - - if (!(mask & blink::WebTextCheckingTypeSpelling)) - return; - - NOTREACHED() << "checkTextOfParagraph should never be called"; -} - -void SpellCheckClient::requestCheckingOfText( - const blink::WebString& textToCheck, - const blink::WebVector& markersInText, - const blink::WebVector& markerOffsets, - blink::WebTextCheckingCompletion* completionCallback) { - base::string16 text(textToCheck); - if (text.empty() || !HasWordCharacters(text, 0)) { - completionCallback->didCancelCheckingText(); - return; - } - - std::vector results; - SpellCheckText(text, false, &results); - completionCallback->didFinishCheckingText(results); -} - -void SpellCheckClient::showSpellingUI(bool show) { -} - -bool SpellCheckClient::isShowingSpellingUI() { - return false; -} - -void SpellCheckClient::updateSpellingUIWithMisspelledWord( - const blink::WebString& word) { -} - -void SpellCheckClient::SpellCheckText( - const base::string16& text, - bool stop_at_first_result, - std::vector* results) { - if (text.length() == 0 || spell_check_.IsEmpty()) - return; - - base::string16 word; - int word_start; - int word_length; - if (!text_iterator_.IsInitialized() && - !text_iterator_.Initialize(&character_attributes_, true)) { - // We failed to initialize text_iterator_, return as spelled correctly. - VLOG(1) << "Failed to initialize SpellcheckWordIterator"; - return; - } - - base::string16 in_word(text); - text_iterator_.SetText(in_word.c_str(), in_word.size()); - while (text_iterator_.GetNextWord(&word, &word_start, &word_length)) { - // Found a word (or a contraction) that the spellchecker can check the - // spelling of. - if (SpellCheckWord(word)) - continue; - - // If the given word is a concatenated word of two or more valid words - // (e.g. "hello:hello"), we should treat it as a valid word. - if (IsValidContraction(word)) - continue; - - blink::WebTextCheckingResult result; - result.location = word_start; - result.length = word_length; - results->push_back(result); - - if (stop_at_first_result) - return; - } -} - -bool SpellCheckClient::SpellCheckWord(const base::string16& word_to_check) { - if (spell_check_.IsEmpty()) - return true; - - v8::HandleScope handle_scope(isolate_); - v8::Local word = mate::ConvertToV8(isolate_, word_to_check); - v8::Local result = spell_check_.NewHandle()->Call( - provider_.NewHandle(), 1, &word); - - if (result->IsBoolean()) - return result->BooleanValue(); - else - return true; -} - -// Returns whether or not the given string is a valid contraction. -// This function is a fall-back when the SpellcheckWordIterator class -// returns a concatenated word which is not in the selected dictionary -// (e.g. "in'n'out") but each word is valid. -bool SpellCheckClient::IsValidContraction(const base::string16& contraction) { - if (!contraction_iterator_.IsInitialized() && - !contraction_iterator_.Initialize(&character_attributes_, false)) { - // We failed to initialize the word iterator, return as spelled correctly. - VLOG(1) << "Failed to initialize contraction_iterator_"; - return true; - } - - contraction_iterator_.SetText(contraction.c_str(), contraction.length()); - - base::string16 word; - int word_start; - int word_length; - - while (contraction_iterator_.GetNextWord(&word, &word_start, &word_length)) { - if (!SpellCheckWord(word)) - return false; - } - return true; -} - -} // namespace api - -} // namespace atom diff --git a/atom/renderer/api/atom_api_spell_check_client.h b/atom/renderer/api/atom_api_spell_check_client.h deleted file mode 100644 index af72756e2ec13..0000000000000 --- a/atom/renderer/api/atom_api_spell_check_client.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_RENDERER_API_ATOM_API_SPELL_CHECK_CLIENT_H_ -#define ATOM_RENDERER_API_ATOM_API_SPELL_CHECK_CLIENT_H_ - -#include -#include - -#include "base/callback.h" -#include "chrome/renderer/spellchecker/spellcheck_worditerator.h" -#include "native_mate/scoped_persistent.h" -#include "third_party/WebKit/public/web/WebSpellCheckClient.h" - -namespace atom { - -namespace api { - -class SpellCheckClient : public blink::WebSpellCheckClient { - public: - SpellCheckClient(const std::string& language, - bool auto_spell_correct_turned_on, - v8::Isolate* isolate, - v8::Local provider); - virtual ~SpellCheckClient(); - - private: - // blink::WebSpellCheckClient: - void spellCheck( - const blink::WebString& text, - int& misspelledOffset, - int& misspelledLength, - blink::WebVector* optionalSuggestions) override; - void checkTextOfParagraph( - const blink::WebString&, - blink::WebTextCheckingTypeMask mask, - blink::WebVector* results) override; - void requestCheckingOfText( - const blink::WebString& textToCheck, - const blink::WebVector& markersInText, - const blink::WebVector& markerOffsets, - blink::WebTextCheckingCompletion* completionCallback) override; - void showSpellingUI(bool show) override; - bool isShowingSpellingUI() override; - void updateSpellingUIWithMisspelledWord( - const blink::WebString& word) override; - - // Check the spelling of text. - void SpellCheckText(const base::string16& text, - bool stop_at_first_result, - std::vector* results); - - // Call JavaScript to check spelling a word. - bool SpellCheckWord(const base::string16& word_to_check); - - // Find a possible correctly spelled word for a misspelled word. Computes an - // empty string if input misspelled word is too long, there is ambiguity, or - // the correct spelling cannot be determined. - base::string16 GetAutoCorrectionWord(const base::string16& word); - - // Returns whether or not the given word is a contraction of valid words - // (e.g. "word:word"). - bool IsValidContraction(const base::string16& word); - - // Represents character attributes used for filtering out characters which - // are not supported by this SpellCheck object. - SpellcheckCharAttribute character_attributes_; - - // Represents word iterators used in this spellchecker. The |text_iterator_| - // splits text provided by WebKit into words, contractions, or concatenated - // words. The |contraction_iterator_| splits a concatenated word extracted by - // |text_iterator_| into word components so we can treat a concatenated word - // consisting only of correct words as a correct word. - SpellcheckWordIterator text_iterator_; - SpellcheckWordIterator contraction_iterator_; - - bool auto_spell_correct_turned_on_; - - v8::Isolate* isolate_; - mate::ScopedPersistent provider_; - mate::ScopedPersistent spell_check_; - - DISALLOW_COPY_AND_ASSIGN(SpellCheckClient); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_RENDERER_API_ATOM_API_SPELL_CHECK_CLIENT_H_ diff --git a/atom/renderer/api/atom_api_web_frame.cc b/atom/renderer/api/atom_api_web_frame.cc deleted file mode 100644 index 9c83fc8e2f59e..0000000000000 --- a/atom/renderer/api/atom_api_web_frame.cc +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/renderer/api/atom_api_web_frame.h" - -#include "atom/common/api/event_emitter_caller.h" -#include "atom/common/native_mate_converters/blink_converter.h" -#include "atom/common/native_mate_converters/callback.h" -#include "atom/common/native_mate_converters/gfx_converter.h" -#include "atom/common/native_mate_converters/string16_converter.h" -#include "atom/renderer/api/atom_api_spell_check_client.h" -#include "base/memory/memory_pressure_listener.h" -#include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_view.h" -#include "native_mate/dictionary.h" -#include "native_mate/object_template_builder.h" -#include "third_party/WebKit/public/web/WebCache.h" -#include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebScriptExecutionCallback.h" -#include "third_party/WebKit/public/web/WebScriptSource.h" -#include "third_party/WebKit/public/web/WebSecurityPolicy.h" -#include "third_party/WebKit/public/web/WebView.h" - -#include "atom/common/node_includes.h" - -namespace atom { - -namespace api { - -namespace { - -class ScriptExecutionCallback : public blink::WebScriptExecutionCallback { - public: - using CompletionCallback = - base::Callback& result)>; - - explicit ScriptExecutionCallback(const CompletionCallback& callback) - : callback_(callback) {} - ~ScriptExecutionCallback() override {} - - void completed( - const blink::WebVector>& result) override { - if (!callback_.is_null() && !result.isEmpty() && !result[0].IsEmpty()) - // Right now only single results per frame is supported. - callback_.Run(result[0]); - delete this; - } - - private: - CompletionCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(ScriptExecutionCallback); -}; - -} // namespace - -WebFrame::WebFrame(v8::Isolate* isolate) - : web_frame_(blink::WebLocalFrame::frameForCurrentContext()) { - Init(isolate); -} - -WebFrame::~WebFrame() { -} - -void WebFrame::SetName(const std::string& name) { - web_frame_->setName(blink::WebString::fromUTF8(name)); -} - -double WebFrame::SetZoomLevel(double level) { - double ret = web_frame_->view()->setZoomLevel(level); - mate::EmitEvent(isolate(), GetWrapper(), "zoom-level-changed", ret); - return ret; -} - -double WebFrame::GetZoomLevel() const { - return web_frame_->view()->zoomLevel(); -} - -double WebFrame::SetZoomFactor(double factor) { - return blink::WebView::zoomLevelToZoomFactor(SetZoomLevel( - blink::WebView::zoomFactorToZoomLevel(factor))); -} - -double WebFrame::GetZoomFactor() const { - return blink::WebView::zoomLevelToZoomFactor(GetZoomLevel()); -} - -void WebFrame::SetZoomLevelLimits(double min_level, double max_level) { - web_frame_->view()->setDefaultPageScaleLimits(min_level, max_level); -} - -v8::Local WebFrame::RegisterEmbedderCustomElement( - const base::string16& name, v8::Local options) { - blink::WebExceptionCode c = 0; - return web_frame_->document().registerEmbedderCustomElement(name, options, c); -} - -void WebFrame::RegisterElementResizeCallback( - int element_instance_id, - const GuestViewContainer::ResizeCallback& callback) { - auto guest_view_container = GuestViewContainer::FromID(element_instance_id); - if (guest_view_container) - guest_view_container->RegisterElementResizeCallback(callback); -} - -void WebFrame::AttachGuest(int id) { - content::RenderFrame::FromWebFrame(web_frame_)->AttachGuest(id); -} - -void WebFrame::SetSpellCheckProvider(mate::Arguments* args, - const std::string& language, - bool auto_spell_correct_turned_on, - v8::Local provider) { - if (!provider->Has(mate::StringToV8(args->isolate(), "spellCheck"))) { - args->ThrowError("\"spellCheck\" has to be defined"); - return; - } - - spell_check_client_.reset(new SpellCheckClient( - language, auto_spell_correct_turned_on, args->isolate(), provider)); - web_frame_->view()->setSpellCheckClient(spell_check_client_.get()); -} - -void WebFrame::RegisterURLSchemeAsSecure(const std::string& scheme) { - // Register scheme to secure list (https, wss, data). - blink::WebSecurityPolicy::registerURLSchemeAsSecure( - blink::WebString::fromUTF8(scheme)); -} - -void WebFrame::RegisterURLSchemeAsBypassingCSP(const std::string& scheme) { - // Register scheme to bypass pages's Content Security Policy. - blink::WebSecurityPolicy::registerURLSchemeAsBypassingContentSecurityPolicy( - blink::WebString::fromUTF8(scheme)); -} - -void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme) { - // Register scheme to privileged list (https, wss, data, chrome-extension) - blink::WebString privileged_scheme(blink::WebString::fromUTF8(scheme)); - blink::WebSecurityPolicy::registerURLSchemeAsSecure(privileged_scheme); - blink::WebSecurityPolicy::registerURLSchemeAsBypassingContentSecurityPolicy( - privileged_scheme); - blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers( - privileged_scheme); - blink::WebSecurityPolicy::registerURLSchemeAsSupportingFetchAPI( - privileged_scheme); -} - -void WebFrame::InsertText(const std::string& text) { - web_frame_->insertText(blink::WebString::fromUTF8(text)); -} - -void WebFrame::ExecuteJavaScript(const base::string16& code, - mate::Arguments* args) { - bool has_user_gesture = false; - args->GetNext(&has_user_gesture); - ScriptExecutionCallback::CompletionCallback completion_callback; - args->GetNext(&completion_callback); - std::unique_ptr callback( - new ScriptExecutionCallback(completion_callback)); - web_frame_->requestExecuteScriptAndReturnValue( - blink::WebScriptSource(code), - has_user_gesture, - callback.release()); -} - -// static -mate::Handle WebFrame::Create(v8::Isolate* isolate) { - return mate::CreateHandle(isolate, new WebFrame(isolate)); -} - -blink::WebCache::ResourceTypeStats WebFrame::GetResourceUsage( - v8::Isolate* isolate) { - blink::WebCache::ResourceTypeStats stats; - blink::WebCache::getResourceTypeStats(&stats); - return stats; -} - -void WebFrame::ClearCache(v8::Isolate* isolate) { - isolate->IdleNotificationDeadline(0.5); - blink::WebCache::clear(); - base::MemoryPressureListener::NotifyMemoryPressure( - base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); -} - -// static -void WebFrame::BuildPrototype( - v8::Isolate* isolate, v8::Local prototype) { - prototype->SetClassName(mate::StringToV8(isolate, "WebFrame")); - mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) - .SetMethod("setName", &WebFrame::SetName) - .SetMethod("setZoomLevel", &WebFrame::SetZoomLevel) - .SetMethod("getZoomLevel", &WebFrame::GetZoomLevel) - .SetMethod("setZoomFactor", &WebFrame::SetZoomFactor) - .SetMethod("getZoomFactor", &WebFrame::GetZoomFactor) - .SetMethod("setZoomLevelLimits", &WebFrame::SetZoomLevelLimits) - .SetMethod("registerEmbedderCustomElement", - &WebFrame::RegisterEmbedderCustomElement) - .SetMethod("registerElementResizeCallback", - &WebFrame::RegisterElementResizeCallback) - .SetMethod("attachGuest", &WebFrame::AttachGuest) - .SetMethod("setSpellCheckProvider", &WebFrame::SetSpellCheckProvider) - .SetMethod("registerURLSchemeAsSecure", - &WebFrame::RegisterURLSchemeAsSecure) - .SetMethod("registerURLSchemeAsBypassingCSP", - &WebFrame::RegisterURLSchemeAsBypassingCSP) - .SetMethod("registerURLSchemeAsPrivileged", - &WebFrame::RegisterURLSchemeAsPrivileged) - .SetMethod("insertText", &WebFrame::InsertText) - .SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript) - .SetMethod("getResourceUsage", &WebFrame::GetResourceUsage) - .SetMethod("clearCache", &WebFrame::ClearCache); -} - -} // namespace api - -} // namespace atom - -namespace { - -using atom::api::WebFrame; - -void Initialize(v8::Local exports, v8::Local unused, - v8::Local context, void* priv) { - v8::Isolate* isolate = context->GetIsolate(); - mate::Dictionary dict(isolate, exports); - dict.Set("webFrame", WebFrame::Create(isolate)); - dict.Set("WebFrame", WebFrame::GetConstructor(isolate)->GetFunction()); -} - -} // namespace - -NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_renderer_web_frame, Initialize) diff --git a/atom/renderer/api/atom_api_web_frame.h b/atom/renderer/api/atom_api_web_frame.h deleted file mode 100644 index 7b2401dd4077b..0000000000000 --- a/atom/renderer/api/atom_api_web_frame.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2014 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_ -#define ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_ - -#include -#include - -#include "atom/renderer/guest_view_container.h" -#include "native_mate/handle.h" -#include "native_mate/wrappable.h" -#include "third_party/WebKit/public/web/WebCache.h" - -namespace blink { -class WebLocalFrame; -} - -namespace mate { -class Arguments; -} - -namespace atom { - -namespace api { - -class SpellCheckClient; - -class WebFrame : public mate::Wrappable { - public: - static mate::Handle Create(v8::Isolate* isolate); - - static void BuildPrototype(v8::Isolate* isolate, - v8::Local prototype); - - private: - explicit WebFrame(v8::Isolate* isolate); - ~WebFrame() override; - - void SetName(const std::string& name); - - double SetZoomLevel(double level); - double GetZoomLevel() const; - double SetZoomFactor(double factor); - double GetZoomFactor() const; - - void SetZoomLevelLimits(double min_level, double max_level); - - v8::Local RegisterEmbedderCustomElement( - const base::string16& name, v8::Local options); - void RegisterElementResizeCallback( - int element_instance_id, - const GuestViewContainer::ResizeCallback& callback); - void AttachGuest(int element_instance_id); - - // Set the provider that will be used by SpellCheckClient for spell check. - void SetSpellCheckProvider(mate::Arguments* args, - const std::string& language, - bool auto_spell_correct_turned_on, - v8::Local provider); - - void RegisterURLSchemeAsSecure(const std::string& scheme); - void RegisterURLSchemeAsBypassingCSP(const std::string& scheme); - void RegisterURLSchemeAsPrivileged(const std::string& scheme); - - // Editing. - void InsertText(const std::string& text); - - // Excecuting scripts. - void ExecuteJavaScript(const base::string16& code, mate::Arguments* args); - - // Resource related methods - blink::WebCache::ResourceTypeStats GetResourceUsage(v8::Isolate* isolate); - void ClearCache(v8::Isolate* isolate); - - std::unique_ptr spell_check_client_; - - blink::WebLocalFrame* web_frame_; - - DISALLOW_COPY_AND_ASSIGN(WebFrame); -}; - -} // namespace api - -} // namespace atom - -#endif // ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_ diff --git a/atom/renderer/atom_render_view_observer.cc b/atom/renderer/atom_render_view_observer.cc deleted file mode 100644 index 45a41eef8acc1..0000000000000 --- a/atom/renderer/atom_render_view_observer.cc +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/renderer/atom_render_view_observer.h" - -#include -#include - -// Put this before event_emitter_caller.h to have string16 support. -#include "atom/common/native_mate_converters/string16_converter.h" - -#include "atom/common/api/api_messages.h" -#include "atom/common/api/event_emitter_caller.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_includes.h" -#include "atom/common/options_switches.h" -#include "atom/renderer/atom_renderer_client.h" -#include "base/command_line.h" -#include "base/strings/string_number_conversions.h" -#include "content/public/renderer/render_view.h" -#include "ipc/ipc_message_macros.h" -#include "net/base/net_module.h" -#include "net/grit/net_resources.h" -#include "third_party/WebKit/public/web/WebDraggableRegion.h" -#include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebFrame.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebKit.h" -#include "third_party/WebKit/public/web/WebView.h" -#include "ui/base/resource/resource_bundle.h" -#include "native_mate/dictionary.h" - -namespace atom { - -namespace { - -bool GetIPCObject(v8::Isolate* isolate, - v8::Local context, - v8::Local* ipc) { - v8::Local key = mate::StringToV8(isolate, "ipc"); - v8::Local privateKey = v8::Private::ForApi(isolate, key); - v8::Local global_object = context->Global(); - v8::Local value; - if (!global_object->GetPrivate(context, privateKey).ToLocal(&value)) - return false; - if (value.IsEmpty() || !value->IsObject()) - return false; - *ipc = value->ToObject(); - return true; -} - -std::vector> ListValueToVector( - v8::Isolate* isolate, - const base::ListValue& list) { - v8::Local array = mate::ConvertToV8(isolate, list); - std::vector> result; - mate::ConvertFromV8(isolate, array, &result); - return result; -} - -void EmitIPCEvent(blink::WebFrame* frame, - const base::string16& channel, - const base::ListValue& args) { - if (!frame || frame->isWebRemoteFrame()) - return; - - v8::Isolate* isolate = blink::mainThreadIsolate(); - v8::HandleScope handle_scope(isolate); - - v8::Local context = frame->mainWorldScriptContext(); - v8::Context::Scope context_scope(context); - - // Only emit IPC event for context with node integration. - node::Environment* env = node::Environment::GetCurrent(context); - if (!env) - return; - - v8::Local ipc; - if (GetIPCObject(isolate, context, &ipc)) { - auto args_vector = ListValueToVector(isolate, args); - // Insert the Event object, event.sender is ipc. - mate::Dictionary event = mate::Dictionary::CreateEmpty(isolate); - event.Set("sender", ipc); - args_vector.insert(args_vector.begin(), event.GetHandle()); - mate::EmitEvent(isolate, ipc, channel, args_vector); - } -} - -base::StringPiece NetResourceProvider(int key) { - if (key == IDR_DIR_HEADER_HTML) { - base::StringPiece html_data = - ui::ResourceBundle::GetSharedInstance().GetRawDataResource( - IDR_DIR_HEADER_HTML); - return html_data; - } - return base::StringPiece(); -} - -} // namespace - -AtomRenderViewObserver::AtomRenderViewObserver( - content::RenderView* render_view, - AtomRendererClient* renderer_client) - : content::RenderViewObserver(render_view), - renderer_client_(renderer_client), - document_created_(false) { - // Initialise resource for directory listing. - net::NetModule::SetResourceProvider(NetResourceProvider); -} - -AtomRenderViewObserver::~AtomRenderViewObserver() { -} - -void AtomRenderViewObserver::DidCreateDocumentElement( - blink::WebLocalFrame* frame) { - document_created_ = true; - - // Read --zoom-factor from command line. - std::string zoom_factor_str = base::CommandLine::ForCurrentProcess()-> - GetSwitchValueASCII(switches::kZoomFactor); - if (zoom_factor_str.empty()) - return; - double zoom_factor; - if (!base::StringToDouble(zoom_factor_str, &zoom_factor)) - return; - double zoom_level = blink::WebView::zoomFactorToZoomLevel(zoom_factor); - frame->view()->setZoomLevel(zoom_level); -} - -void AtomRenderViewObserver::DraggableRegionsChanged(blink::WebFrame* frame) { - blink::WebVector webregions = - frame->document().draggableRegions(); - std::vector regions; - for (const auto& webregion : webregions) { - DraggableRegion region; - region.bounds = webregion.bounds; - region.draggable = webregion.draggable; - regions.push_back(region); - } - Send(new AtomViewHostMsg_UpdateDraggableRegions(routing_id(), regions)); -} - -bool AtomRenderViewObserver::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(AtomRenderViewObserver, message) - IPC_MESSAGE_HANDLER(AtomViewMsg_Message, OnBrowserMessage) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - return handled; -} - -void AtomRenderViewObserver::OnBrowserMessage(bool send_to_all, - const base::string16& channel, - const base::ListValue& args) { - if (!document_created_) - return; - - if (!render_view()->GetWebView()) - return; - - blink::WebFrame* frame = render_view()->GetWebView()->mainFrame(); - if (!frame || frame->isWebRemoteFrame()) - return; - - EmitIPCEvent(frame, channel, args); - - // Also send the message to all sub-frames. - if (send_to_all) { - for (blink::WebFrame* child = frame->firstChild(); child; - child = child->nextSibling()) - EmitIPCEvent(child, channel, args); - } -} - -} // namespace atom diff --git a/atom/renderer/atom_render_view_observer.h b/atom/renderer/atom_render_view_observer.h deleted file mode 100644 index 376138f0849a9..0000000000000 --- a/atom/renderer/atom_render_view_observer.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_RENDERER_ATOM_RENDER_VIEW_OBSERVER_H_ -#define ATOM_RENDERER_ATOM_RENDER_VIEW_OBSERVER_H_ - -#include "base/strings/string16.h" -#include "content/public/renderer/render_view_observer.h" - -namespace base { -class ListValue; -} - -namespace atom { - -class AtomRendererClient; - -class AtomRenderViewObserver : public content::RenderViewObserver { - public: - explicit AtomRenderViewObserver(content::RenderView* render_view, - AtomRendererClient* renderer_client); - - protected: - virtual ~AtomRenderViewObserver(); - - private: - // content::RenderViewObserver implementation. - void DidCreateDocumentElement(blink::WebLocalFrame* frame) override; - void DraggableRegionsChanged(blink::WebFrame* frame) override; - bool OnMessageReceived(const IPC::Message& message) override; - - void OnBrowserMessage(bool send_to_all, - const base::string16& channel, - const base::ListValue& args); - - // Weak reference to renderer client. - AtomRendererClient* renderer_client_; - - // Whether the document object has been created. - bool document_created_; - - DISALLOW_COPY_AND_ASSIGN(AtomRenderViewObserver); -}; - -} // namespace atom - -#endif // ATOM_RENDERER_ATOM_RENDER_VIEW_OBSERVER_H_ diff --git a/atom/renderer/atom_renderer_client.cc b/atom/renderer/atom_renderer_client.cc deleted file mode 100644 index d2c341fa27f57..0000000000000 --- a/atom/renderer/atom_renderer_client.cc +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/renderer/atom_renderer_client.h" - -#include -#include - -#include "atom/common/api/api_messages.h" -#include "atom/common/api/atom_bindings.h" -#include "atom/common/api/event_emitter_caller.h" -#include "atom/common/color_util.h" -#include "atom/common/native_mate_converters/value_converter.h" -#include "atom/common/node_bindings.h" -#include "atom/common/node_includes.h" -#include "atom/common/options_switches.h" -#include "atom/renderer/atom_render_view_observer.h" -#include "atom/renderer/guest_view_container.h" -#include "atom/renderer/node_array_buffer_bridge.h" -#include "atom/renderer/preferences_manager.h" -#include "base/command_line.h" -#include "chrome/renderer/media/chrome_key_systems.h" -#include "chrome/renderer/pepper/pepper_helper.h" -#include "chrome/renderer/printing/print_web_view_helper.h" -#include "chrome/renderer/tts_dispatcher.h" -#include "content/public/common/content_constants.h" -#include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_frame_observer.h" -#include "content/public/renderer/render_thread.h" -#include "content/public/renderer/render_view.h" -#include "ipc/ipc_message_macros.h" -#include "native_mate/dictionary.h" -#include "third_party/WebKit/public/web/WebCustomElement.h" -#include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebFrameWidget.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebPluginParams.h" -#include "third_party/WebKit/public/web/WebKit.h" -#include "third_party/WebKit/public/web/WebScriptSource.h" -#include "third_party/WebKit/public/web/WebSecurityPolicy.h" -#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" -#include "third_party/WebKit/public/web/WebView.h" - -#if defined(OS_MACOSX) -#include "base/mac/mac_util.h" -#include "base/strings/sys_string_conversions.h" -#endif - -#if defined(OS_WIN) -#include -#endif - -namespace atom { - -namespace { - -// Helper class to forward the messages to the client. -class AtomRenderFrameObserver : public content::RenderFrameObserver { - public: - AtomRenderFrameObserver(content::RenderFrame* frame, - AtomRendererClient* renderer_client) - : content::RenderFrameObserver(frame), - render_frame_(frame), - world_id_(-1), - renderer_client_(renderer_client) {} - - // content::RenderFrameObserver: - void DidClearWindowObject() override { - renderer_client_->DidClearWindowObject(render_frame_); - } - - void DidCreateScriptContext(v8::Handle context, - int extension_group, - int world_id) override { - if (world_id_ != -1 && world_id_ != world_id) - return; - world_id_ = world_id; - renderer_client_->DidCreateScriptContext(context, render_frame_); - } - void WillReleaseScriptContext(v8::Local context, - int world_id) override { - if (world_id_ != world_id) - return; - renderer_client_->WillReleaseScriptContext(context, render_frame_); - } - - private: - content::RenderFrame* render_frame_; - int world_id_; - AtomRendererClient* renderer_client_; - - DISALLOW_COPY_AND_ASSIGN(AtomRenderFrameObserver); -}; - -v8::Local GetRenderProcessPreferences( - const PreferencesManager* preferences_manager, v8::Isolate* isolate) { - if (preferences_manager->preferences()) - return mate::ConvertToV8(isolate, *preferences_manager->preferences()); - else - return v8::Null(isolate); -} - -void AddRenderBindings(v8::Isolate* isolate, - v8::Local process, - const PreferencesManager* preferences_manager) { - mate::Dictionary dict(isolate, process); - dict.SetMethod( - "getRenderProcessPreferences", - base::Bind(GetRenderProcessPreferences, preferences_manager)); -} - -bool IsDevToolsExtension(content::RenderFrame* render_frame) { - return static_cast(render_frame->GetWebFrame()->document().url()) - .SchemeIs("chrome-extension"); -} - -} // namespace - -AtomRendererClient::AtomRendererClient() - : node_bindings_(NodeBindings::Create(false)), - atom_bindings_(new AtomBindings) { - // Parse --standard-schemes=scheme1,scheme2 - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - std::string custom_schemes = command_line->GetSwitchValueASCII( - switches::kStandardSchemes); - if (!custom_schemes.empty()) { - std::vector schemes_list = base::SplitString( - custom_schemes, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - for (const std::string& scheme : schemes_list) - url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); - } -} - -AtomRendererClient::~AtomRendererClient() { -} - -void AtomRendererClient::RenderThreadStarted() { - blink::WebCustomElement::addEmbedderCustomElementName("webview"); - blink::WebCustomElement::addEmbedderCustomElementName("browserplugin"); - - OverrideNodeArrayBuffer(); - - preferences_manager_.reset(new PreferencesManager); - -#if defined(OS_WIN) - // Set ApplicationUserModelID in renderer process. - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - base::string16 app_id = - command_line->GetSwitchValueNative(switches::kAppUserModelId); - if (!app_id.empty()) { - SetCurrentProcessExplicitAppUserModelID(app_id.c_str()); - } -#endif - -#if defined(OS_MACOSX) - // Disable rubber banding by default. - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (!command_line->HasSwitch(switches::kScrollBounce)) { - base::ScopedCFTypeRef key( - base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding")); - base::ScopedCFTypeRef value( - base::SysUTF8ToCFStringRef("false")); - CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication); - CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); - } -#endif -} - -void AtomRendererClient::RenderFrameCreated( - content::RenderFrame* render_frame) { - new PepperHelper(render_frame); - new AtomRenderFrameObserver(render_frame, this); - - // Allow file scheme to handle service worker by default. - // FIXME(zcbenz): Can this be moved elsewhere? - blink::WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers("file"); -} - -void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) { - new printing::PrintWebViewHelper(render_view); - new AtomRenderViewObserver(render_view, this); - - blink::WebFrameWidget* web_frame_widget = render_view->GetWebFrameWidget(); - if (!web_frame_widget) - return; - - base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); - if (cmd->HasSwitch(switches::kGuestInstanceID)) { // webview. - web_frame_widget->setBaseBackgroundColor(SK_ColorTRANSPARENT); - } else { // normal window. - // If backgroundColor is specified then use it. - std::string name = cmd->GetSwitchValueASCII(switches::kBackgroundColor); - // Otherwise use white background. - SkColor color = name.empty() ? SK_ColorWHITE : ParseHexColor(name); - web_frame_widget->setBaseBackgroundColor(color); - } -} - -void AtomRendererClient::DidClearWindowObject( - content::RenderFrame* render_frame) { - // Make sure every page will get a script context created. - render_frame->GetWebFrame()->executeScript(blink::WebScriptSource("void 0")); -} - -void AtomRendererClient::RunScriptsAtDocumentStart( - content::RenderFrame* render_frame) { - // Inform the document start pharse. - node::Environment* env = node_bindings_->uv_env(); - if (env) { - v8::HandleScope handle_scope(env->isolate()); - mate::EmitEvent(env->isolate(), env->process_object(), "document-start"); - } -} - -void AtomRendererClient::RunScriptsAtDocumentEnd( - content::RenderFrame* render_frame) { - // Inform the document end pharse. - node::Environment* env = node_bindings_->uv_env(); - if (env) { - v8::HandleScope handle_scope(env->isolate()); - mate::EmitEvent(env->isolate(), env->process_object(), "document-end"); - } -} - -blink::WebSpeechSynthesizer* AtomRendererClient::OverrideSpeechSynthesizer( - blink::WebSpeechSynthesizerClient* client) { - return new TtsDispatcher(client); -} - -bool AtomRendererClient::OverrideCreatePlugin( - content::RenderFrame* render_frame, - blink::WebLocalFrame* frame, - const blink::WebPluginParams& params, - blink::WebPlugin** plugin) { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (params.mimeType.utf8() == content::kBrowserPluginMimeType || - command_line->HasSwitch(switches::kEnablePlugins)) - return false; - - *plugin = nullptr; - return true; -} - -void AtomRendererClient::DidCreateScriptContext( - v8::Handle context, content::RenderFrame* render_frame) { - // Only allow node integration for the main frame, unless it is a devtools - // extension page. - if (!render_frame->IsMainFrame() && !IsDevToolsExtension(render_frame)) - return; - - // Whether the node binding has been initialized. - bool first_time = node_bindings_->uv_env() == nullptr; - - // Prepare the node bindings. - if (first_time) { - node_bindings_->Initialize(); - node_bindings_->PrepareMessageLoop(); - } - - // Setup node environment for each window. - node::Environment* env = node_bindings_->CreateEnvironment(context); - - // Add atom-shell extended APIs. - atom_bindings_->BindTo(env->isolate(), env->process_object()); - AddRenderBindings(env->isolate(), env->process_object(), - preferences_manager_.get()); - - // Load everything. - node_bindings_->LoadEnvironment(env); - - if (first_time) { - // Make uv loop being wrapped by window context. - node_bindings_->set_uv_env(env); - - // Give the node loop a run to make sure everything is ready. - node_bindings_->RunMessageLoop(); - } -} - -void AtomRendererClient::WillReleaseScriptContext( - v8::Handle context, content::RenderFrame* render_frame) { - // Only allow node integration for the main frame, unless it is a devtools - // extension page. - if (!render_frame->IsMainFrame() && !IsDevToolsExtension(render_frame)) - return; - - node::Environment* env = node::Environment::GetCurrent(context); - if (env) - mate::EmitEvent(env->isolate(), env->process_object(), "exit"); -} - -bool AtomRendererClient::ShouldFork(blink::WebLocalFrame* frame, - const GURL& url, - const std::string& http_method, - bool is_initial_navigation, - bool is_server_redirect, - bool* send_referrer) { - // Handle all the navigations and reloads in browser. - // FIXME We only support GET here because http method will be ignored when - // the OpenURLFromTab is triggered, which means form posting would not work, - // we should solve this by patching Chromium in future. - *send_referrer = true; - return http_method == "GET"; -} - -content::BrowserPluginDelegate* AtomRendererClient::CreateBrowserPluginDelegate( - content::RenderFrame* render_frame, - const std::string& mime_type, - const GURL& original_url) { - if (mime_type == content::kBrowserPluginMimeType) { - return new GuestViewContainer(render_frame); - } else { - return nullptr; - } -} - -void AtomRendererClient::AddSupportedKeySystems( - std::vector>* key_systems) { - AddChromeKeySystems(key_systems); -} - -} // namespace atom diff --git a/atom/renderer/atom_renderer_client.h b/atom/renderer/atom_renderer_client.h deleted file mode 100644 index 5419692d2aeba..0000000000000 --- a/atom/renderer/atom_renderer_client.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2013 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_RENDERER_ATOM_RENDERER_CLIENT_H_ -#define ATOM_RENDERER_ATOM_RENDERER_CLIENT_H_ - -#include -#include - -#include "content/public/renderer/content_renderer_client.h" - -namespace atom { - -class AtomBindings; -class PreferencesManager; -class NodeBindings; - -class AtomRendererClient : public content::ContentRendererClient { - public: - AtomRendererClient(); - virtual ~AtomRendererClient(); - - void DidClearWindowObject(content::RenderFrame* render_frame); - void DidCreateScriptContext( - v8::Handle context, content::RenderFrame* render_frame); - void WillReleaseScriptContext( - v8::Handle context, content::RenderFrame* render_frame); - - private: - enum NodeIntegration { - ALL, - EXCEPT_IFRAME, - MANUAL_ENABLE_IFRAME, - DISABLE, - }; - - // content::ContentRendererClient: - void RenderThreadStarted() override; - void RenderFrameCreated(content::RenderFrame*) override; - void RenderViewCreated(content::RenderView*) override; - void RunScriptsAtDocumentStart(content::RenderFrame* render_frame) override; - void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) override; - blink::WebSpeechSynthesizer* OverrideSpeechSynthesizer( - blink::WebSpeechSynthesizerClient* client) override; - bool OverrideCreatePlugin(content::RenderFrame* render_frame, - blink::WebLocalFrame* frame, - const blink::WebPluginParams& params, - blink::WebPlugin** plugin) override; - bool ShouldFork(blink::WebLocalFrame* frame, - const GURL& url, - const std::string& http_method, - bool is_initial_navigation, - bool is_server_redirect, - bool* send_referrer) override; - content::BrowserPluginDelegate* CreateBrowserPluginDelegate( - content::RenderFrame* render_frame, - const std::string& mime_type, - const GURL& original_url) override; - void AddSupportedKeySystems( - std::vector>* key_systems) - override; - - std::unique_ptr node_bindings_; - std::unique_ptr atom_bindings_; - std::unique_ptr preferences_manager_; - - DISALLOW_COPY_AND_ASSIGN(AtomRendererClient); -}; - -} // namespace atom - -#endif // ATOM_RENDERER_ATOM_RENDERER_CLIENT_H_ diff --git a/atom/renderer/guest_view_container.cc b/atom/renderer/guest_view_container.cc deleted file mode 100644 index f50c3f78685c0..0000000000000 --- a/atom/renderer/guest_view_container.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/renderer/guest_view_container.h" - -#include - -#include "base/bind.h" -#include "base/lazy_instance.h" -#include "base/message_loop/message_loop.h" -#include "ui/gfx/geometry/size.h" - -namespace atom { - -namespace { - -using GuestViewContainerMap = std::map; -static base::LazyInstance g_guest_view_container_map = - LAZY_INSTANCE_INITIALIZER; - -} // namespace - -GuestViewContainer::GuestViewContainer(content::RenderFrame* render_frame) - : render_frame_(render_frame), - weak_ptr_factory_(this) { -} - -GuestViewContainer::~GuestViewContainer() { - if (element_instance_id_ > 0) - g_guest_view_container_map.Get().erase(element_instance_id_); -} - -// static -GuestViewContainer* GuestViewContainer::FromID(int element_instance_id) { - GuestViewContainerMap* guest_view_containers = - g_guest_view_container_map.Pointer(); - auto it = guest_view_containers->find(element_instance_id); - return it == guest_view_containers->end() ? nullptr : it->second; -} - -void GuestViewContainer::RegisterElementResizeCallback( - const ResizeCallback& callback) { - element_resize_callback_ = callback; -} - -void GuestViewContainer::SetElementInstanceID(int element_instance_id) { - element_instance_id_ = element_instance_id; - g_guest_view_container_map.Get().insert( - std::make_pair(element_instance_id, this)); -} - -void GuestViewContainer::DidResizeElement(const gfx::Size& new_size) { - if (element_resize_callback_.is_null()) - return; - - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(element_resize_callback_, new_size)); -} - -base::WeakPtr GuestViewContainer::GetWeakPtr() { - return weak_ptr_factory_.GetWeakPtr(); -} - -} // namespace atom diff --git a/atom/renderer/guest_view_container.h b/atom/renderer/guest_view_container.h deleted file mode 100644 index 3771c7adc4e6c..0000000000000 --- a/atom/renderer/guest_view_container.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_RENDERER_GUEST_VIEW_CONTAINER_H_ -#define ATOM_RENDERER_GUEST_VIEW_CONTAINER_H_ - -#include "base/callback.h" -#include "content/public/renderer/browser_plugin_delegate.h" - -namespace gfx { -class Size; -} - -namespace atom { - -class GuestViewContainer : public content::BrowserPluginDelegate { - public: - typedef base::Callback ResizeCallback; - - explicit GuestViewContainer(content::RenderFrame* render_frame); - ~GuestViewContainer() override; - - static GuestViewContainer* FromID(int element_instance_id); - - void RegisterElementResizeCallback(const ResizeCallback& callback); - - // content::BrowserPluginDelegate: - void SetElementInstanceID(int element_instance_id) final; - void DidResizeElement(const gfx::Size& new_size) final; - base::WeakPtr GetWeakPtr() final; - - private: - int element_instance_id_; - content::RenderFrame* render_frame_; - - ResizeCallback element_resize_callback_; - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(GuestViewContainer); -}; - -} // namespace atom - -#endif // ATOM_RENDERER_GUEST_VIEW_CONTAINER_H_ diff --git a/atom/renderer/node_array_buffer_bridge.cc b/atom/renderer/node_array_buffer_bridge.cc deleted file mode 100644 index 61ad25222f994..0000000000000 --- a/atom/renderer/node_array_buffer_bridge.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/renderer/node_array_buffer_bridge.h" - -#include "base/macros.h" -#include "atom/common/node_includes.h" -#include "native_mate/converter.h" -#include "third_party/WebKit/public/web/WebArrayBuffer.h" -#include "third_party/WebKit/public/web/WebArrayBufferConverter.h" - -namespace atom { - -namespace { - -// global.Uint8Array; -v8::Local GetUint8ArrayConstructor( - v8::Isolate* isolate, v8::Local context) { - v8::Local constructor = context->Global()->Get( - mate::StringToV8(isolate, "Uint8Array")); - return v8::Local::Cast(constructor); -} - -// new ArrayBuffer(size); -v8::Local BlinkArrayBufferNew( - v8::Isolate* isolate, size_t size) { - blink::WebArrayBuffer buffer = blink::WebArrayBuffer::create(size, 1); - return v8::Local::Cast( - blink::WebArrayBufferConverter::toV8Value( - &buffer, isolate->GetCurrentContext()->Global(), isolate)); -} - -// new ArrayBuffer(data, size); -v8::Local BlinkArrayBufferNewWith( - v8::Isolate* isolate, void* data, size_t size) { - blink::WebArrayBuffer buffer = blink::WebArrayBuffer::createExternal( - data, size); - return v8::Local::Cast( - blink::WebArrayBufferConverter::toV8Value( - &buffer, isolate->GetCurrentContext()->Global(), isolate)); -} - -// new Uint8Array(array_buffer, offset, size); -v8::Local BlinkUint8ArrayNew( - v8::Local ab, size_t offset, size_t size) { - // Use the DOM's Uint8Array constructor to create Uint8Array. - v8::Local context = ab->CreationContext(); - v8::Isolate* isolate = context->GetIsolate(); - v8::Local constructor = - GetUint8ArrayConstructor(isolate, context); - v8::Local args[] = { - ab, mate::ConvertToV8(isolate, offset), mate::ConvertToV8(isolate, size) - }; - return v8::Local::Cast(constructor->NewInstance( - context, node::arraysize(args), args).ToLocalChecked()); -} - -} // namespace - -void OverrideNodeArrayBuffer() { - node::Buffer::SetArrayBufferCreator( - BlinkArrayBufferNew, BlinkArrayBufferNewWith, BlinkUint8ArrayNew); -} - -} // namespace atom diff --git a/atom/renderer/node_array_buffer_bridge.h b/atom/renderer/node_array_buffer_bridge.h deleted file mode 100644 index 61d1806993121..0000000000000 --- a/atom/renderer/node_array_buffer_bridge.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_RENDERER_NODE_ARRAY_BUFFER_BRIDGE_H_ -#define ATOM_RENDERER_NODE_ARRAY_BUFFER_BRIDGE_H_ - -namespace atom { - -// Override Node's ArrayBuffer with DOM's ArrayBuffer. -void OverrideNodeArrayBuffer(); - -} // namespace atom - -#endif // ATOM_RENDERER_NODE_ARRAY_BUFFER_BRIDGE_H_ diff --git a/atom/renderer/preferences_manager.cc b/atom/renderer/preferences_manager.cc deleted file mode 100644 index a9ed710a9dbd5..0000000000000 --- a/atom/renderer/preferences_manager.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/renderer/preferences_manager.h" - -#include "atom/common/api/api_messages.h" -#include "content/public/renderer/render_thread.h" - -namespace atom { - -PreferencesManager::PreferencesManager() { - content::RenderThread::Get()->AddObserver(this); -} - -PreferencesManager::~PreferencesManager() { -} - -bool PreferencesManager::OnControlMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PreferencesManager, message) - IPC_MESSAGE_HANDLER(AtomMsg_UpdatePreferences, OnUpdatePreferences) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void PreferencesManager::OnUpdatePreferences( - const base::ListValue& preferences) { - preferences_ = preferences.CreateDeepCopy(); -} - -} // namespace atom diff --git a/atom/renderer/preferences_manager.h b/atom/renderer/preferences_manager.h deleted file mode 100644 index c531fe879ace2..0000000000000 --- a/atom/renderer/preferences_manager.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2016 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_RENDERER_PREFERENCES_MANAGER_H_ -#define ATOM_RENDERER_PREFERENCES_MANAGER_H_ - -#include - -#include "base/values.h" -#include "content/public/renderer/render_thread_observer.h" - -namespace atom { - -class PreferencesManager : public content::RenderThreadObserver { - public: - PreferencesManager(); - ~PreferencesManager() override; - - const base::ListValue* preferences() const { return preferences_.get(); } - - private: - // content::RenderThreadObserver: - bool OnControlMessageReceived(const IPC::Message& message) override; - - void OnUpdatePreferences(const base::ListValue& preferences); - - std::unique_ptr preferences_; - - DISALLOW_COPY_AND_ASSIGN(PreferencesManager); -}; - -} // namespace atom - -#endif // ATOM_RENDERER_PREFERENCES_MANAGER_H_ diff --git a/atom/renderer/resources/mac/Info.plist b/atom/renderer/resources/mac/Info.plist deleted file mode 100644 index 1da2c29fd9ca2..0000000000000 --- a/atom/renderer/resources/mac/Info.plist +++ /dev/null @@ -1,16 +0,0 @@ - - - - - CFBundleIdentifier - ${ATOM_BUNDLE_ID} - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - LSUIElement - - NSSupportsAutomaticGraphicsSwitching - - - diff --git a/atom/utility/atom_content_utility_client.cc b/atom/utility/atom_content_utility_client.cc deleted file mode 100644 index 8d4ccf628933c..0000000000000 --- a/atom/utility/atom_content_utility_client.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#include "atom/utility/atom_content_utility_client.h" - -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/memory/ref_counted.h" -#include "base/time/time.h" -#include "chrome/common/chrome_utility_messages.h" -#include "chrome/utility/utility_message_handler.h" -#include "content/public/common/content_switches.h" -#include "content/public/utility/utility_thread.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_message_macros.h" - - -#if defined(OS_WIN) -#include "chrome/utility/printing_handler_win.h" -#endif - - -namespace { - -bool Send(IPC::Message* message) { - return content::UtilityThread::Get()->Send(message); -} - -} // namespace - -namespace atom { - -int64_t AtomContentUtilityClient::max_ipc_message_size_ = - IPC::Channel::kMaximumMessageSize; - -AtomContentUtilityClient::AtomContentUtilityClient() - : filter_messages_(false) { -#if defined(OS_WIN) - handlers_.push_back(new printing::PrintingHandlerWin()); -#endif -} - -AtomContentUtilityClient::~AtomContentUtilityClient() { -} - -void AtomContentUtilityClient::UtilityThreadStarted() { -} - -bool AtomContentUtilityClient::OnMessageReceived( - const IPC::Message& message) { - if (filter_messages_ && !ContainsKey(message_id_whitelist_, message.type())) - return false; - - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(AtomContentUtilityClient, message) - IPC_MESSAGE_HANDLER(ChromeUtilityMsg_StartupPing, OnStartupPing) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - for (auto it = handlers_.begin(); !handled && it != handlers_.end(); ++it) { - handled = (*it)->OnMessageReceived(message); - } - - return handled; -} - -void AtomContentUtilityClient::OnStartupPing() { - Send(new ChromeUtilityHostMsg_ProcessStarted); - // Don't release the process, we assume further messages are on the way. -} - -} // namespace atom diff --git a/atom/utility/atom_content_utility_client.h b/atom/utility/atom_content_utility_client.h deleted file mode 100644 index ba0fef471a11e..0000000000000 --- a/atom/utility/atom_content_utility_client.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2015 GitHub, Inc. -// Use of this source code is governed by the MIT license that can be -// found in the LICENSE file. - -#ifndef ATOM_UTILITY_ATOM_CONTENT_UTILITY_CLIENT_H_ -#define ATOM_UTILITY_ATOM_CONTENT_UTILITY_CLIENT_H_ - -#include -#include -#include - -#include "base/compiler_specific.h" -#include "base/memory/scoped_vector.h" -#include "content/public/utility/content_utility_client.h" -#include "ipc/ipc_platform_file.h" - -namespace base { -class FilePath; -struct FileDescriptor; -} - -class UtilityMessageHandler; - -namespace atom { - -class AtomContentUtilityClient : public content::ContentUtilityClient { - public: - AtomContentUtilityClient(); - ~AtomContentUtilityClient() override; - - void UtilityThreadStarted() override; - bool OnMessageReceived(const IPC::Message& message) override; - - static void set_max_ipc_message_size_for_test(int64_t max_message_size) { - max_ipc_message_size_ = max_message_size; - } - - private: - void OnStartupPing(); - - typedef ScopedVector Handlers; - Handlers handlers_; - - // Flag to enable whitelisting. - bool filter_messages_; - // A list of message_ids to filter. - std::set message_id_whitelist_; - // Maximum IPC msg size (default to kMaximumMessageSize; override for testing) - static int64_t max_ipc_message_size_; - - DISALLOW_COPY_AND_ASSIGN(AtomContentUtilityClient); -}; - -} // namespace atom - -#endif // ATOM_UTILITY_ATOM_CONTENT_UTILITY_CLIENT_H_ diff --git a/build/args/all.gn b/build/args/all.gn new file mode 100644 index 0000000000000..35b8b0045c088 --- /dev/null +++ b/build/args/all.gn @@ -0,0 +1,71 @@ +is_electron_build = true +root_extra_deps = [ "//electron" ] + +# Registry of NMVs --> https://github.com/nodejs/node/blob/main/doc/abi_version_registry.json +node_module_version = 148 + +v8_promise_internal_field_count = 1 +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 +ffmpeg_branding = "Chrome" +proprietary_codecs = true + +enable_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 + +# 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 new file mode 100644 index 0000000000000..c25abfd25fa4b --- /dev/null +++ b/build/args/ffmpeg.gn @@ -0,0 +1,7 @@ +import("//electron/build/args/all.gn") +is_component_build = false +is_component_ffmpeg = true +is_official_build = true +ffmpeg_branding = "Chromium" +enable_dsyms = false +proprietary_codecs = false diff --git a/build/args/native_tests.gn b/build/args/native_tests.gn new file mode 100644 index 0000000000000..26d6bf3dce4f3 --- /dev/null +++ b/build/args/native_tests.gn @@ -0,0 +1,7 @@ +root_extra_deps = [ "//electron/spec-chromium:spec" ] + +dcheck_always_on = true +is_debug = false +is_component_build = false +is_component_ffmpeg = false +symbol_level = 1 diff --git a/build/args/release.gn b/build/args/release.gn new file mode 100644 index 0000000000000..77351cc181ad9 --- /dev/null +++ b/build/args/release.gn @@ -0,0 +1,9 @@ +import("//electron/build/args/all.gn") +is_component_build = false +is_official_build = true + +# 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, +# we build ffmpeg as a shared library. +is_component_ffmpeg = true diff --git a/build/args/testing.gn b/build/args/testing.gn new file mode 100644 index 0000000000000..395734c594329 --- /dev/null +++ b/build/args/testing.gn @@ -0,0 +1,7 @@ +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 diff --git a/build/asar.gni b/build/asar.gni new file mode 100644 index 0000000000000..b8b290da2c670 --- /dev/null +++ b/build/asar.gni @@ -0,0 +1,87 @@ +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, + [ + "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 + } +} + +template("asar") { + assert(defined(invoker.sources), + "Need sources in $target_name listing the source files") + assert(defined(invoker.outputs), + "Need asar name (as 1-element array, e.g. \$root_out_dir/foo.asar)") + assert(defined(invoker.root), "Need the base dir for generating the ASAR") + + node_action(target_name) { + forward_variables_from(invoker, + "*", + [ + "script", + "args", + ]) + + script = "//electron/script/gn-asar.js" + args = [ + "--base", + rebase_path(root), + "--files", + ] + rebase_path(sources) + + [ + "--out", + 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 new file mode 100644 index 0000000000000..a82a0d7e316ee --- /dev/null +++ b/build/config/BUILD.gn @@ -0,0 +1,11 @@ +action("generate_mas_config") { + outputs = [ "$target_gen_dir/../../mas.h" ] + script = "../../script/generate-mas-config.py" + if (is_mas_build) { + args = [ "true" ] + } else { + args = [ "false" ] + } + + args += rebase_path(outputs) +} diff --git a/build/dump_syms.py b/build/dump_syms.py new file mode 100644 index 0000000000000..8b38944928e59 --- /dev/null +++ b/build/dump_syms.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +import collections +import os +import subprocess +import sys +import errno + +# The BINARY_INFO tuple describes a binary as dump_syms identifies it. +BINARY_INFO = collections.namedtuple('BINARY_INFO', + ['platform', 'arch', 'hash', 'name']) + +def get_module_info(header_info): + # header info is of the form "MODULE $PLATFORM $ARCH $HASH $BINARY" + info_split = header_info.strip().split(' ', 4) + if len(info_split) != 5 or info_split[0] != 'MODULE': + return None + return BINARY_INFO(*info_split[1:]) + +def get_symbol_path(symbol_data): + module_info = get_module_info(symbol_data[:symbol_data.index('\n')]) + if not module_info: + raise Exception("Couldn't get module info for binary '{}'".format(binary)) + exe_name = module_info.name.replace('.pdb', '') + return os.path.join(module_info.name, module_info.hash, exe_name + ".sym") + +def mkdir_p(path): + """Simulates mkdir -p.""" + try: + os.makedirs(path) + except OSError as e: + if e.errno == errno.EEXIST and os.path.isdir(path): + pass + else: raise + +def main(dump_syms, binary, out_dir, stamp_file, dsym_file=None): + args = [dump_syms] + if dsym_file: + args += ["-g", dsym_file] + args += [binary] + + 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)) + + with open(symbol_path, 'w') as out: + out.write(symbol_data) + + with open(stamp_file, 'w'): + pass + +if __name__ == '__main__': + main(*sys.argv[1:]) diff --git a/build/electron.def b/build/electron.def new file mode 100644 index 0000000000000..311ad202e674c --- /dev/null +++ b/build/electron.def @@ -0,0 +1,6 @@ +; This is to support renaming of electron.exe. node-gyp has hard-coded +; executable names which it will recognise as node. This module definition +; file claims that the electron executable is in fact named "node.exe", +; which is one of the executable names that node-gyp recognizes. +; See https://github.com/nodejs/node-gyp/commit/52ceec3a6d15de3a8f385f43dbe5ecf5456ad07a +NAME node.exe diff --git a/build/electron_paks.gni b/build/electron_paks.gni new file mode 100644 index 0000000000000..26a4982dfe23a --- /dev/null +++ b/build/electron_paks.gni @@ -0,0 +1,243 @@ +import("//build/config/locales.gni") +import("//electron/buildflags/buildflags.gni") +import("//printing/buildflags/buildflags.gni") +import("//tools/grit/repack.gni") +import("//ui/base/ui_features.gni") + +# See: //chrome/chrome_paks.gni +template("electron_repack_percent") { + percent = invoker.percent + + repack(target_name) { + forward_variables_from(invoker, + [ + "copy_data_to_bundle", + "repack_whitelist", + "visibility", + ]) + + # All sources should also have deps for completeness. + sources = [ + "$root_gen_dir/components/components_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", + "//third_party/blink/public:scaled_resources_${percent}_percent", + "//ui/resources", + ] + + if (defined(invoker.deps)) { + deps += invoker.deps + } + + if (toolkit_views) { + sources += [ "$root_gen_dir/ui/views/resources/views_resources_${percent}_percent.pak" ] + deps += [ "//ui/views/resources" ] + } + + output = "${invoker.output_dir}/chrome_${percent}_percent.pak" + } +} + +template("electron_extra_paks") { + repack(target_name) { + forward_variables_from(invoker, + [ + "copy_data_to_bundle", + "repack_whitelist", + "visibility", + ]) + output = "${invoker.output_dir}/resources.pak" + sources = [ + "$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/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/third_party/blink/public/strings/permission_element_generated_strings.pak", + "$target_gen_dir/electron_resources.pak", + ] + deps = [ + "//chrome/browser:resources", + "//chrome/browser/resources/accessibility:resources", + "//chrome/common:resources", + "//components/resources", + "//content:content_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", + "//mojo/public/js:resources", + "//net:net_resources", + "//third_party/blink/public:devtools_inspector_resources", + "//third_party/blink/public:resources", + "//third_party/blink/public/strings:permission_element_generated_strings", + "//ui/webui/resources", + ] + if (defined(invoker.deps)) { + deps += invoker.deps + } + if (defined(invoker.additional_paks)) { + sources += invoker.additional_paks + } + + # New paks should be added here by default. + 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:resources" ] + } + if (enable_electron_extensions) { + sources += [ + "$root_gen_dir/chrome/component_extension_resources.pak", + "$root_gen_dir/extensions/extensions_renderer_resources.pak", + "$root_gen_dir/extensions/extensions_resources.pak", + ] + deps += [ + "//chrome/browser/resources:component_extension_resources", + "//extensions:extensions_resources", + ] + } + } +} + +template("electron_paks") { + electron_repack_percent("${target_name}_100_percent") { + percent = "100" + forward_variables_from(invoker, + [ + "copy_data_to_bundle", + "deps", + "output_dir", + "repack_whitelist", + "visibility", + ]) + } + + if (enable_hidpi) { + electron_repack_percent("${target_name}_200_percent") { + percent = "200" + forward_variables_from(invoker, + [ + "copy_data_to_bundle", + "deps", + "output_dir", + "repack_whitelist", + "visibility", + ]) + } + } + + electron_extra_paks("${target_name}_extra") { + forward_variables_from(invoker, + [ + "copy_data_to_bundle", + "deps", + "output_dir", + "repack_whitelist", + "visibility", + ]) + if (defined(invoker.additional_extra_paks)) { + additional_paks = invoker.additional_extra_paks + } + } + + repack_locales("${target_name}_locales") { + forward_variables_from(invoker, + [ + "copy_data_to_bundle", + "deps", + "visibility", + ]) + if (defined(invoker.locale_whitelist)) { + repack_whitelist = invoker.locale_whitelist + } else if (defined(invoker.repack_whitelist)) { + repack_whitelist = invoker.repack_whitelist + } + + 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}/device/bluetooth/strings/bluetooth_strings_", + "${root_gen_dir}/device/fido/strings/fido_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}/third_party/blink/public/strings/permission_element_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", + "//device/fido/strings", + "//electron:resources", + "//extensions/strings", + "//services/strings", + "//third_party/blink/public/strings", + "//third_party/blink/public/strings:permission_element_strings", + "//ui/strings:app_locale_settings", + "//ui/strings:auto_image_annotation_strings", + "//ui/strings:ax_strings", + "//ui/strings:ui_strings", + ] + + input_locales = platform_pak_locales + output_dir = "${invoker.output_dir}/locales" + + if (is_mac) { + output_locales = locales_as_apple_outputs + } else { + output_locales = platform_pak_locales + } + } + + group(target_name) { + forward_variables_from(invoker, [ "deps" ]) + public_deps = [ + ":${target_name}_100_percent", + ":${target_name}_extra", + ":${target_name}_locales", + ] + if (enable_hidpi) { + public_deps += [ ":${target_name}_200_percent" ] + } + if (defined(invoker.public_deps)) { + public_deps += invoker.public_deps + } + } +} 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 new file mode 100644 index 0000000000000..8d6c2e72b9386 --- /dev/null +++ b/build/extract_symbols.gni @@ -0,0 +1,54 @@ +import("//build/toolchain/toolchain.gni") + +# Extracts symbols from a binary into a symbol file using dump_syms. +# +# Args: +# binary: Path to the binary containing symbols to extract, e.g.: +# "$root_out_dir/electron" +# symbol_dir: Desired output directory for symbols, e.g.: +# "$root_out_dir/breakpad_symbols" + +if (host_os == "win") { + _host_executable_suffix = ".exe" +} else { + _host_executable_suffix = "" +} + +template("extract_symbols") { + action(target_name) { + forward_variables_from(invoker, + [ + "deps", + "testonly", + ]) + 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_system_allocator_toolchain)" + dump_syms_binary = get_label_info(dump_syms_label, "root_out_dir") + + "/dump_syms$_host_executable_suffix" + + script = "//electron/build/dump_syms.py" + inputs = [ + invoker.binary, + dump_syms_binary, + ] + stamp_file = "${target_gen_dir}/${target_name}.stamp" + outputs = [ stamp_file ] + args = [ + "./" + rebase_path(dump_syms_binary, root_build_dir), + rebase_path(invoker.binary, root_build_dir), + rebase_path(invoker.symbol_dir, root_build_dir), + rebase_path(stamp_file, root_build_dir), + ] + if (defined(invoker.dsym_file)) { + args += [ rebase_path(invoker.dsym_file, root_build_dir) ] + } + + if (!defined(deps)) { + deps = [] + } + deps += [ dump_syms_label ] + } +} diff --git a/build/fuses/build.py b/build/fuses/build.py new file mode 100755 index 0000000000000..77f269f6e837d --- /dev/null +++ b/build/fuses/build.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +from collections import OrderedDict +import json +import os +import sys + +dir_path = os.path.dirname(os.path.realpath(__file__)) + +SENTINEL = "dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX" + +TEMPLATE_H = """ +#ifndef ELECTRON_FUSES_H_ +#define ELECTRON_FUSES_H_ + +#if defined(WIN32) +#define FUSE_EXPORT __declspec(dllexport) +#else +#define FUSE_EXPORT __attribute__((visibility("default"))) +#endif + +namespace electron::fuses { + +extern const volatile char kFuseWire[]; + +{getters} + +} // namespace electron::fuses + +#endif // ELECTRON_FUSES_H_ +""" + +TEMPLATE_CC = """ +#include "electron/fuses.h" +#include "base/dcheck_is_on.h" + +#if DCHECK_IS_ON() +#include "base/command_line.h" +#include +#endif + +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.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'] +del fuse_defaults['_schema'] +del fuse_defaults['_comment'] + +if fuse_version >= pow(2, 8): + raise Exception("Fuse version can not exceed one byte in size") + +fuses = fuse_defaults.keys() + +initial_config = "" +getters_h = "" +getters_cc = "" +index = len(SENTINEL) + 1 +for fuse in fuses: + index += 1 + initial_config += fuse_defaults[fuse] + name = ''.join(word.title() for word in fuse.split('_')) + 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("{switch_name}", f"set-fuse-{fuse.lower()}").replace("{index}", str(index)) + +def c_hex(n): + s = hex(n)[2:] + return "0x" + s.rjust(2, '0') + +def hex_arr(s): + arr = [] + for char in s: + arr.append(c_hex(ord(char))) + return ",".join(arr) + +header = TEMPLATE_H.replace("{getters}", getters_h.strip()) +impl = TEMPLATE_CC.replace("{sentinel}", hex_arr(SENTINEL)) +impl = impl.replace("{fuse_version}", c_hex(fuse_version)) +impl = impl.replace("{fuse_wire_length}", c_hex(len(fuses))) +impl = impl.replace("{initial_config}", hex_arr(initial_config)) +impl = impl.replace("{getters}", getters_cc.strip()) + +with open(sys.argv[1], 'w') as f: + f.write(header) + +with open(sys.argv[2], 'w') as f: + f.write(impl) 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-template.py b/build/generate-template.py new file mode 100644 index 0000000000000..8d5cc04210efe --- /dev/null +++ b/build/generate-template.py @@ -0,0 +1,16 @@ +import json +import sys +from string import Template + +inpath = sys.argv[1] +outpath = sys.argv[2] +argpaths = sys.argv[3:] + +with open(inpath, 'r') as infile, open(outpath, 'w') as outfile: + data = {} + for argpath in argpaths: + with open(argpath, 'r') as argfile: + data.update(json.load(argfile)) + + s = Template(infile.read()).substitute(data) + outfile.write(s) 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/js2c.py b/build/js2c.py new file mode 100644 index 0000000000000..1529d3d0365d4 --- /dev/null +++ b/build/js2c.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys + +def main(): + js2c = sys.argv[1] + root = sys.argv[2] + natives = sys.argv[3] + js_source_files = sys.argv[4:] + + subprocess.check_call( + [js2c, natives] + js_source_files + ['--only-js', "--root", root]) + +if __name__ == '__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 new file mode 100644 index 0000000000000..47f3a9f1f661f --- /dev/null +++ b/build/mac/make_locale_dirs.py @@ -0,0 +1,28 @@ +# usage: make_locale_dirs.py locale_dir [...] +# +# This script is intended to create empty locale directories (.lproj) in a +# 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 +# directories for its helper executable bundles, which do not otherwise +# require any direct Cocoa locale support. + +import os +import errno +import sys + + +def main(args): + for dirname in args: + try: + os.makedirs(dirname) + except OSError as e: + if e.errno == errno.EEXIST: + # It's OK if it already exists + pass + else: + raise + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/build/npm-run.py b/build/npm-run.py new file mode 100644 index 0000000000000..2fcf649f10627 --- /dev/null +++ b/build/npm-run.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys + +SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__)) +cmd = "npm" +if sys.platform == "win32": + cmd += ".cmd" +args = [cmd, "run", + "--prefix", + SOURCE_ROOT + ] + sys.argv[1:] +try: + subprocess.check_output(args, stderr=subprocess.STDOUT) +except subprocess.CalledProcessError as e: + 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 new file mode 100644 index 0000000000000..7790dcece157f --- /dev/null +++ b/build/npm.gni @@ -0,0 +1,45 @@ +template("npm_action") { + assert(defined(invoker.script), + "Need script name to run (must be defined in package.json)") + assert(defined(invoker.args), "Need script arguments") + + action("npm_pre_flight_" + target_name) { + inputs = [ + "//electron/package.json", + "//electron/yarn.lock", + ] + script = "//electron/build/npm-run.py" + + outputs = [ "$target_gen_dir/npm_pre_stamps/" + target_name + ".stamp" ] + + args = [ + "--silent", + "pre-flight", + "--", + "--stamp", + rebase_path(outputs[0]), + ] + } + + action(target_name) { + forward_variables_from(invoker, + [ + "deps", + "public_deps", + "sources", + "inputs", + "outputs", + ]) + if (!defined(deps)) { + deps = [] + } + deps += [ ":npm_pre_flight_" + target_name ] + + script = "//electron/build/npm-run.py" + args = [ + "--silent", + invoker.script, + "--", + ] + invoker.args + } +} diff --git a/build/profile_toolchain.py b/build/profile_toolchain.py new file mode 100755 index 0000000000000..e3da6edd3077e --- /dev/null +++ b/build/profile_toolchain.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +import contextlib +import sys +import os +import optparse +import json + +sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__))) + +import find_depot_tools +from vs_toolchain import \ + SetEnvironmentAndGetRuntimeDllDirs, \ + SetEnvironmentAndGetSDKDir, \ + NormalizePath + +sys.path.append("%s/win_toolchain" % find_depot_tools.add_depot_tools_to_path()) + +from get_toolchain_if_necessary import CalculateHash + + +@contextlib.contextmanager +def cwd(directory): + curdir = os.getcwd() + try: + os.chdir(directory) + yield + finally: + os.chdir(curdir) + + +def calculate_hash(root): + with cwd(root): + return CalculateHash('.', None) + +def windows_installed_software(): + # 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(): + runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs() + win_sdk_dir = SetEnvironmentAndGetSDKDir() + path = NormalizePath(os.environ['GYP_MSVS_OVERRIDE_PATH']) + + # since current windows executable are symbols path dependent, + # profile the current directory too + return { + 'pwd': os.getcwd(), + 'installed_software': windows_installed_software(), + 'sdks': [ + {'name': 'vs', 'path': path, 'hash': calculate_hash(path)}, + { + 'name': 'wsdk', + 'path': win_sdk_dir, + 'hash': calculate_hash(win_sdk_dir), + }, + ], + 'runtime_lib_dirs': runtime_dll_dirs, + } + + +def main(options): + if sys.platform == 'win32': + with open(options.output_json, 'w') as f: + json.dump(windows_profile(), f) + else: + raise OSError("Unsupported OS") + + +if __name__ == '__main__': + parser = optparse.OptionParser() + parser.add_option('--output-json', metavar='FILE', default='profile.json', + help='write information about toolchain to FILE') + opts, args = parser.parse_args() + sys.exit(main(opts)) diff --git a/build/rules.gni b/build/rules.gni new file mode 100644 index 0000000000000..e085af8b914d6 --- /dev/null +++ b/build/rules.gni @@ -0,0 +1,90 @@ +import("//build/config/mac/mac_sdk.gni") + +# Template to compile .xib and .storyboard files. +# (copied from src/build/config/ios/rules.gni) +# +# Arguments +# +# sources: +# list of string, sources to compile +# +# ibtool_flags: +# (optional) list of string, additional flags to pass to the ibtool +template("compile_ib_files") { + action_foreach(target_name) { + forward_variables_from(invoker, + [ + "testonly", + "visibility", + ]) + assert(defined(invoker.sources), + "sources must be specified for $target_name") + assert(defined(invoker.output_extension), + "output_extension must be specified for $target_name") + + ibtool_flags = [] + if (defined(invoker.ibtool_flags)) { + ibtool_flags = invoker.ibtool_flags + } + + _output_extension = invoker.output_extension + + script = "//build/config/apple/compile_ib_files.py" + sources = invoker.sources + outputs = [ + "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension", + ] + args = [ + "--input", + "{{source}}", + "--output", + rebase_path( + "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension", + root_build_dir), + ] + args += ibtool_flags + } +} + +# Template is copied here from Chromium but was removed in +# https://chromium-review.googlesource.com/c/chromium/src/+/1637981 +# Template to compile and package Mac XIB files as bundle data. +# Arguments +# sources: +# 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. +template("mac_xib_bundle_data") { + _target_name = target_name + _compile_target_name = _target_name + "_compile_ibtool" + + compile_ib_files(_compile_target_name) { + forward_variables_from(invoker, [ "testonly" ]) + visibility = [ ":$_target_name" ] + sources = invoker.sources + output_extension = "nib" + ibtool_flags = [ + "--minimum-deployment-target", + mac_deployment_target, + ] + } + + bundle_data(_target_name) { + forward_variables_from(invoker, + [ + "testonly", + "visibility", + ]) + + public_deps = [ ":$_compile_target_name" ] + sources = get_target_outputs(":$_compile_target_name") + + _output_path = "{{bundle_resources_dir}}" + if (defined(invoker.output_path)) { + _output_path = invoker.output_path + } + + outputs = [ "$_output_path/{{source_file_part}}" ] + } +} diff --git a/build/run-in-dir.py b/build/run-in-dir.py new file mode 100644 index 0000000000000..ededac1804b3b --- /dev/null +++ b/build/run-in-dir.py @@ -0,0 +1,11 @@ +import sys +import os +import subprocess + +def main(argv): + os.chdir(argv[1]) + p = subprocess.Popen(argv[2:]) + return p.wait() + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/build/run-node.py b/build/run-node.py new file mode 100644 index 0000000000000..0e0c30d671be2 --- /dev/null +++ b/build/run-node.py @@ -0,0 +1,14 @@ +import os +import subprocess +import sys + + +SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__)) + +def main(): + # Proxy all args to node script + script = os.path.join(SOURCE_ROOT, sys.argv[1]) + subprocess.check_call(['node', script] + [str(x) for x in sys.argv[2:]]) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/build/strip_framework.py b/build/strip_framework.py new file mode 100755 index 0000000000000..73cf424dde488 --- /dev/null +++ b/build/strip_framework.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +import os +import subprocess +import sys + +source = sys.argv[1] +dest = sys.argv[2] + +# Ensure any existing framework is removed +subprocess.check_output(["rm", "-rf", dest]) + +subprocess.check_output(["cp", "-a", source, dest]) + +# Strip headers, we do not need to ship them +subprocess.check_output(["rm", "-r", os.path.join(dest, "Headers")]) +subprocess.check_output( + ["rm", "-r", os.path.join(dest, "Versions", "Current", "Headers")] +) diff --git a/build/templated_file.gni b/build/templated_file.gni new file mode 100644 index 0000000000000..e4d35211d3e6e --- /dev/null +++ b/build/templated_file.gni @@ -0,0 +1,35 @@ +template("templated_file") { + assert(defined(invoker.template), "Need template file to run") + assert(defined(invoker.output), "Need output file to run") + + if (defined(invoker.values)) { + args_path = "$target_gen_dir/$target_name.args" + write_file(args_path, invoker.values, "json") + } + + action(target_name) { + forward_variables_from(invoker, + [ + "deps", + "public_deps", + "inputs", + "outputs", + ]) + inputs = [ invoker.template ] + outputs = [ invoker.output ] + script = "//electron/build/generate-template.py" + args = [ + rebase_path(invoker.template), + rebase_path(invoker.output), + ] + + if (defined(invoker.values)) { + args += rebase_path(args_path) + } + + if (defined(invoker.args_files)) { + args += rebase_path(invoker.args_files) + inputs += invoker.args_files + } + } +} 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/electron_version.tmpl b/build/templates/electron_version.tmpl new file mode 100644 index 0000000000000..2baa4fc66049c --- /dev/null +++ b/build/templates/electron_version.tmpl @@ -0,0 +1,23 @@ +// Copyright (c) 2019 Slack Technologies, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ELECTRON_ELECTRON_VERSION_H +#define ELECTRON_ELECTRON_VERSION_H + +#define ELECTRON_MAJOR_VERSION $major +#define ELECTRON_MINOR_VERSION $minor +#define ELECTRON_PATCH_VERSION $patch +#if $has_prerelease +#define ELECTRON_PRE_RELEASE_VERSION -$prerelease +#endif + +#ifndef ELECTRON_PRE_RELEASE_VERSION +#define ELECTRON_VERSION_STRING "$major.$minor.$patch" +#else +#define ELECTRON_VERSION_STRING "$major.$minor.$patch-$prerelease" +#endif + +#define ELECTRON_VERSION "v" ELECTRON_VERSION_STRING + +#endif // ELECTRON_ELECTRON_VERSION_H 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/tsc.gni b/build/tsc.gni new file mode 100644 index 0000000000000..136c9fcd3b70d --- /dev/null +++ b/build/tsc.gni @@ -0,0 +1,46 @@ +import("npm.gni") + +template("typescript_build") { + assert(defined(invoker.tsconfig), "Need tsconfig name to run") + assert(defined(invoker.sources), "Need tsc sources to run") + assert(defined(invoker.output_dir_name), + "Need output_dir_name to run, should be 'lib' or other top level dir") + assert(defined(invoker.output_gen_dir), + "Need output_gen_dir to run, should be relative to the root gen dir") + + npm_action(target_name) { + forward_variables_from(invoker, + [ + "deps", + "public_deps", + "outputs", + ]) + script = "tsc" + + sources = invoker.sources + inputs = [ + invoker.tsconfig, + "//electron/tsconfig.json", + "//electron/yarn.lock", + "//electron/typings/internal-ambient.d.ts", + "//electron/typings/internal-electron.d.ts", + ] + + base_out_path = invoker.output_gen_dir + "/electron/" + args = [ + "-p", + rebase_path(invoker.tsconfig), + "--outDir", + rebase_path("$base_out_path" + invoker.output_dir_name), + ] + + outputs = [] + + foreach(invoker_source, invoker.sources) { + # The output of TSC is all inputs but with JS instead of TS as the + # extension + outputs += [ "$base_out_path" + get_path_info(invoker_source, "dir") + + "/" + get_path_info(invoker_source, "name") + ".js" ] + } + } +} diff --git a/build/webpack/webpack.config.base.js b/build/webpack/webpack.config.base.js new file mode 100644 index 0000000000000..6cea23eba8afa --- /dev/null +++ b/build/webpack/webpack.config.base.js @@ -0,0 +1,195 @@ +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)); + console.info(JSON.stringify(filePaths)); + }); + }); + } +} + +module.exports = ({ + alwaysHasNode, + loadElectronFromAlternateTarget, + targetDeletesNodeGlobals, + target, + wrapInitWithProfilingTimeout, + wrapInitWithTryCatch +}) => { + let entry = path.resolve(electronRoot, 'lib', target, 'init.ts'); + if (!fs.existsSync(entry)) { + entry = path.resolve(electronRoot, 'lib', target, 'init.js'); + } + + const electronAPIFile = path.resolve( + electronRoot, + 'lib', + loadElectronFromAlternateTarget || target, + 'api', + 'exports', + 'electron.ts' + ); + + return (env = {}, argv = {}) => { + const onlyPrintingGraph = !!env.PRINT_WEBPACK_GRAPH; + const outputFilename = argv['output-filename'] || `${target}.bundle.js`; + + const defines = { + BUILDFLAG: onlyPrintingGraph ? '(a => a)' : '' + }; + + if (env.buildflags) { + const flagFile = fs.readFileSync(env.buildflags, 'utf8'); + for (const line of flagFile.split(/(\r\n|\r|\n)/g)) { + const flagMatch = line.match(/#define BUILDFLAG_INTERNAL_(.+?)\(\) \(([01])\)/); + if (flagMatch) { + const [, flagName, flagValue] = flagMatch; + defines[flagName] = JSON.stringify(Boolean(parseInt(flagValue, 10))); + } + } + } + + const ignoredModules = []; + + const plugins = []; + + if (onlyPrintingGraph) { + plugins.push(new AccessDependenciesPlugin()); + } + + if (targetDeletesNodeGlobals) { + 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.DefinePlugin(defines)); + + if (wrapInitWithProfilingTimeout) { + 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: ` +} catch (err) { + console.error('Electron ${outputFilename} script failed to run'); + console.error(err); +}` + }) + ); + } + + return { + mode: 'development', + devtool: false, + entry, + target: alwaysHasNode ? 'node' : 'web', + output: { + filename: outputFilename + }, + resolve: { + alias: { + '@electron/internal': path.resolve(electronRoot, 'lib'), + electron$: electronAPIFile, + 'electron/main$': electronAPIFile, + 'electron/renderer$': electronAPIFile, + 'electron/common$': electronAPIFile, + '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'], + 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, + // Private field '{0}' must be declared in an enclosing class. + 1111 + ] + } + } + ] + }, + node: { + __dirname: false, + __filename: false + }, + optimization: { + minimize: env.mode === 'production', + minimizer: [ + new TerserPlugin({ + terserOptions: { + keep_classnames: true, + keep_fnames: true + } + }) + ] + }, + plugins + }; + }; +}; diff --git a/build/webpack/webpack.config.browser.js b/build/webpack/webpack.config.browser.js new file mode 100644 index 0000000000000..c01b97fcf8e36 --- /dev/null +++ b/build/webpack/webpack.config.browser.js @@ -0,0 +1,4 @@ +module.exports = require('./webpack.config.base')({ + target: 'browser', + alwaysHasNode: true +}); diff --git a/build/webpack/webpack.config.isolated_renderer.js b/build/webpack/webpack.config.isolated_renderer.js new file mode 100644 index 0000000000000..627498c255e2e --- /dev/null +++ b/build/webpack/webpack.config.isolated_renderer.js @@ -0,0 +1,5 @@ +module.exports = require('./webpack.config.base')({ + target: 'isolated_renderer', + alwaysHasNode: false, + wrapInitWithTryCatch: true +}); 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.renderer.js b/build/webpack/webpack.config.renderer.js new file mode 100644 index 0000000000000..ada961852e157 --- /dev/null +++ b/build/webpack/webpack.config.renderer.js @@ -0,0 +1,7 @@ +module.exports = require('./webpack.config.base')({ + target: 'renderer', + alwaysHasNode: true, + targetDeletesNodeGlobals: true, + wrapInitWithProfilingTimeout: true, + wrapInitWithTryCatch: true +}); diff --git a/build/webpack/webpack.config.sandboxed_renderer.js b/build/webpack/webpack.config.sandboxed_renderer.js new file mode 100644 index 0000000000000..67e6a06640fe9 --- /dev/null +++ b/build/webpack/webpack.config.sandboxed_renderer.js @@ -0,0 +1,6 @@ +module.exports = require('./webpack.config.base')({ + target: 'sandboxed_renderer', + 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.config.worker.js b/build/webpack/webpack.config.worker.js new file mode 100644 index 0000000000000..acf5d1d6b021d --- /dev/null +++ b/build/webpack/webpack.config.worker.js @@ -0,0 +1,7 @@ +module.exports = require('./webpack.config.base')({ + target: 'worker', + loadElectronFromAlternateTarget: 'renderer', + alwaysHasNode: true, + targetDeletesNodeGlobals: true, + wrapInitWithTryCatch: true +}); diff --git a/build/webpack/webpack.gni b/build/webpack/webpack.gni new file mode 100644 index 0000000000000..8672bfca4cd79 --- /dev/null +++ b/build/webpack/webpack.gni @@ -0,0 +1,46 @@ +import("../npm.gni") + +template("webpack_build") { + assert(defined(invoker.config_file), "Need webpack config file to run") + assert(defined(invoker.out_file), "Need output file to run") + assert(defined(invoker.inputs), "Need webpack inputs to run") + + npm_action(target_name) { + forward_variables_from(invoker, + [ + "deps", + "public_deps", + ]) + script = "webpack" + + inputs = [ + invoker.config_file, + "//electron/build/webpack/webpack.config.base.js", + "//electron/tsconfig.json", + "//electron/yarn.lock", + "//electron/typings/internal-ambient.d.ts", + "//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"), + "--env", + "mode=" + mode, + ] + 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 new file mode 100644 index 0000000000000..ff9b834054886 --- /dev/null +++ b/build/zip.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys +import zipfile + +EXTENSIONS_TO_SKIP = [ + '.pdb', + '.mojom.js', + '.mojom-lite.js', + '.info', + '.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 = [ + # Skip because it is an output of //ui/gl that we don't need. + 'angledata', + # Skip because these are outputs that we don't need. + './libVkICD_mock_', + # Skip because these are outputs that we don't need. + './VkICD_mock_', + # Skip because its an output of create_bundle from + # //build/config/mac/rules.gni that we don't need + 'Electron.dSYM', + # Refs https://chromium-review.googlesource.com/c/angle/angle/+/2425197. + # Remove this when Angle themselves remove the file: + # https://issuetracker.google.com/issues/168736059 + 'gen/angle/angle_commit.h', + # //chrome/browser:resources depends on this via + # //chrome/browser/resources/ssl/ssl_error_assistant, but we don't need to + # ship it. + 'pyproto', + # 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): + # Skip specific paths and extensions as well as the following special case: + # snapshot_blob.bin is a dependency of mksnapshot.zip because + # v8_context_generator needs it, but this file does not get generated for arm + # and arm 64 binaries of mksnapshot since they are built on x64 hardware. + # Consumers of arm and arm64 mksnapshot can generate snapshot_blob.bin + # themselves by running mksnapshot. + should_skip = ( + any(dep.startswith(path) for path in PATHS_TO_SKIP) or + any(dep.endswith(ext) for ext in EXTENSIONS_TO_SKIP) or + ( + "arm" in target_cpu + and dist_zip == "mksnapshot.zip" + and dep == "snapshot_blob.bin" + ) + ) + if should_skip and os.environ.get('ELECTRON_DEBUG_ZIP_SKIP') == '1': + print("Skipping {}".format(dep)) + return should_skip + +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 main(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: + for dep in f.readlines(): + 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: + with zipfile.ZipFile( + dist_zip, 'w', zipfile.ZIP_DEFLATED, allowZip64=True + ) as z: + for dep in dist_files: + if os.path.isdir(dep): + for root, _, files in os.walk(dep): + for filename in files: + z.write(os.path.join(root, filename)) + else: + basename = os.path.basename(dep) + dirname = os.path.dirname(dep) + arcname = ( + os.path.join(dirname, '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, + name_to_write, + ) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) 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 new file mode 100644 index 0000000000000..ef00ad27f6085 --- /dev/null +++ b/buildflags/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright (c) 2018 GitHub, Inc. +# Use of this source code is governed by the MIT license that can be +# found in the LICENSE file. + +import("//build/buildflag_header.gni") +import("//electron/buildflags/buildflags.gni") + +buildflag_header("buildflags") { + header = "buildflags.h" + + flags = [ + "ENABLE_PDF_VIEWER=$enable_pdf_viewer", + "ENABLE_ELECTRON_EXTENSIONS=$enable_electron_extensions", + "ENABLE_BUILTIN_SPELLCHECKER=$enable_builtin_spellchecker", + "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 new file mode 100644 index 0000000000000..801732cb2595b --- /dev/null +++ b/buildflags/buildflags.gni @@ -0,0 +1,30 @@ +# Copyright (c) 2018 GitHub, Inc. +# Use of this source code is governed by the MIT license that can be +# found in the LICENSE file. + +declare_args() { + enable_pdf_viewer = true + + # Provide a fake location provider for mocking + # the geolocation responses. Disable it if you + # need to test with chromium's location provider. + # Should not be enabled for release build. + enable_fake_location_provider = !is_official_build + + # Enable Chrome extensions support. + enable_electron_extensions = true + + # Enable Spellchecker support + enable_builtin_spellchecker = true + + # 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 new file mode 100644 index 0000000000000..1da801d3a27e9 --- /dev/null +++ b/chromium_src/BUILD.gn @@ -0,0 +1,531 @@ +# Copyright (c) 2018 GitHub, Inc. +# 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") +import("//printing/buildflags/buildflags.gni") +import("//third_party/widevine/cdm/widevine.gni") + +# Builds some of the chrome sources that Electron depends on. +static_library("chrome") { + visibility = [ "//electron:electron_lib" ] + sources = [ + "//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/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/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/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/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_posix) { + sources += [ "//chrome/browser/process_singleton_posix.cc" ] + } + + if (is_win) { + sources += [ + "//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", + "//content/public/browser", + "//services/strings", + ] + + deps = [ + "//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", + "//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", + ] + 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) { + sources += [ + "//chrome/browser/win/icon_reader_service.cc", + "//chrome/browser/win/icon_reader_service.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", + ] + } + + if (is_mac) { + sources += [ + "//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", + ] + deps += [ ":system_media_capture_permissions_mac_conflict" ] + } + + if (enable_widevine) { + sources += [ + "//chrome/renderer/media/chrome_key_systems.cc", + "//chrome/renderer/media/chrome_key_systems.h", + "//chrome/renderer/media/chrome_key_systems_provider.cc", + "//chrome/renderer/media/chrome_key_systems_provider.h", + ] + deps += [ "//components/cdm/renderer" ] + } + + 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/printer_query.cc", + "//chrome/browser/printing/printer_query.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", + "//components/printing/renderer", + "//components/services/print_compositor", + "//components/services/print_compositor/public/cpp", + "//components/services/print_compositor/public/mojom", + "//printing/backend", + ] + + deps += [ + "//components/printing/common", + "//printing", + ] + + if (is_win) { + sources += [ + "//chrome/browser/printing/pdf_to_emf_converter.cc", + "//chrome/browser/printing/pdf_to_emf_converter.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_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/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/pdf_extension_util.cc", + "//chrome/browser/pdf/pdf_extension_util.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) { + sources += [ "//chrome/browser/hang_monitor/hang_crash_dump.h" ] + if (is_mac) { + sources += [ "//chrome/browser/hang_monitor/hang_crash_dump_mac.cc" ] + } else if (is_win) { + sources += [ "//chrome/browser/hang_monitor/hang_crash_dump_win.cc" ] + } else { + sources += [ "//chrome/browser/hang_monitor/hang_crash_dump.cc" ] + } + } +} + +# 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 +source_set("chrome_spellchecker") { + sources = [] + deps = [] + libs = [] + public_deps = [] + + 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_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", + "//chrome/browser/spellchecker/spell_check_panel_host_impl.h", + ] + } + + if (use_browser_spellchecker) { + sources += [ + "//chrome/browser/spellchecker/spelling_request.cc", + "//chrome/browser/spellchecker/spelling_request.h", + ] + } + + deps += [ + "//base:base_static", + "//components/language/core/browser", + "//components/spellcheck:buildflags", + "//components/sync", + ] + + public_deps += [ "//chrome/common:constants" ] + } + + public_deps += [ + "//components/spellcheck/browser", + "//components/spellcheck/common", + "//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/browser_process.cc b/chromium_src/chrome/browser/browser_process.cc deleted file mode 100644 index 2c07333210ea9..0000000000000 --- a/chromium_src/chrome/browser/browser_process.cc +++ /dev/null @@ -1,28 +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/browser_process.h" - -#include "chrome/browser/printing/print_job_manager.h" -#include "ui/base/l10n/l10n_util.h" - -BrowserProcess* g_browser_process = NULL; - -BrowserProcess::BrowserProcess() { - g_browser_process = this; - - print_job_manager_.reset(new printing::PrintJobManager); -} - -BrowserProcess::~BrowserProcess() { - g_browser_process = NULL; -} - -std::string BrowserProcess::GetApplicationLocale() { - return l10n_util::GetApplicationLocale(""); -} - -printing::PrintJobManager* BrowserProcess::print_job_manager() { - return print_job_manager_.get(); -} diff --git a/chromium_src/chrome/browser/browser_process.h b/chromium_src/chrome/browser/browser_process.h deleted file mode 100644 index 1459ca31a60a0..0000000000000 --- a/chromium_src/chrome/browser/browser_process.h +++ /dev/null @@ -1,41 +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. - -// This interface is for managing the global services of the application. Each -// service is lazily created when requested the first time. The service getters -// will return NULL if the service is not available, so callers must check for -// this condition. - -#ifndef CHROME_BROWSER_BROWSER_PROCESS_H_ -#define CHROME_BROWSER_BROWSER_PROCESS_H_ - -#include -#include - -#include "base/macros.h" - -namespace printing { -class PrintJobManager; -} - -// NOT THREAD SAFE, call only from the main thread. -// These functions shouldn't return NULL unless otherwise noted. -class BrowserProcess { - public: - BrowserProcess(); - ~BrowserProcess(); - - std::string GetApplicationLocale(); - - printing::PrintJobManager* print_job_manager(); - - private: - std::unique_ptr print_job_manager_; - - DISALLOW_COPY_AND_ASSIGN(BrowserProcess); -}; - -extern BrowserProcess* g_browser_process; - -#endif // CHROME_BROWSER_BROWSER_PROCESS_H_ 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 2274c09e34157..0000000000000 --- a/chromium_src/chrome/browser/certificate_manager_model.cc +++ /dev/null @@ -1,173 +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 "content/public/browser/browser_context.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/crypto_module.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, - const base::Callback& 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. - g_nss_cert_database = new net::NSSCertDatabase( - crypto::ScopedPK11Slot( - crypto::GetPersistentNSSKeySlot()) /* public slot */, - crypto::ScopedPK11Slot( - crypto::GetPersistentNSSKeySlot()) /* 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, - const CreationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&CertificateManagerModel::GetCertDBOnIOThread, - browser_context->GetResourceContext(), - 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() { -} - -int CertificateManagerModel::ImportFromPKCS12(net::CryptoModule* module, - const std::string& data, - const base::string16& password, - bool is_extractable, - net::CertificateList* imported_certs) { - return cert_db_->ImportFromPKCS12(module, data, password, - is_extractable, imported_certs); -} - -int CertificateManagerModel::ImportUserCert(const std::string& data) { - return cert_db_->ImportUserCert(data); -} - -bool CertificateManagerModel::ImportCACerts( - const net::CertificateList& 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::CertificateList& certificates, - net::NSSCertDatabase::TrustBits trust_bits, - net::NSSCertDatabase::ImportCertFailureList* not_imported) { - return cert_db_->ImportServerCert(certificates, trust_bits, - not_imported); -} - -bool CertificateManagerModel::SetCertTrust( - const net::X509Certificate* cert, - net::CertType type, - net::NSSCertDatabase::TrustBits trust_bits) { - return cert_db_->SetCertTrust(cert, type, trust_bits); -} - -bool CertificateManagerModel::Delete(net::X509Certificate* cert) { - return cert_db_->DeleteCertAndKey(cert); -} - -// static -void CertificateManagerModel::DidGetCertDBOnUIThread( - net::NSSCertDatabase* cert_db, - bool is_user_db_available, - const CreationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - std::unique_ptr model(new CertificateManagerModel( - cert_db, is_user_db_available)); - callback.Run(std::move(model)); -} - -// static -void CertificateManagerModel::DidGetCertDBOnIOThread( - const CreationCallback& callback, - net::NSSCertDatabase* cert_db) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - bool is_user_db_available = !!cert_db->GetPublicSlot(); - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&CertificateManagerModel::DidGetCertDBOnUIThread, - cert_db, - is_user_db_available, - callback)); -} - -// static -void CertificateManagerModel::GetCertDBOnIOThread( - content::ResourceContext* context, - const CreationCallback& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext( - context, - base::Bind(&CertificateManagerModel::DidGetCertDBOnIOThread, - callback)); - if (cert_db) - DidGetCertDBOnIOThread(callback, 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 7646da5b9b4d3..0000000000000 --- a/chromium_src/chrome/browser/certificate_manager_model.h +++ /dev/null @@ -1,119 +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: - typedef base::Callback)> - CreationCallback; - - // 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, - const 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(net::CryptoModule* module, - const std::string& data, - const base::string16& password, - bool is_extractable, - net::CertificateList* 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::CertificateList& 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::CertificateList& 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(const net::X509Certificate* 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(net::X509Certificate* 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, - const CreationCallback& callback); - static void DidGetCertDBOnIOThread( - const CreationCallback& callback, - net::NSSCertDatabase* cert_db); - static void GetCertDBOnIOThread(content::ResourceContext* context, - const 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/chrome_notification_types.h b/chromium_src/chrome/browser/chrome_notification_types.h deleted file mode 100644 index 05df960c5ea49..0000000000000 --- a/chromium_src/chrome/browser/chrome_notification_types.h +++ /dev/null @@ -1,949 +0,0 @@ -// Copyright 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_CHROME_NOTIFICATION_TYPES_H_ -#define CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_ - -#include "build/build_config.h" -#include "content/public/browser/notification_types.h" - -namespace chrome { - -enum NotificationType { - NOTIFICATION_CHROME_START = content::NOTIFICATION_CONTENT_END, - - // Browser-window ---------------------------------------------------------- - - // This message is sent after a window has been opened. The source is a - // Source containing the affected Browser. No details are - // expected. - NOTIFICATION_BROWSER_OPENED = NOTIFICATION_CHROME_START, - - // This message is sent soon after BROWSER_OPENED, and indicates that - // the Browser's |window_| is now non-NULL. The source is a Source - // containing the affected Browser. No details are expected. - NOTIFICATION_BROWSER_WINDOW_READY, - - // This message is sent when a browser is closing. The source is a - // Source containing the affected Browser. No details are expected. - // This is sent prior to BROWSER_CLOSED, and may be sent more than once for a - // particular browser. - NOTIFICATION_BROWSER_CLOSING, - - // This message is sent after a window has been closed. The source is a - // Source containing the affected Browser. No details are expected. - NOTIFICATION_BROWSER_CLOSED, - - // This message is sent when closing a browser has been cancelled, either by - // the user cancelling a beforeunload dialog, or IsClosingPermitted() - // disallowing closing. This notification implies that no BROWSER_CLOSING or - // BROWSER_CLOSED notification will be sent. - // The source is a Source containing the affected browser. No details - // are expected. - NOTIFICATION_BROWSER_CLOSE_CANCELLED, - - // Indicates that a top window has been closed. The source is the HWND - // that was closed, no details are expected. - NOTIFICATION_WINDOW_CLOSED, - -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) - // On Linux maximize can be an asynchronous operation. This notification - // indicates that the window has been maximized. The source is - // a Source containing the BrowserWindow that was maximized. - // No details are expected. - NOTIFICATION_BROWSER_WINDOW_MAXIMIZED, -#endif - - // Sent when the language (English, French...) for a page has been detected. - // The details Details contain the ISO 639-1 language code and - // the source is Source. - NOTIFICATION_TAB_LANGUAGE_DETERMINED, - - // Sent when a page has been translated. The source is the tab for that page - // (Source) and the details are the language the page was - // originally in and the language it was translated to - // (std::pair). - NOTIFICATION_PAGE_TRANSLATED, - - // The user has changed the browser theme. The source is a - // Source. There are no details. - NOTIFICATION_BROWSER_THEME_CHANGED, - -#if defined(USE_AURA) - // The user has changed the fling curve configuration. - // Source. There are no details. - NOTIFICATION_BROWSER_FLING_CURVE_PARAMETERS_CHANGED, -#endif // defined(USE_AURA) - - // Sent when the renderer returns focus to the browser, as part of focus - // traversal. The source is the browser, there are no details. - NOTIFICATION_FOCUS_RETURNED_TO_BROWSER, - - // A new tab is created from an existing tab to serve as a target of a - // navigation that is about to happen. The source will be a Source - // corresponding to the profile in which the new tab will live. Details in - // the form of a RetargetingDetails object are provided. - NOTIFICATION_RETARGETING, - - // Application-wide ---------------------------------------------------------- - - // This message is sent when the application is terminating (the last - // browser window has shutdown as part of an explicit user-initiated exit, - // or the user closed the last browser window on Windows/Linux and there are - // no BackgroundContents keeping the browser running). No source or details - // are passed. - NOTIFICATION_APP_TERMINATING, - -#if defined(OS_MACOSX) - // This notification is sent when the app has no key window, such as when - // all windows are closed but the app is still active. No source or details - // are provided. - NOTIFICATION_NO_KEY_WINDOW, -#endif - - // This is sent when the user has chosen to exit the app, but before any - // browsers have closed. This is sent if the user chooses to exit (via exit - // menu item or keyboard shortcut) or to restart the process (such as in flags - // page), not if Chrome exits by some other means (such as the user closing - // the last window). No source or details are passed. - // - // Note that receiving this notification does not necessarily mean the process - // will exit because the shutdown process can be cancelled by an unload - // handler. Use APP_TERMINATING for such needs. - NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST, - - // Application-modal dialogs ----------------------------------------------- - - // Sent after an application-modal dialog has been shown. The source - // is the dialog. - NOTIFICATION_APP_MODAL_DIALOG_SHOWN, - - // This message is sent when a new InfoBar has been added to an - // InfoBarService. The source is a Source with a pointer to - // the InfoBarService the InfoBar was added to. The details is a - // Details. - NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, - - // This message is sent when an InfoBar is about to be removed from an - // InfoBarService. The source is a Source with a pointer to - // the InfoBarService the InfoBar was removed from. The details is a - // Details. - NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, - - // This message is sent when an InfoBar is replacing another infobar in an - // InfoBarService. The source is a Source with a pointer to - // the InfoBarService the InfoBar was removed from. The details is a - // Details. - NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED, - - // Used to fire notifications about how long various events took to - // complete. E.g., this is used to get more fine grained timings from the - // new tab page. The source is a WebContents and the details is a - // MetricEventDurationDetails. - NOTIFICATION_METRIC_EVENT_DURATION, - - // This notification is sent when extensions::TabHelper::SetExtensionApp is - // invoked. The source is the extensions::TabHelper SetExtensionApp was - // invoked on. - NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, - - // Tabs -------------------------------------------------------------------- - - // Sent when a tab is added to a WebContentsDelegate. The source is the - // WebContentsDelegate and the details is the added WebContents. - NOTIFICATION_TAB_ADDED, - - // This notification is sent after a tab has been appended to the tab_strip. - // The source is a Source of the tab being added. There - // are no details. - NOTIFICATION_TAB_PARENTED, - - // This message is sent before a tab has been closed. The source is a - // Source with a pointer to the controller for the - // closed tab. No details are expected. - // - // See also content::NOTIFICATION_WEB_CONTENTS_DESTROYED, which is sent when - // the WebContents containing the NavigationController is destroyed. - NOTIFICATION_TAB_CLOSING, - - // Stuff inside the tabs --------------------------------------------------- - - // This notification is sent when the result of a find-in-page search is - // available with the browser process. The source is a Source. - // Details encompass a FindNotificationDetail object that tells whether the - // match was found or not found. - NOTIFICATION_FIND_RESULT_AVAILABLE, - - // BackgroundContents ------------------------------------------------------ - - // A new background contents was opened by script. The source is the parent - // profile and the details are BackgroundContentsOpenedDetails. - NOTIFICATION_BACKGROUND_CONTENTS_OPENED, - - // The background contents navigated to a new location. The source is the - // parent Profile, and the details are the BackgroundContents that was - // navigated. - NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, - - // The background contents were closed by someone invoking window.close() - // or the parent application was uninstalled. - // The source is the parent profile, and the details are the - // BackgroundContents. - NOTIFICATION_BACKGROUND_CONTENTS_CLOSED, - - // The background contents is being deleted. The source is the - // parent Profile, and the details are the BackgroundContents being deleted. - NOTIFICATION_BACKGROUND_CONTENTS_DELETED, - - // The background contents has crashed. The source is the parent Profile, - // and the details are the BackgroundContents. - NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED, - - // The background contents associated with a hosted app has changed (either - // a new background contents has been created, or an existing background - // contents has closed). The source is the parent Profile, and the details - // are the BackgroundContentsService. - NOTIFICATION_BACKGROUND_CONTENTS_SERVICE_CHANGED, - - // Chrome has entered/exited background mode. The source is the - // BackgroundModeManager and the details are a boolean value which is set to - // true if Chrome is now in background mode. - NOTIFICATION_BACKGROUND_MODE_CHANGED, - - // This is sent when a login prompt is shown. The source is the - // Source for the tab in which the prompt is shown. - // Details are a LoginNotificationDetails which provide the LoginHandler - // that should be given authentication. - NOTIFICATION_AUTH_NEEDED, - - // This is sent when authentication credentials have been supplied (either - // by the user or by an automation service), but before we've actually - // received another response from the server. The source is the - // Source for the tab in which the prompt was shown. - // Details are an AuthSuppliedLoginNotificationDetails which provide the - // LoginHandler that should be given authentication as well as the supplied - // username and password. - NOTIFICATION_AUTH_SUPPLIED, - - // This is sent when an authentication request has been dismissed without - // supplying credentials (either by the user or by an automation service). - // The source is the Source for the tab in which the - // prompt was shown. Details are a LoginNotificationDetails which provide - // the LoginHandler that should be cancelled. - NOTIFICATION_AUTH_CANCELLED, - - // History ----------------------------------------------------------------- - - // Sent when a history service has finished loading. The source is the - // profile that the history service belongs to, and the details is the - // HistoryService. - NOTIFICATION_HISTORY_LOADED, - - // Sent when a URL has been added or modified. This is used by the in-memory - // URL database and the InMemoryURLIndex (both used by autocomplete) to track - // changes to the main history system. - // - // The source is the profile owning the history service that changed, and - // the details is history::URLsModifiedDetails that lists the modified or - // added URLs. - NOTIFICATION_HISTORY_URLS_MODIFIED, - - // Sent when the user visits a URL. - // - // The source is the profile owning the history service that changed, and - // the details is history::URLVisitedDetails. - NOTIFICATION_HISTORY_URL_VISITED, - - // Sent when one or more URLs are deleted. - // - // The source is the profile owning the history service that changed, and - // the details is history::URLsDeletedDetails that lists the deleted URLs. - NOTIFICATION_HISTORY_URLS_DELETED, - - // Sent when a keyword search term is updated. The source is the Profile and - // the details is history::KeywordSearchUpdatedDetails. - NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED, - - // Sent when a keyword search term is deleted. The source is the Profile and - // the details is history::KeywordSearchDeletedDetails. - NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED, - - // Sent by history when the favicon of a URL changes. The source is the - // profile, and the details is FaviconChangedDetails (see - // chrome/browser/favicon/favicon_changed_details.h). - NOTIFICATION_FAVICON_CHANGED, - - // Sent by FaviconTabHelper when a tab's favicon has been successfully - // updated. The details are a bool indicating whether the - // NavigationEntry's favicon URL has changed since the previous - // NOTIFICATION_FAVICON_UPDATED notification. The details are true if - // there was no previous NOTIFICATION_FAVICON_UPDATED notification for the - // current NavigationEntry. - NOTIFICATION_FAVICON_UPDATED, - - // Profiles ----------------------------------------------------------------- - - // Sent after a Profile has been created. This notification is sent both for - // normal and OTR profiles. - // The details are none and the source is the new profile. - NOTIFICATION_PROFILE_CREATED, - - // Sent after a Profile has been added to ProfileManager. - // The details are none and the source is the new profile. - NOTIFICATION_PROFILE_ADDED, - - // Sent before a Profile is destroyed. This notification is sent both for - // normal and OTR profiles. - // The details are none and the source is a Profile*. - NOTIFICATION_PROFILE_DESTROYED, - - // Sent after the URLRequestContextGetter for a Profile has been initialized. - // The details are none and the source is a Profile*. - NOTIFICATION_PROFILE_URL_REQUEST_CONTEXT_GETTER_INITIALIZED, - - // TopSites ---------------------------------------------------------------- - - // Sent by TopSites when it finishes loading. The source is the profile the - // details the TopSites. - NOTIFICATION_TOP_SITES_LOADED, - - // Sent by TopSites when the either one of the most visited urls changed, or - // one of the images changes. The source is the TopSites, the details not - // used. - NOTIFICATION_TOP_SITES_CHANGED, - - // Task Manager ------------------------------------------------------------ - - // Sent when a renderer process is notified of new v8 heap statistics. The - // source is the ID of the renderer process, and the details are a - // V8HeapStatsDetails object. - NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED, - - // Non-history storage services -------------------------------------------- - - // Sent when a TemplateURL is removed from the model. The source is the - // Profile, and the details the id of the TemplateURL being removed. - NOTIFICATION_TEMPLATE_URL_REMOVED, - - // Sent when the prefs relating to the default search engine have changed due - // to policy. Source and details are unused. - NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED, - - // The state of a web resource has been changed. A resource may have been - // added, removed, or altered. Source is WebResourceService, and the - // details are NoDetails. - NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED, - - // A safe browsing database update completed. Source is the - // SafeBrowsingService and the details are a bool indicating whether the - // update was successful. - NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE, - - // Autocomplete ------------------------------------------------------------ - - // Sent by the autocomplete controller when done. The source is the - // AutocompleteController, the details not used. - NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY, - - // This is sent when an item of the Omnibox popup is selected. The source - // is the profile. - NOTIFICATION_OMNIBOX_OPENED_URL, - - // This is sent from Instant when the omnibox focus state changes. - NOTIFICATION_OMNIBOX_FOCUS_CHANGED, - - // Sent when the Google URL for a profile has been updated. Some services - // cache this value and need to update themselves when it changes. See - // google_util::GetGoogleURLAndUpdateIfNecessary(). The source is the - // Profile, the details a GoogleURLTracker::UpdatedDetails containing the old - // and new URLs. - // - // Note that because incognito mode requests for the GoogleURLTracker are - // redirected to the non-incognito profile's copy, this notification will only - // ever fire on non-incognito profiles; thus listeners should use - // GetOriginalProfile() when constructing a Source to filter against. - NOTIFICATION_GOOGLE_URL_UPDATED, - - // Printing ---------------------------------------------------------------- - - // Notification from PrintJob that an event occurred. It can be that a page - // finished printing or that the print job failed. Details is - // PrintJob::EventDetails. Source is a PrintJob. - NOTIFICATION_PRINT_JOB_EVENT, - - // Sent when a PrintJob has been released. - // Source is the WebContents that holds the print job. - NOTIFICATION_PRINT_JOB_RELEASED, - - // Shutdown ---------------------------------------------------------------- - - // Sent when WM_ENDSESSION has been received, after the browsers have been - // closed but before browser process has been shutdown. The source/details - // are all source and no details. - NOTIFICATION_SESSION_END, - - // User Scripts ------------------------------------------------------------ - - // Sent when there are new user scripts available. The details are a - // pointer to SharedMemory containing the new scripts. - NOTIFICATION_USER_SCRIPTS_UPDATED, - - // Extensions -------------------------------------------------------------- - - // Sent when a CrxInstaller finishes. Source is the CrxInstaller that - // finished. The details are the extension which was installed. - NOTIFICATION_CRX_INSTALLER_DONE, - - // Sent when the known installed extensions have all been loaded. In - // testing scenarios this can happen multiple times if extensions are - // unloaded and reloaded. The source is a Profile. - NOTIFICATION_EXTENSIONS_READY, - - // Sent when an extension icon being displayed in the location bar is updated. - // The source is the Profile and the details are the WebContents for - // the tab. - NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED, - - // DEPRECATED: Use ExtensionRegistry::AddObserver instead. - // - // Sent when a new extension is loaded. The details are an Extension, and - // the source is a Profile. - NOTIFICATION_EXTENSION_LOADED_DEPRECATED, - - // An error occurred while attempting to load an extension. The details are a - // string with details about why the load failed. - NOTIFICATION_EXTENSION_LOAD_ERROR, - - // Sent when an extension is enabled. Under most circumstances, listeners - // will want to use NOTIFICATION_EXTENSION_LOADED_DEPRECATED. This - // notification is only - // fired when the "Enable" button is hit in the extensions tab. The details - // are an Extension, and the source is a Profile. - NOTIFICATION_EXTENSION_ENABLED, - - // Sent when attempting to load a new extension, but they are disabled. The - // details are an Extension*, and the source is a Profile*. - NOTIFICATION_EXTENSION_UPDATE_DISABLED, - - // Sent when an extension's permissions change. The details are an - // UpdatedExtensionPermissionsInfo, and the source is a Profile. - NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, - - // Sent when new extensions are installed, or existing extensions are updated. - // The details are an InstalledExtensionInfo, and the source is a Profile. - NOTIFICATION_EXTENSION_INSTALLED, - - // An error occurred during extension install. The details are a string with - // details about why the install failed. - NOTIFICATION_EXTENSION_INSTALL_ERROR, - - // Sent when an extension has been uninstalled. The details are an Extension, - // and the source is a Profile. - NOTIFICATION_EXTENSION_UNINSTALLED, - - // Sent when an extension uninstall is not allowed because the extension is - // not user manageable. The details are an Extension, and the source is a - // Profile. - NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED, - - // DEPRECATED: Use ExtensionRegistry::AddObserver instead. - // - // Sent when an extension is unloaded. This happens when an extension is - // uninstalled or disabled. The details are an UnloadedExtensionInfo, and - // the source is a Profile. - // - // Note that when this notification is sent, ExtensionService has already - // removed the extension from its internal state. - NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, - - // Sent when an Extension object is removed from ExtensionService. This - // can happen when an extension is uninstalled, upgraded, or blacklisted, - // including all cases when the Extension is deleted. The details are an - // Extension, and the source is a Profile. - NOTIFICATION_EXTENSION_REMOVED, - - // Sent after a new ExtensionHost is created. The details are - // an ExtensionHost* and the source is a Profile*. - NOTIFICATION_EXTENSION_HOST_CREATED, - - // Sent before an ExtensionHost is destroyed. The details are - // an ExtensionHost* and the source is a Profile*. - NOTIFICATION_EXTENSION_HOST_DESTROYED, - - // Sent by an ExtensionHost when it has finished its initial page load, - // including any external resources. - // The details are an ExtensionHost* and the source is a Profile*. - NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, - - // Sent by an ExtensionHost when its render view requests closing through - // window.close(). The details are an ExtensionHost* and the source is a - // Profile*. - NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, - - // Sent when extension render process ends (whether it crashes or closes). - // The details are an ExtensionHost* and the source is a Profile*. Not sent - // during browser shutdown. - NOTIFICATION_EXTENSION_PROCESS_TERMINATED, - - // Sent when a background page is ready so other components can load. - NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, - - // Sent when a browser action's state has changed. The source is the - // ExtensionAction* that changed. The details are the Profile* that the - // browser action belongs to. - NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, - - // Sent when the count of page actions has changed. Note that some of them - // may not apply to the current page. The source is a LocationBar*. There - // are no details. - NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED, - - // Sent when a browser action's visibility has changed. The source is the - // ExtensionPrefs* that changed, and the details are a std::string with the - // extension's ID. - NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED, - - // Sent when a page action's visibility has changed. The source is the - // ExtensionAction* that changed. The details are a WebContents*. - NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, - - // Sent when a system indicator action's state has changed. The source is the - // Profile* that the browser action belongs to. The details are the - // ExtensionAction* that changed. - NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED, - - // Sent when an extension command has been removed. The source is the profile - // and the details is a std::pair of two std::string objects (an extension ID - // and the name of the command being removed). - NOTIFICATION_EXTENSION_COMMAND_REMOVED, - - // Sent when an extension command has been added. The source is the profile - // and the details is a std::pair of two std::string objects (an extension ID - // and the name of the command being added). - NOTIFICATION_EXTENSION_COMMAND_ADDED, - - // Sent when an extension command shortcut for a browser action is activated - // on Mac. The source is the profile and the details is a std::pair of a - // std::string containing an extension ID and a gfx::NativeWindow for the - // associated window. - NOTIFICATION_EXTENSION_COMMAND_BROWSER_ACTION_MAC, - - // Sent when an extension command shortcut for a page action is activated - // on Mac. The source is the profile and the details is a std::pair of a - // std::string containing an extension ID and a gfx::NativeWindow for the - // associated window. - NOTIFICATION_EXTENSION_COMMAND_PAGE_ACTION_MAC, - - // A new extension RenderViewHost has been registered. The details are - // the RenderViewHost*. - NOTIFICATION_EXTENSION_VIEW_REGISTERED, - - // An extension RenderViewHost has been unregistered. The details are - // the RenderViewHost*. - NOTIFICATION_EXTENSION_VIEW_UNREGISTERED, - - // Sent by an extension to notify the browser about the results of a unit - // test. - NOTIFICATION_EXTENSION_TEST_PASSED, - NOTIFICATION_EXTENSION_TEST_FAILED, - - // Sent by extension test javascript code, typically in a browser test. The - // sender is a std::string representing the extension id, and the details - // are a std::string with some message. This is particularly useful when you - // want to have C++ code wait for javascript code to do something. - NOTIFICATION_EXTENSION_TEST_MESSAGE, - - // Sent when an bookmarks extensions API function was successfully invoked. - // The source is the id of the extension that invoked the function, and the - // details are a pointer to the const BookmarksFunction in question. - NOTIFICATION_EXTENSION_BOOKMARKS_API_INVOKED, - - // Sent when a downloads extensions API event is fired. The source is an - // ExtensionDownloadsEventRouter::NotificationSource, and the details is a - // std::string containing json. Used for testing. - NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, - - // Sent when an omnibox extension has sent back omnibox suggestions. The - // source is the profile, and the details are an - // extensions::api::omnibox::SendSuggestions::Params object. - NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY, - - // Sent when the user accepts the input in an extension omnibox keyword - // session. The source is the profile. - NOTIFICATION_EXTENSION_OMNIBOX_INPUT_ENTERED, - - // Sent when an omnibox extension has updated the default suggestion. The - // source is the profile. - NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED, - - // Sent when the extension updater starts checking for updates to installed - // extensions. The source is a Profile, and there are no details. - NOTIFICATION_EXTENSION_UPDATING_STARTED, - - // The extension updater found an update and will attempt to download and - // install it. The source is a Profile, and the details are an - // extensions::UpdateDetails object with the extension id and version of the - // found update. - NOTIFICATION_EXTENSION_UPDATE_FOUND, - - // Upgrade notifications --------------------------------------------------- - - // Sent when Chrome believes an update has been installed and available for - // long enough with the user shutting down to let it take effect. See - // upgrade_detector.cc for details on how long it waits. No details are - // expected. - NOTIFICATION_UPGRADE_RECOMMENDED, - - // Sent when a critical update has been installed. No details are expected. - NOTIFICATION_CRITICAL_UPGRADE_INSTALLED, - - // Sent when the current install is outdated. No details are expected. - NOTIFICATION_OUTDATED_INSTALL, - - // Sent when the current install is outdated and auto-update (AU) is disabled. - // No details are expected. - NOTIFICATION_OUTDATED_INSTALL_NO_AU, - - // Software incompatibility notifications ---------------------------------- - - // Sent when Chrome has finished compiling the list of loaded modules (and - // other modules of interest). No details are expected. - NOTIFICATION_MODULE_LIST_ENUMERATED, - - // Sent when Chrome is done scanning the module list and when the user has - // acknowledged the module incompatibility. No details are expected. - NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE, - - // Content Settings -------------------------------------------------------- - - // Sent when content settings change. The source is a HostContentSettings - // object, the details are ContentSettingsNotificationsDetails. - NOTIFICATION_CONTENT_SETTINGS_CHANGED, - - // Sent when the collect cookies dialog is shown. The source is a - // TabSpecificContentSettings object, there are no details. - NOTIFICATION_COLLECTED_COOKIES_SHOWN, - - // Sent when a non-default setting in the notification content settings - // map has changed. The source is the DesktopNotificationService, the - // details are None. - NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED, - - // Sent when content settings change for a tab. The source is a - // content::WebContents object, the details are None. - NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, - - // Sync -------------------------------------------------------------------- - - // The sync service has finished the datatype configuration process. The - // source is the ProfileSyncService object of the Profile. There are no - // details. - NOTIFICATION_SYNC_CONFIGURE_DONE, - - // A service is requesting a sync datatype refresh for the current profile. - // The details value is a const syncer::ModelTypeSet. - // If the payload map is empty, it should be treated as an invalidation for - // all enabled types. This is used by session sync. - NOTIFICATION_SYNC_REFRESH_LOCAL, - - // External notification requesting a sync datatype refresh for the current - // profile. The details value is a const syncer::ObjectIdInvalidationMap. - // If the payload map is empty, it should be treated as an invalidation for - // all enabled types. This is used for notifications on Android. - NOTIFICATION_SYNC_REFRESH_REMOTE, - - // The session service has been saved. This notification type is only sent - // if there were new SessionService commands to save, and not for no-op save - // operations. - NOTIFICATION_SESSION_SERVICE_SAVED, - - // A foreign session has been updated. If a new tab page is open, the - // foreign session handler needs to update the new tab page's foreign - // session data. - NOTIFICATION_FOREIGN_SESSION_UPDATED, - - // Foreign sessions has been disabled. New tabs should not display foreign - // session data. - NOTIFICATION_FOREIGN_SESSION_DISABLED, - - // All tab metadata has been loaded from disk asynchronously. - // Sent on the UI thread. - // The source is the Profile. There are no details. - NOTIFICATION_SESSION_RESTORE_COMPLETE, - - // Cookies ----------------------------------------------------------------- - - // Sent when a cookie changes. The source is a Profile object, the details - // are a ChromeCookieDetails object. - NOTIFICATION_COOKIE_CHANGED, - - // Download Notifications -------------------------------------------------- - - // Sent when a download is initiated. It is possible that the download will - // not actually begin due to the DownloadRequestLimiter cancelling it - // prematurely. - // The source is the corresponding RenderViewHost. There are no details. - NOTIFICATION_DOWNLOAD_INITIATED, - - // Misc -------------------------------------------------------------------- - - // Sent when PerformanceMonitor has finished all the initial steps of data - // collection and has begun passively observing. The source is the - // PerformanceMonitor*. No details are expected. - NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED, - -#if defined(OS_CHROMEOS) - // Sent when a chromium os user logs in. - // The details are a chromeos::User object. - NOTIFICATION_LOGIN_USER_CHANGED, - - // Sent immediately after the logged-in user's profile is ready. - // The details are a Profile object. - NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, - - // Sent when the chromium session of a particular user is started. - // If this is a new user on the machine this will not be sent until a profile - // picture has been selected, unlike NOTIFICATION_LOGIN_USER_CHANGED which is - // sent immediately after the user has logged in. This will be sent again if - // the browser crashes and restarts. - // The details are a chromeos::User object. - NOTIFICATION_SESSION_STARTED, - - // Sent when user image is updated. - NOTIFICATION_LOGIN_USER_IMAGE_CHANGED, - - // Sent by UserManager when a profile image download has been completed. - NOTIFICATION_PROFILE_IMAGE_UPDATED, - - // Sent by UserManager when profile image download has failed or user has the - // default profile image or no profile image at all. No details are expected. - NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED, - - // Sent when a chromium os user attempts to log in. The source is - // all and the details are AuthenticationNotificationDetails. - NOTIFICATION_LOGIN_AUTHENTICATION, - - // Sent when a network error message is displayed on the WebUI login screen. - // First paint event of this fires NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE. - NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN, - - // Sent when the specific part of login/lock WebUI is considered to be - // visible. That moment is tracked as the first paint event after one of the: - // NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN - // - // Possible series of notifications: - // 1. Boot into fresh OOBE - // NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE - // 2. Boot into user pods list (normal boot). Same for lock screen. - // NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE - // 3. Boot into GAIA sign in UI (user pods display disabled or no users): - // if no network is connected or flaky network - // (NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN + - // NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE) - // NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE - // 4. Boot into retail mode - // NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE - // 5. Boot into kiosk mode - // NOTIFICATION_KIOSK_APP_LAUNCHED - NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, - - // Sent when proxy dialog is closed. - NOTIFICATION_LOGIN_PROXY_CHANGED, - - // Send when kiosk auto-launch warning screen is visible. - NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE, - - // Send when kiosk auto-launch warning screen had completed. - NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED, - - // Send when enable consumer kiosk warning screen is visible. - NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE, - - // Send when consumer kiosk has been enabled. - NOTIFICATION_KIOSK_ENABLED, - - // Send when enable consumer kiosk warning screen had completed. - NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED, - - // Sent when kiosk app list is loaded in UI. - NOTIFICATION_KIOSK_APPS_LOADED, - - // Sent when a kiosk app is launched. - NOTIFICATION_KIOSK_APP_LAUNCHED, - - // Sent when the user list has changed. - NOTIFICATION_USER_LIST_CHANGED, - - // Sent when the screen lock state has changed. The source is - // ScreenLocker and the details is a bool specifying that the - // screen is locked. When details is a false, the source object - // is being deleted, so the receiver shouldn't use the screen locker - // object. - NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, - - // Sent by DeviceSettingsService to indicate that the ownership status - // changed. If you can, please use DeviceSettingsService::Observer instead. - // Other singleton-based services can't use that because Observer - // unregistration is impossible due to unpredictable deletion order. - NOTIFICATION_OWNERSHIP_STATUS_CHANGED, - - // Sent by SIM unlock dialog when it has finished with the process of - // updating RequirePin setting. RequirePin setting might have been changed - // to a new value or update might have been canceled. - // In either case notification is sent and details contain a bool - // that represents current value. - NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED, - - // Sent by SIM unlock dialog when it has finished the EnterPin or - // EnterPuk dialog, either because the user cancelled, or entered a - // PIN or PUK. - NOTIFICATION_ENTER_PIN_ENDED, -#endif - -#if defined(TOOLKIT_VIEWS) - // Sent when a bookmark's context menu is shown. Used to notify - // tests that the context menu has been created and shown. - NOTIFICATION_BOOKMARK_CONTEXT_MENU_SHOWN, - - // Notification that the nested loop using during tab dragging has returned. - // Used for testing. - NOTIFICATION_TAB_DRAG_LOOP_DONE, -#endif - - // Send when a context menu is shown. Used to notify tests that the context - // menu has been created and shown. - NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN, - - // Sent when the Instant Controller determines whether an Instant tab supports - // the Instant API or not. - NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED, - - // Sent when the Instant Controller determines whether the NTP supports the - // Instant API or not. - NOTIFICATION_INSTANT_NTP_SUPPORT_DETERMINED, - - // Sent when the CaptivePortalService checks if we're behind a captive portal. - // The Source is the Profile the CaptivePortalService belongs to, and the - // Details are a Details. - NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT, - - // Sent when the applications in the NTP app launcher have been reordered. - // The details, if not NoDetails, is the std::string ID of the extension that - // was moved. - NOTIFICATION_EXTENSION_LAUNCHER_REORDERED, - - // Sent when an app is installed and an NTP has been shown. Source is the - // WebContents that was shown, and Details is the string ID of the extension - // which was installed. - NOTIFICATION_APP_INSTALLED_TO_NTP, - - // Similar to NOTIFICATION_APP_INSTALLED_TO_NTP but used to notify ash AppList - // about installed app. Source is the profile in which the app is installed - // and Details is the string ID of the extension. - NOTIFICATION_APP_INSTALLED_TO_APPLIST, - -#if defined(USE_ASH) - // Sent when wallpaper show animation has finished. - NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, - - // Sent when the Ash session has started. In its current incantation this is - // generated when the metro app has connected to the browser IPC channel. - // Used only on Windows. - NOTIFICATION_ASH_SESSION_STARTED, - // Sent when the Ash session ended. Currently this means the metro app exited. - // Used only on Windows. - NOTIFICATION_ASH_SESSION_ENDED, -#endif - - // Protocol Handler Registry ----------------------------------------------- - // Sent when a ProtocolHandlerRegistry is changed. The source is the profile. - NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, - - // Sent when the cached profile info has changed. - NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, - - // Sent when the cached profile has finished writing a profile picture to - // disk. - NOTIFICATION_PROFILE_CACHE_PICTURE_SAVED, - - // Sent when the browser enters or exits fullscreen mode. - NOTIFICATION_FULLSCREEN_CHANGED, - - // Sent when the FullscreenController changes, confirms, or denies mouse lock. - // The source is the browser's FullscreenController, no details. - NOTIFICATION_MOUSE_LOCK_CHANGED, - - // Sent by the PluginPrefs when there is a change of plugin enable/disable - // status. The source is the profile. - NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, - - // Panels Notifications. The Panels are small browser windows near the bottom - // of the screen. - // Sent when all nonblocking bounds animations are finished across panels. - // Used only in unit testing. - NOTIFICATION_PANEL_BOUNDS_ANIMATIONS_FINISHED, - - // Sent when panel gains/loses focus. - // The source is the Panel, no details. - // Used only in unit testing. - NOTIFICATION_PANEL_CHANGED_ACTIVE_STATUS, - - // Sent when panel is minimized/restored/shows title only etc. - // The source is the Panel, no details. - NOTIFICATION_PANEL_CHANGED_EXPANSION_STATE, - - // Sent when panel window size is known. This is for platforms where the - // window creation is async and size of the window only becomes known later. - // Used only in unit testing. - NOTIFICATION_PANEL_WINDOW_SIZE_KNOWN, - - // Sent when panel app icon is loaded. - // Used only in unit testing. - NOTIFICATION_PANEL_APP_ICON_LOADED, - - // Sent when panel collection get updated. - // The source is the PanelCollection, no details. - // Used only in coordination with notification balloons. - NOTIFICATION_PANEL_COLLECTION_UPDATED, - - // Sent when panel is closed. - // The source is the Panel, no details. - NOTIFICATION_PANEL_CLOSED, - - // Sent when a global error has changed and the error UI should update it - // self. The source is a Source containing the profile for the - // error. The detail is a GlobalError object that has changed or NULL if - // all error UIs should update. - NOTIFICATION_GLOBAL_ERRORS_CHANGED, - - // BrowsingDataRemover ---------------------------------------------------- - // Sent on the UI thread after BrowsingDataRemover has removed browsing data - // but before it has notified its explicit observers. The source is a - // Source containing the profile in which browsing data was removed, - // and the detail is a BrowsingDataRemover::NotificationDetail containing the - // removal mask and the start of the removal timeframe with which - // BrowsingDataRemove::Remove was called. - NOTIFICATION_BROWSING_DATA_REMOVED, - - // The user accepted or dismissed a SSL client authentication request. - // The source is a Source. Details is a - // (std::pair). - NOTIFICATION_SSL_CLIENT_AUTH_CERT_SELECTED, - - // Session Restore -------------------------------------------------------- - - // Sent when synchronous (startup) session restore completes. No details or - // source. - NOTIFICATION_SESSION_RESTORE_DONE, - - // Note:- - // Currently only Content and Chrome define and use notifications. - // Custom notifications not belonging to Content and Chrome should start - // from here. - NOTIFICATION_CHROME_END, -}; - -} // namespace chrome - -#endif // CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_ diff --git a/chromium_src/chrome/browser/chrome_process_finder_win.cc b/chromium_src/chrome/browser/chrome_process_finder_win.cc deleted file mode 100644 index 5a662258a0be7..0000000000000 --- a/chromium_src/chrome/browser/chrome_process_finder_win.cc +++ /dev/null @@ -1,86 +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. - -#include "chrome/browser/chrome_process_finder_win.h" - -#include -#include - -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/logging.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/win/message_window.h" -#include "base/win/scoped_handle.h" -#include "base/win/win_util.h" -#include "base/win/windows_version.h" - - -namespace { - -int timeout_in_milliseconds = 20 * 1000; - -} // namespace - -namespace chrome { - -HWND FindRunningChromeWindow(const base::FilePath& user_data_dir) { - return base::win::MessageWindow::FindWindow(user_data_dir.value()); -} - -NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window, - bool fast_start) { - DCHECK(remote_window); - DWORD process_id = 0; - DWORD thread_id = GetWindowThreadProcessId(remote_window, &process_id); - if (!thread_id || !process_id) - return NOTIFY_FAILED; - - // Send the command line to the remote chrome window. - // Format is "START\0<<>>\0<<>>". - std::wstring to_send(L"START\0", 6); // want the NULL in the string. - base::FilePath cur_dir; - if (!base::GetCurrentDirectory(&cur_dir)) - return NOTIFY_FAILED; - to_send.append(cur_dir.value()); - to_send.append(L"\0", 1); // Null separator. - to_send.append(::GetCommandLineW()); - to_send.append(L"\0", 1); // Null separator. - - // Allow the current running browser window to make itself the foreground - // window (otherwise it will just flash in the taskbar). - ::AllowSetForegroundWindow(process_id); - - COPYDATASTRUCT cds; - cds.dwData = 0; - cds.cbData = static_cast((to_send.length() + 1) * sizeof(wchar_t)); - cds.lpData = const_cast(to_send.c_str()); - DWORD_PTR result = 0; - if (::SendMessageTimeout(remote_window, WM_COPYDATA, NULL, - reinterpret_cast(&cds), SMTO_ABORTIFHUNG, - timeout_in_milliseconds, &result)) { - return result ? NOTIFY_SUCCESS : NOTIFY_FAILED; - } - - // It is possible that the process owning this window may have died by now. - if (!::IsWindow(remote_window)) - return NOTIFY_FAILED; - - // If the window couldn't be notified but still exists, assume it is hung. - return NOTIFY_WINDOW_HUNG; -} - -base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout) { - base::TimeDelta old_timeout = - base::TimeDelta::FromMilliseconds(timeout_in_milliseconds); - timeout_in_milliseconds = new_timeout.InMilliseconds(); - return old_timeout; -} - -} // namespace chrome diff --git a/chromium_src/chrome/browser/chrome_process_finder_win.h b/chromium_src/chrome/browser/chrome_process_finder_win.h deleted file mode 100644 index a66429de5e746..0000000000000 --- a/chromium_src/chrome/browser/chrome_process_finder_win.h +++ /dev/null @@ -1,39 +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_CHROME_PROCESS_FINDER_WIN_H_ -#define CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_ - -#include - -#include "base/time/time.h" - -namespace base { -class FilePath; -} - -namespace chrome { - -enum NotifyChromeResult { - NOTIFY_SUCCESS, - NOTIFY_FAILED, - NOTIFY_WINDOW_HUNG, -}; - -// Finds an already running Chrome window if it exists. -HWND FindRunningChromeWindow(const base::FilePath& user_data_dir); - -// Attempts to send the current command line to an already running instance of -// Chrome via a WM_COPYDATA message. -// Returns true if a running Chrome is found and successfully notified. -// |fast_start| is true when this is being called on the window fast start path. -NotifyChromeResult AttemptToNotifyRunningChrome(HWND remote_window, - bool fast_start); - -// Changes the notification timeout to |new_timeout|, returns the old timeout. -base::TimeDelta SetNotificationTimeoutForTesting(base::TimeDelta new_timeout); - -} // namespace chrome - -#endif // CHROME_BROWSER_CHROME_PROCESS_FINDER_WIN_H_ diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener.cc b/chromium_src/chrome/browser/extensions/global_shortcut_listener.cc deleted file mode 100644 index 925cb40d0f968..0000000000000 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (c) 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. - -#include "chrome/browser/extensions/global_shortcut_listener.h" - -#include "base/logging.h" -#include "content/public/browser/browser_thread.h" -#include "ui/base/accelerators/accelerator.h" - -using content::BrowserThread; - -namespace extensions { - -GlobalShortcutListener::GlobalShortcutListener() - : shortcut_handling_suspended_(false) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); -} - -GlobalShortcutListener::~GlobalShortcutListener() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(accelerator_map_.empty()); // Make sure we've cleaned up. -} - -bool GlobalShortcutListener::RegisterAccelerator( - const ui::Accelerator& accelerator, Observer* observer) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (IsShortcutHandlingSuspended()) - return false; - - AcceleratorMap::const_iterator it = accelerator_map_.find(accelerator); - if (it != accelerator_map_.end()) { - // The accelerator has been registered. - return false; - } - - if (!RegisterAcceleratorImpl(accelerator)) { - // If the platform-specific registration fails, mostly likely the shortcut - // has been registered by other native applications. - return false; - } - - if (accelerator_map_.empty()) - StartListening(); - - accelerator_map_[accelerator] = observer; - return true; -} - -void GlobalShortcutListener::UnregisterAccelerator( - const ui::Accelerator& accelerator, Observer* observer) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (IsShortcutHandlingSuspended()) - return; - - AcceleratorMap::iterator it = accelerator_map_.find(accelerator); - // We should never get asked to unregister something that we didn't register. - DCHECK(it != accelerator_map_.end()); - // The caller should call this function with the right observer. - DCHECK(it->second == observer); - - UnregisterAcceleratorImpl(accelerator); - accelerator_map_.erase(it); - if (accelerator_map_.empty()) - StopListening(); -} - -void GlobalShortcutListener::UnregisterAccelerators(Observer* observer) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (IsShortcutHandlingSuspended()) - return; - - AcceleratorMap::iterator it = accelerator_map_.begin(); - while (it != accelerator_map_.end()) { - if (it->second == observer) { - AcceleratorMap::iterator to_remove = it++; - UnregisterAccelerator(to_remove->first, observer); - } else { - ++it; - } - } -} - -void GlobalShortcutListener::SetShortcutHandlingSuspended(bool suspended) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (shortcut_handling_suspended_ == suspended) - return; - - shortcut_handling_suspended_ = suspended; - for (AcceleratorMap::iterator it = accelerator_map_.begin(); - it != accelerator_map_.end(); - ++it) { - // On Linux, when shortcut handling is suspended we cannot simply early - // return in NotifyKeyPressed (similar to what we do for non-global - // shortcuts) because we'd eat the keyboard event thereby preventing the - // user from setting the shortcut. Therefore we must unregister while - // handling is suspended and register when handling resumes. - if (shortcut_handling_suspended_) - UnregisterAcceleratorImpl(it->first); - else - RegisterAcceleratorImpl(it->first); - } -} - -bool GlobalShortcutListener::IsShortcutHandlingSuspended() const { - return shortcut_handling_suspended_; -} - -void GlobalShortcutListener::NotifyKeyPressed( - const ui::Accelerator& accelerator) { - AcceleratorMap::iterator iter = accelerator_map_.find(accelerator); - if (iter == accelerator_map_.end()) { - // This should never occur, because if it does, we have failed to unregister - // or failed to clean up the map after unregistering the shortcut. - NOTREACHED(); - return; // No-one is listening to this key. - } - - iter->second->OnKeyPressed(accelerator); -} - -} // namespace extensions diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener.h b/chromium_src/chrome/browser/extensions/global_shortcut_listener.h deleted file mode 100644 index 9aec54a3263d2..0000000000000 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 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_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_ -#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_ - -#include - -#include "base/macros.h" -#include "ui/events/keycodes/keyboard_codes.h" - -namespace ui { -class Accelerator; -} - -namespace extensions { - -// Platform-neutral implementation of a class that keeps track of observers and -// monitors keystrokes. It relays messages to the appropriate observer when a -// global shortcut has been struck by the user. -class GlobalShortcutListener { - public: - class Observer { - public: - // Called when your global shortcut (|accelerator|) is struck. - virtual void OnKeyPressed(const ui::Accelerator& accelerator) = 0; - }; - - virtual ~GlobalShortcutListener(); - - static GlobalShortcutListener* GetInstance(); - - // Register an observer for when a certain |accelerator| is struck. Returns - // true if register successfully, or false if 1) the specificied |accelerator| - // has been registered by another caller or other native applications, or - // 2) shortcut handling is suspended. - // - // Note that we do not support recognizing that an accelerator has been - // registered by another application on all platforms. This is a per-platform - // consideration. - bool RegisterAccelerator(const ui::Accelerator& accelerator, - Observer* observer); - - // Stop listening for the given |accelerator|, does nothing if shortcut - // handling is suspended. - void UnregisterAccelerator(const ui::Accelerator& accelerator, - Observer* observer); - - // Stop listening for all accelerators of the given |observer|, does nothing - // if shortcut handling is suspended. - void UnregisterAccelerators(Observer* observer); - - // Suspend/Resume global shortcut handling. Note that when suspending, - // RegisterAccelerator/UnregisterAccelerator/UnregisterAccelerators are not - // allowed to be called until shortcut handling has been resumed. - void SetShortcutHandlingSuspended(bool suspended); - - // Returns whether shortcut handling is currently suspended. - bool IsShortcutHandlingSuspended() const; - - protected: - GlobalShortcutListener(); - - // Called by platform specific implementations of this class whenever a key - // is struck. Only called for keys that have an observer registered. - void NotifyKeyPressed(const ui::Accelerator& accelerator); - - private: - // The following methods are implemented by platform-specific implementations - // of this class. - // - // Start/StopListening are called when transitioning between zero and nonzero - // registered accelerators. StartListening will be called after - // RegisterAcceleratorImpl and StopListening will be called after - // UnregisterAcceleratorImpl. - // - // For RegisterAcceleratorImpl, implementations return false if registration - // did not complete successfully. - virtual void StartListening() = 0; - virtual void StopListening() = 0; - virtual bool RegisterAcceleratorImpl(const ui::Accelerator& accelerator) = 0; - virtual void UnregisterAcceleratorImpl( - const ui::Accelerator& accelerator) = 0; - - // The map of accelerators that have been successfully registered as global - // shortcuts and their observer. - typedef std::map AcceleratorMap; - AcceleratorMap accelerator_map_; - - // Keeps track of whether shortcut handling is currently suspended. - bool shortcut_handling_suspended_; - - DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListener); -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_H_ diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.h b/chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.h deleted file mode 100644 index c38cb1dc5289b..0000000000000 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) 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_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_ -#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_ - -#include "chrome/browser/extensions/global_shortcut_listener.h" - -#include -#include - -#include - -#include "base/mac/scoped_nsobject.h" - -namespace extensions { - -// Mac-specific implementation of the GlobalShortcutListener class that -// listens for global shortcuts. Handles basic keyboard intercepting and -// forwards its output to the base class for processing. -// -// This class does two things: -// 1. Intercepts media/volume keys. Uses an event tap for intercepting media keys -// (PlayPause, NextTrack, PreviousTrack) and volume keys(VolumeUp, VolumeDown, VolumeMute). -// 2. Binds keyboard shortcuts (hot keys). Carbon RegisterEventHotKey API for -// binding to non-media key global hot keys (eg. Command-Shift-1). -class GlobalShortcutListenerMac : public GlobalShortcutListener { - public: - GlobalShortcutListenerMac(); - virtual ~GlobalShortcutListenerMac(); - - private: - typedef int KeyId; - typedef std::map AcceleratorIdMap; - typedef std::map IdAcceleratorMap; - typedef std::map IdHotKeyRefMap; - - // Keyboard event callbacks. - void OnHotKeyEvent(EventHotKeyID hot_key_id); - bool OnMediaOrVolumeKeyEvent(int key_code); - - // GlobalShortcutListener implementation. - virtual void StartListening() override; - virtual void StopListening() override; - virtual bool RegisterAcceleratorImpl( - const ui::Accelerator& accelerator) override; - virtual void UnregisterAcceleratorImpl( - const ui::Accelerator& accelerator) override; - - // Mac-specific functions for registering hot keys with modifiers. - bool RegisterHotKey(const ui::Accelerator& accelerator, KeyId hot_key_id); - void UnregisterHotKey(const ui::Accelerator& accelerator); - - // Enable and disable the media/volume key event tap. - void StartWatchingMediaOrVolumeKeys(); - void StopWatchingMediaOrVolumeKeys(); - - // Enable and disable the hot key event handler. - void StartWatchingHotKeys(); - void StopWatchingHotKeys(); - - // Whether or not any media/volume keys are currently registered. - bool IsAnyMediaOrVolumeKeyRegistered(); - - // Whether or not any hot keys are currently registered. - bool IsAnyHotKeyRegistered(); - - // The callback for when an event tap happens. - static CGEventRef EventTapCallback( - CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon); - - // The callback for when a hot key event happens. - static OSStatus HotKeyHandler( - EventHandlerCallRef next_handler, EventRef event, void* user_data); - - // Whether this object is listening for global shortcuts. - bool is_listening_; - - // The hotkey identifier for the next global shortcut that is added. - KeyId hot_key_id_; - - // A map of all hotkeys (media/volume keys and shortcuts) mapping to their - // corresponding hotkey IDs. For quickly finding if an accelerator is - // registered. - AcceleratorIdMap accelerator_ids_; - - // The inverse map for quickly looking up accelerators by hotkey id. - IdAcceleratorMap id_accelerators_; - - // Keyboard shortcut IDs to hotkeys map for unregistration. - IdHotKeyRefMap id_hot_key_refs_; - - // Event tap for intercepting mac media/volume keys. - CFMachPortRef event_tap_; - CFRunLoopSourceRef event_tap_source_; - - // Event handler for keyboard shortcut hot keys. - EventHandlerRef event_handler_; - - DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerMac); -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_ diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.mm b/chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.mm deleted file mode 100644 index 80daf8712ab67..0000000000000 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.mm +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright (c) 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. - -#include "chrome/browser/extensions/global_shortcut_listener_mac.h" - -#include -#import -#include - -#import "base/mac/foundation_util.h" -#include "content/public/browser/browser_thread.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/events/event.h" -#import "ui/events/keycodes/keyboard_code_conversion_mac.h" - -using content::BrowserThread; -using extensions::GlobalShortcutListenerMac; - -namespace { - -// The media/volume keys subtype. No official docs found, but widely known. -// http://lists.apple.com/archives/cocoa-dev/2007/Aug/msg00499.html -const int kSystemDefinedEventMediaAndVolumeKeysSubtype = 8; - -ui::KeyboardCode MediaOrVolumeKeyCodeToKeyboardCode(int key_code) { - switch (key_code) { - case NX_KEYTYPE_PLAY: - return ui::VKEY_MEDIA_PLAY_PAUSE; - case NX_KEYTYPE_PREVIOUS: - case NX_KEYTYPE_REWIND: - return ui::VKEY_MEDIA_PREV_TRACK; - case NX_KEYTYPE_NEXT: - case NX_KEYTYPE_FAST: - return ui::VKEY_MEDIA_NEXT_TRACK; - case NX_KEYTYPE_SOUND_UP: - return ui::VKEY_VOLUME_UP; - case NX_KEYTYPE_SOUND_DOWN: - return ui::VKEY_VOLUME_DOWN; - case NX_KEYTYPE_MUTE: - return ui::VKEY_VOLUME_MUTE; - } - return ui::VKEY_UNKNOWN; -} - -bool IsMediaOrVolumeKey(const ui::Accelerator& accelerator) { - if (accelerator.modifiers() != 0) - return false; - return (accelerator.key_code() == ui::VKEY_MEDIA_NEXT_TRACK || - accelerator.key_code() == ui::VKEY_MEDIA_PREV_TRACK || - accelerator.key_code() == ui::VKEY_MEDIA_PLAY_PAUSE || - accelerator.key_code() == ui::VKEY_MEDIA_STOP || - accelerator.key_code() == ui::VKEY_VOLUME_UP || - accelerator.key_code() == ui::VKEY_VOLUME_DOWN || - accelerator.key_code() == ui::VKEY_VOLUME_MUTE); -} - -} // namespace - -namespace extensions { - -// static -GlobalShortcutListener* GlobalShortcutListener::GetInstance() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - static GlobalShortcutListenerMac* instance = - new GlobalShortcutListenerMac(); - return instance; -} - -GlobalShortcutListenerMac::GlobalShortcutListenerMac() - : is_listening_(false), - hot_key_id_(0), - event_tap_(NULL), - event_tap_source_(NULL), - event_handler_(NULL) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); -} - -GlobalShortcutListenerMac::~GlobalShortcutListenerMac() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // By this point, UnregisterAccelerator should have been called for all - // keyboard shortcuts. Still we should clean up. - if (is_listening_) - StopListening(); - - // If keys are still registered, make sure we stop the tap. Again, this - // should never happen. - if (IsAnyMediaOrVolumeKeyRegistered()) - StopWatchingMediaOrVolumeKeys(); - - if (IsAnyHotKeyRegistered()) - StopWatchingHotKeys(); -} - -void GlobalShortcutListenerMac::StartListening() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - DCHECK(!accelerator_ids_.empty()); - DCHECK(!id_accelerators_.empty()); - DCHECK(!is_listening_); - - is_listening_ = true; -} - -void GlobalShortcutListenerMac::StopListening() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - DCHECK(accelerator_ids_.empty()); // Make sure the set is clean. - DCHECK(id_accelerators_.empty()); - DCHECK(is_listening_); - - is_listening_ = false; -} - -void GlobalShortcutListenerMac::OnHotKeyEvent(EventHotKeyID hot_key_id) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // This hot key should be registered. - DCHECK(id_accelerators_.find(hot_key_id.id) != id_accelerators_.end()); - // Look up the accelerator based on this hot key ID. - const ui::Accelerator& accelerator = id_accelerators_[hot_key_id.id]; - NotifyKeyPressed(accelerator); -} - -bool GlobalShortcutListenerMac::OnMediaOrVolumeKeyEvent( - int media_or_volume_key_code) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ui::KeyboardCode key_code = MediaOrVolumeKeyCodeToKeyboardCode( - media_or_volume_key_code); - // Create an accelerator corresponding to the keyCode. - ui::Accelerator accelerator(key_code, 0); - // Look for a match with a bound hot_key. - if (accelerator_ids_.find(accelerator) != accelerator_ids_.end()) { - // If matched, callback to the event handling system. - NotifyKeyPressed(accelerator); - return true; - } - return false; -} - -bool GlobalShortcutListenerMac::RegisterAcceleratorImpl( - const ui::Accelerator& accelerator) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(accelerator_ids_.find(accelerator) == accelerator_ids_.end()); - - if (IsMediaOrVolumeKey(accelerator)) { - if (!IsAnyMediaOrVolumeKeyRegistered()) { - // If this is the first media/volume key registered, start the event tap. - StartWatchingMediaOrVolumeKeys(); - } - } else { - // Register hot_key if they are non-media keyboard shortcuts. - if (!RegisterHotKey(accelerator, hot_key_id_)) - return false; - - if (!IsAnyHotKeyRegistered()) { - StartWatchingHotKeys(); - } - } - - // Store the hotkey-ID mappings we will need for lookup later. - id_accelerators_[hot_key_id_] = accelerator; - accelerator_ids_[accelerator] = hot_key_id_; - ++hot_key_id_; - return true; -} - -void GlobalShortcutListenerMac::UnregisterAcceleratorImpl( - const ui::Accelerator& accelerator) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(accelerator_ids_.find(accelerator) != accelerator_ids_.end()); - - // Unregister the hot_key if it's a keyboard shortcut. - if (!IsMediaOrVolumeKey(accelerator)) - UnregisterHotKey(accelerator); - - // Remove hot_key from the mappings. - KeyId key_id = accelerator_ids_[accelerator]; - id_accelerators_.erase(key_id); - accelerator_ids_.erase(accelerator); - - if (IsMediaOrVolumeKey(accelerator)) { - // If we unregistered a media/volume key, and now no media/volume keys are registered, - // stop the media/volume key tap. - if (!IsAnyMediaOrVolumeKeyRegistered()) - StopWatchingMediaOrVolumeKeys(); - } else { - // If we unregistered a hot key, and no more hot keys are registered, remove - // the hot key handler. - if (!IsAnyHotKeyRegistered()) { - StopWatchingHotKeys(); - } - } -} - -bool GlobalShortcutListenerMac::RegisterHotKey( - const ui::Accelerator& accelerator, KeyId hot_key_id) { - EventHotKeyID event_hot_key_id; - - // Signature uniquely identifies the application that owns this hot_key. - event_hot_key_id.signature = base::mac::CreatorCodeForApplication(); - event_hot_key_id.id = hot_key_id; - - // Translate ui::Accelerator modifiers to cmdKey, altKey, etc. - int modifiers = 0; - modifiers |= (accelerator.IsShiftDown() ? shiftKey : 0); - modifiers |= (accelerator.IsCtrlDown() ? controlKey : 0); - modifiers |= (accelerator.IsAltDown() ? optionKey : 0); - modifiers |= (accelerator.IsCmdDown() ? cmdKey : 0); - - int key_code = ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(), 0, - NULL, NULL); - - // Register the event hot key. - EventHotKeyRef hot_key_ref; - OSStatus status = RegisterEventHotKey(key_code, modifiers, event_hot_key_id, - GetApplicationEventTarget(), 0, &hot_key_ref); - if (status != noErr) - return false; - - id_hot_key_refs_[hot_key_id] = hot_key_ref; - return true; -} - -void GlobalShortcutListenerMac::UnregisterHotKey( - const ui::Accelerator& accelerator) { - // Ensure this accelerator is already registered. - DCHECK(accelerator_ids_.find(accelerator) != accelerator_ids_.end()); - // Get the ref corresponding to this accelerator. - KeyId key_id = accelerator_ids_[accelerator]; - EventHotKeyRef ref = id_hot_key_refs_[key_id]; - // Unregister the event hot key. - UnregisterEventHotKey(ref); - - // Remove the event from the mapping. - id_hot_key_refs_.erase(key_id); -} - -void GlobalShortcutListenerMac::StartWatchingMediaOrVolumeKeys() { - // Make sure there's no existing event tap. - DCHECK(event_tap_ == NULL); - DCHECK(event_tap_source_ == NULL); - - // Add an event tap to intercept the system defined media/volume key events. - event_tap_ = CGEventTapCreate(kCGSessionEventTap, - kCGHeadInsertEventTap, - kCGEventTapOptionDefault, - CGEventMaskBit(NX_SYSDEFINED), - EventTapCallback, - this); - if (event_tap_ == NULL) { - LOG(ERROR) << "Error: failed to create event tap."; - return; - } - - event_tap_source_ = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, - event_tap_, 0); - if (event_tap_source_ == NULL) { - LOG(ERROR) << "Error: failed to create new run loop source."; - return; - } - - CFRunLoopAddSource(CFRunLoopGetCurrent(), event_tap_source_, - kCFRunLoopCommonModes); -} - -void GlobalShortcutListenerMac::StopWatchingMediaOrVolumeKeys() { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), event_tap_source_, - kCFRunLoopCommonModes); - // Ensure both event tap and source are initialized. - DCHECK(event_tap_ != NULL); - DCHECK(event_tap_source_ != NULL); - - // Invalidate the event tap. - CFMachPortInvalidate(event_tap_); - CFRelease(event_tap_); - event_tap_ = NULL; - - // Release the event tap source. - CFRelease(event_tap_source_); - event_tap_source_ = NULL; -} - -void GlobalShortcutListenerMac::StartWatchingHotKeys() { - DCHECK(!event_handler_); - EventHandlerUPP hot_key_function = NewEventHandlerUPP(HotKeyHandler); - EventTypeSpec event_type; - event_type.eventClass = kEventClassKeyboard; - event_type.eventKind = kEventHotKeyPressed; - InstallApplicationEventHandler( - hot_key_function, 1, &event_type, this, &event_handler_); -} - -void GlobalShortcutListenerMac::StopWatchingHotKeys() { - DCHECK(event_handler_); - RemoveEventHandler(event_handler_); - event_handler_ = NULL; -} - -bool GlobalShortcutListenerMac::IsAnyMediaOrVolumeKeyRegistered() { - // Iterate through registered accelerators, looking for media/volume keys. - AcceleratorIdMap::iterator it; - for (it = accelerator_ids_.begin(); it != accelerator_ids_.end(); ++it) { - if (IsMediaOrVolumeKey(it->first)) - return true; - } - return false; -} - -bool GlobalShortcutListenerMac::IsAnyHotKeyRegistered() { - AcceleratorIdMap::iterator it; - for (it = accelerator_ids_.begin(); it != accelerator_ids_.end(); ++it) { - if (!IsMediaOrVolumeKey(it->first)) - return true; - } - return false; -} - -// Processed events should propagate if they aren't handled by any listeners. -// For events that don't matter, this handler should return as quickly as -// possible. -// Returning event causes the event to propagate to other applications. -// Returning NULL prevents the event from propagating. -// static -CGEventRef GlobalShortcutListenerMac::EventTapCallback( - CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) { - GlobalShortcutListenerMac* shortcut_listener = - static_cast(refcon); - - // Handle the timeout case by re-enabling the tap. - if (type == kCGEventTapDisabledByTimeout) { - CGEventTapEnable(shortcut_listener->event_tap_, TRUE); - return event; - } - - // Convert the CGEvent to an NSEvent for access to the data1 field. - NSEvent* ns_event = [NSEvent eventWithCGEvent:event]; - if (ns_event == nil) { - return event; - } - - // Ignore events that are not system defined media/volume keys. - if (type != NX_SYSDEFINED || - [ns_event type] != NSSystemDefined || - [ns_event subtype] != kSystemDefinedEventMediaAndVolumeKeysSubtype) { - return event; - } - - NSInteger data1 = [ns_event data1]; - // Ignore media keys that aren't previous, next and play/pause and - // volume keys that aren't up, down and mute. - // Magical constants are from http://weblog.rogueamoeba.com/2007/09/29/ - int key_code = (data1 & 0xFFFF0000) >> 16; - if (key_code != NX_KEYTYPE_PLAY && key_code != NX_KEYTYPE_NEXT && - key_code != NX_KEYTYPE_PREVIOUS && key_code != NX_KEYTYPE_FAST && - key_code != NX_KEYTYPE_REWIND && - key_code != NX_KEYTYPE_SOUND_UP && - key_code != NX_KEYTYPE_SOUND_DOWN && - key_code != NX_KEYTYPE_MUTE) { - return event; - } - - int key_flags = data1 & 0x0000FFFF; - bool is_key_pressed = ((key_flags & 0xFF00) >> 8) == 0xA; - - // If the key wasn't pressed (eg. was released), ignore this event. - if (!is_key_pressed) - return event; - - // Now we have a media/volume key that we care about. Send it to the caller. - bool was_handled = shortcut_listener->OnMediaOrVolumeKeyEvent(key_code); - - // Prevent event from proagating to other apps if handled by Chrome. - if (was_handled) - return NULL; - - // By default, pass the event through. - return event; -} - -// static -OSStatus GlobalShortcutListenerMac::HotKeyHandler( - EventHandlerCallRef next_handler, EventRef event, void* user_data) { - // Extract the hotkey from the event. - EventHotKeyID hot_key_id; - OSStatus result = GetEventParameter(event, kEventParamDirectObject, - typeEventHotKeyID, NULL, sizeof(hot_key_id), NULL, &hot_key_id); - if (result != noErr) - return result; - - GlobalShortcutListenerMac* shortcut_listener = - static_cast(user_data); - shortcut_listener->OnHotKeyEvent(hot_key_id); - return noErr; -} - -} // namespace extensions diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc b/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc deleted file mode 100644 index 8ed234d5e81b9..0000000000000 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 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. - -#include "chrome/browser/extensions/global_shortcut_listener_win.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/win/win_util.h" -#include "content/public/browser/browser_thread.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/events/event_constants.h" -#include "ui/events/keycodes/keyboard_code_conversion_win.h" -#include "ui/gfx/win/singleton_hwnd.h" - -using content::BrowserThread; - -namespace extensions { - -// static -GlobalShortcutListener* GlobalShortcutListener::GetInstance() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - static GlobalShortcutListenerWin* instance = - new GlobalShortcutListenerWin(); - return instance; -} - -GlobalShortcutListenerWin::GlobalShortcutListenerWin() - : is_listening_(false) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); -} - -GlobalShortcutListenerWin::~GlobalShortcutListenerWin() { - if (is_listening_) - StopListening(); -} - -void GlobalShortcutListenerWin::StartListening() { - DCHECK(!is_listening_); // Don't start twice. - DCHECK(!hotkey_ids_.empty()); // Also don't start if no hotkey is registered. - singleton_hwnd_observer_.reset(new gfx::SingletonHwndObserver( - base::Bind( - &GlobalShortcutListenerWin::OnWndProc, base::Unretained(this)))); - - is_listening_ = true; -} - -void GlobalShortcutListenerWin::StopListening() { - DCHECK(is_listening_); // No point if we are not already listening. - DCHECK(hotkey_ids_.empty()); // Make sure the map is clean before ending. - singleton_hwnd_observer_.reset(nullptr); - is_listening_ = false; -} - -void GlobalShortcutListenerWin::OnWndProc(HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam) { - if (message != WM_HOTKEY) - return; - - int key_code = HIWORD(lparam); - int modifiers = 0; - modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0; - modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0; - modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0; - modifiers |= (LOWORD(lparam) & MOD_WIN) ? ui::EF_COMMAND_DOWN : 0; - - ui::Accelerator accelerator( - ui::KeyboardCodeForWindowsKeyCode(key_code), modifiers); - - NotifyKeyPressed(accelerator); -} - -bool GlobalShortcutListenerWin::RegisterAcceleratorImpl( - const ui::Accelerator& accelerator) { - DCHECK(hotkey_ids_.find(accelerator) == hotkey_ids_.end()); - - int modifiers = 0; - modifiers |= accelerator.IsShiftDown() ? MOD_SHIFT : 0; - modifiers |= accelerator.IsCtrlDown() ? MOD_CONTROL : 0; - modifiers |= accelerator.IsAltDown() ? MOD_ALT : 0; - modifiers |= accelerator.IsCmdDown() ? MOD_WIN : 0; - - static int hotkey_id = 0; - bool success = !!RegisterHotKey( - gfx::SingletonHwnd::GetInstance()->hwnd(), - hotkey_id, - modifiers, - accelerator.key_code()); - - if (!success) { - // Most likely error: 1409 (Hotkey already registered). - return false; - } - - hotkey_ids_[accelerator] = hotkey_id++; - return true; -} - -void GlobalShortcutListenerWin::UnregisterAcceleratorImpl( - const ui::Accelerator& accelerator) { - HotkeyIdMap::iterator it = hotkey_ids_.find(accelerator); - DCHECK(it != hotkey_ids_.end()); - - bool success = !!UnregisterHotKey( - gfx::SingletonHwnd::GetInstance()->hwnd(), it->second); - // This call should always succeed, as long as we pass in the right HWND and - // an id we've used to register before. - DCHECK(success); - - hotkey_ids_.erase(it); -} - -} // namespace extensions diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h b/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h deleted file mode 100644 index 83e9fdff283fb..0000000000000 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 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_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_ -#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_ - -#include - -#include - -#include "chrome/browser/extensions/global_shortcut_listener.h" -#include "ui/gfx/win/singleton_hwnd.h" -#include "ui/gfx/win/singleton_hwnd_observer.h" - -namespace extensions { - -// Windows-specific implementation of the GlobalShortcutListener class that -// listens for global shortcuts. Handles setting up a keyboard hook and -// forwarding its output to the base class for processing. -class GlobalShortcutListenerWin : public GlobalShortcutListener { - public: - GlobalShortcutListenerWin(); - virtual ~GlobalShortcutListenerWin(); - - private: - // The implementation of our Window Proc, called by SingletonHwndObserver. - void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); - - // GlobalShortcutListener implementation. - virtual void StartListening() override; - virtual void StopListening() override; - virtual bool RegisterAcceleratorImpl( - const ui::Accelerator& accelerator) override; - virtual void UnregisterAcceleratorImpl( - const ui::Accelerator& accelerator) override; - - // Whether this object is listening for global shortcuts. - bool is_listening_; - - // A map of registered accelerators and their registration ids. - typedef std::map HotkeyIdMap; - HotkeyIdMap hotkey_ids_; - - std::unique_ptr singleton_hwnd_observer_; - - DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerWin); -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_WIN_H_ diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc b/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc deleted file mode 100644 index 00a689a7cb2fe..0000000000000 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.cc +++ /dev/null @@ -1,163 +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. - -#include "chrome/browser/extensions/global_shortcut_listener_x11.h" - -#include - -#include "base/macros.h" -#include "content/public/browser/browser_thread.h" -#include "ui/base/accelerators/accelerator.h" -#include "ui/events/keycodes/keyboard_code_conversion_x.h" -#include "ui/events/platform/platform_event_source.h" -#include "ui/gfx/x/x11_error_tracker.h" -#include "ui/gfx/x/x11_types.h" - -using content::BrowserThread; - -namespace { - -// The modifiers masks used for grabing keys. Due to XGrabKey only working on -// exact modifiers, we need to grab all key combination including zero or more -// of the following: Num lock, Caps lock and Scroll lock. So that we can make -// sure the behavior of global shortcuts is consistent on all platforms. -const unsigned int kModifiersMasks[] = { - 0, // No additional modifier. - Mod2Mask, // Num lock - LockMask, // Caps lock - Mod5Mask, // Scroll lock - Mod2Mask | LockMask, - Mod2Mask | Mod5Mask, - LockMask | Mod5Mask, - Mod2Mask | LockMask | Mod5Mask -}; - -int GetNativeModifiers(const ui::Accelerator& accelerator) { - int modifiers = 0; - modifiers |= accelerator.IsShiftDown() ? ShiftMask : 0; - modifiers |= accelerator.IsCtrlDown() ? ControlMask : 0; - modifiers |= accelerator.IsAltDown() ? Mod1Mask : 0; - modifiers |= accelerator.IsCmdDown() ? Mod4Mask : 0; - - return modifiers; -} - -} // namespace - -namespace extensions { - -// static -GlobalShortcutListener* GlobalShortcutListener::GetInstance() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - static GlobalShortcutListenerX11* instance = - new GlobalShortcutListenerX11(); - return instance; -} - -GlobalShortcutListenerX11::GlobalShortcutListenerX11() - : is_listening_(false), - x_display_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(x_display_)) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); -} - -GlobalShortcutListenerX11::~GlobalShortcutListenerX11() { - if (is_listening_) - StopListening(); -} - -void GlobalShortcutListenerX11::StartListening() { - DCHECK(!is_listening_); // Don't start twice. - DCHECK(!registered_hot_keys_.empty()); // Also don't start if no hotkey is - // registered. - - ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); - - is_listening_ = true; -} - -void GlobalShortcutListenerX11::StopListening() { - DCHECK(is_listening_); // No point if we are not already listening. - DCHECK(registered_hot_keys_.empty()); // Make sure the set is clean before - // ending. - - ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); - - is_listening_ = false; -} - -bool GlobalShortcutListenerX11::CanDispatchEvent( - const ui::PlatformEvent& event) { - return event->type == KeyPress; -} - -uint32_t GlobalShortcutListenerX11::DispatchEvent( - const ui::PlatformEvent& event) { - CHECK_EQ(KeyPress, event->type); - OnXKeyPressEvent(event); - - return ui::POST_DISPATCH_NONE; -} - -bool GlobalShortcutListenerX11::RegisterAcceleratorImpl( - const ui::Accelerator& accelerator) { - DCHECK(registered_hot_keys_.find(accelerator) == registered_hot_keys_.end()); - - int modifiers = GetNativeModifiers(accelerator); - KeyCode keycode = XKeysymToKeycode(x_display_, - XKeysymForWindowsKeyCode(accelerator.key_code(), false)); - gfx::X11ErrorTracker err_tracker; - - // Because XGrabKey only works on the exact modifiers mask, we should register - // our hot keys with modifiers that we want to ignore, including Num lock, - // Caps lock, Scroll lock. See comment about |kModifiersMasks|. - for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) { - XGrabKey(x_display_, keycode, modifiers | kModifiersMasks[i], - x_root_window_, False, GrabModeAsync, GrabModeAsync); - } - - if (err_tracker.FoundNewError()) { - // We may have part of the hotkeys registered, clean up. - for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) { - XUngrabKey(x_display_, keycode, modifiers | kModifiersMasks[i], - x_root_window_); - } - - return false; - } - - registered_hot_keys_.insert(accelerator); - return true; -} - -void GlobalShortcutListenerX11::UnregisterAcceleratorImpl( - const ui::Accelerator& accelerator) { - DCHECK(registered_hot_keys_.find(accelerator) != registered_hot_keys_.end()); - - int modifiers = GetNativeModifiers(accelerator); - KeyCode keycode = XKeysymToKeycode(x_display_, - XKeysymForWindowsKeyCode(accelerator.key_code(), false)); - - for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) { - XUngrabKey(x_display_, keycode, modifiers | kModifiersMasks[i], - x_root_window_); - } - registered_hot_keys_.erase(accelerator); -} - -void GlobalShortcutListenerX11::OnXKeyPressEvent(::XEvent* x_event) { - DCHECK(x_event->type == KeyPress); - int modifiers = 0; - modifiers |= (x_event->xkey.state & ShiftMask) ? ui::EF_SHIFT_DOWN : 0; - modifiers |= (x_event->xkey.state & ControlMask) ? ui::EF_CONTROL_DOWN : 0; - modifiers |= (x_event->xkey.state & Mod1Mask) ? ui::EF_ALT_DOWN : 0; - modifiers |= (x_event->xkey.state & Mod4Mask) ? ui::EF_COMMAND_DOWN: 0; - - ui::Accelerator accelerator( - ui::KeyboardCodeFromXKeyEvent(x_event), modifiers); - if (registered_hot_keys_.find(accelerator) != registered_hot_keys_.end()) - NotifyKeyPressed(accelerator); -} - -} // namespace extensions diff --git a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h b/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h deleted file mode 100644 index 43230b7aa3108..0000000000000 --- a/chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h +++ /dev/null @@ -1,58 +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_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_ -#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_ - -#include -#include - -#include - -#include "base/macros.h" -#include "chrome/browser/extensions/global_shortcut_listener.h" -#include "ui/events/platform/platform_event_dispatcher.h" - -namespace extensions { - -// X11-specific implementation of the GlobalShortcutListener class that -// listens for global shortcuts. Handles basic keyboard intercepting and -// forwards its output to the base class for processing. -class GlobalShortcutListenerX11 : public GlobalShortcutListener, - public ui::PlatformEventDispatcher { - public: - GlobalShortcutListenerX11(); - ~GlobalShortcutListenerX11() override; - - // ui::PlatformEventDispatcher implementation. - bool CanDispatchEvent(const ui::PlatformEvent& event) override; - uint32_t DispatchEvent(const ui::PlatformEvent& event) override; - - private: - // GlobalShortcutListener implementation. - void StartListening() override; - void StopListening() override; - bool RegisterAcceleratorImpl(const ui::Accelerator& accelerator) override; - void UnregisterAcceleratorImpl(const ui::Accelerator& accelerator) override; - - // Invoked when a global shortcut is pressed. - void OnXKeyPressEvent(::XEvent* x_event); - - // Whether this object is listening for global shortcuts. - bool is_listening_; - - // The x11 default display and the native root window. - ::Display* x_display_; - ::Window x_root_window_; - - // A set of registered accelerators. - typedef std::set RegisteredHotKeys; - RegisteredHotKeys registered_hot_keys_; - - DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerX11); -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_ diff --git a/chromium_src/chrome/browser/media/desktop_media_list.h b/chromium_src/chrome/browser/media/desktop_media_list.h deleted file mode 100644 index 6572e792a1229..0000000000000 --- a/chromium_src/chrome/browser/media/desktop_media_list.h +++ /dev/null @@ -1,61 +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_MEDIA_DESKTOP_MEDIA_LIST_H_ -#define CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_H_ - -#include "base/strings/string16.h" -#include "base/time/time.h" -#include "content/public/browser/desktop_media_id.h" -#include "ui/gfx/image/image_skia.h" - -class DesktopMediaListObserver; - -// DesktopMediaList provides the list of desktop media source (screens, windows, -// tabs), and their thumbnails, to the desktop media picker dialog. It -// transparently updates the list in the background, and notifies the desktop -// media picker when something changes. -class DesktopMediaList { - public: - // Struct used to represent each entry in the list. - struct Source { - // Id of the source. - content::DesktopMediaID id; - - // Name of the source that should be shown to the user. - base::string16 name; - - // The thumbnail for the source. - gfx::ImageSkia thumbnail; - }; - - virtual ~DesktopMediaList() {} - - // Sets time interval between updates. By default list of sources and their - // thumbnail are updated once per second. If called after StartUpdating() then - // it will take effect only after the next update. - virtual void SetUpdatePeriod(base::TimeDelta period) = 0; - - // Sets size to which the thumbnails should be scaled. If called after - // StartUpdating() then some thumbnails may be still scaled to the old size - // until they are updated. - virtual void SetThumbnailSize(const gfx::Size& thumbnail_size) = 0; - - // Sets ID of the hosting desktop picker dialog. The window with this ID will - // be filtered out from the list of sources. - virtual void SetViewDialogWindowId(content::DesktopMediaID::Id dialog_id) = 0; - - // Starts updating the model. The model is initially empty, so OnSourceAdded() - // notifications will be generated for each existing source as it is - // enumerated. After the initial enumeration the model will be refreshed based - // on the update period, and notifications generated only for changes in the - // model. - virtual void StartUpdating(DesktopMediaListObserver* observer) = 0; - - virtual int GetSourceCount() const = 0; - virtual const Source& GetSource(int index) const = 0; - virtual std::vector GetSources() const = 0; -}; - -#endif // CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_H_ diff --git a/chromium_src/chrome/browser/media/desktop_media_list_observer.h b/chromium_src/chrome/browser/media/desktop_media_list_observer.h deleted file mode 100644 index 34cd626bf6bfe..0000000000000 --- a/chromium_src/chrome/browser/media/desktop_media_list_observer.h +++ /dev/null @@ -1,23 +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_MEDIA_DESKTOP_MEDIA_LIST_OBSERVER_H_ -#define CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_OBSERVER_H_ - -// Interface implemented by the desktop media picker dialog to receive -// notifications about changes in DesktopMediaList. -class DesktopMediaListObserver { - public: - virtual void OnSourceAdded(int index) = 0; - virtual void OnSourceRemoved(int index) = 0; - virtual void OnSourceMoved(int old_index, int new_index) = 0; - virtual void OnSourceNameChanged(int index) = 0; - virtual void OnSourceThumbnailChanged(int index) = 0; - virtual bool OnRefreshFinished() = 0; - - protected: - virtual ~DesktopMediaListObserver() {} -}; - -#endif // CHROME_BROWSER_MEDIA_DESKTOP_MEDIA_LIST_OBSERVER_H_ diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.cc b/chromium_src/chrome/browser/media/native_desktop_media_list.cc deleted file mode 100644 index 76170a473d873..0000000000000 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.cc +++ /dev/null @@ -1,370 +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. - -#include "chrome/browser/media/native_desktop_media_list.h" - -#include -#include -#include - -#include "base/hash.h" -#include "base/logging.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/threading/sequenced_worker_pool.h" -#include "chrome/browser/media/desktop_media_list_observer.h" -#include "content/public/browser/browser_thread.h" -#include "media/base/video_util.h" -#include "third_party/libyuv/include/libyuv/scale_argb.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" -#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" -#include "third_party/webrtc/modules/desktop_capture/window_capturer.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/skia_util.h" - -using content::BrowserThread; -using content::DesktopMediaID; - -namespace { - -// Update the list every second. -const int kDefaultUpdatePeriod = 1000; - -// Returns a hash of a DesktopFrame content to detect when image for a desktop -// media source has changed. -uint32_t GetFrameHash(webrtc::DesktopFrame* frame) { - int data_size = frame->stride() * frame->size().height(); - return base::SuperFastHash(reinterpret_cast(frame->data()), data_size); -} - -gfx::ImageSkia ScaleDesktopFrame(std::unique_ptr frame, - gfx::Size size) { - gfx::Rect scaled_rect = media::ComputeLetterboxRegion( - gfx::Rect(0, 0, size.width(), size.height()), - gfx::Size(frame->size().width(), frame->size().height())); - - SkBitmap result; - result.allocN32Pixels(scaled_rect.width(), scaled_rect.height(), true); - result.lockPixels(); - - uint8* pixels_data = reinterpret_cast(result.getPixels()); - libyuv::ARGBScale(frame->data(), frame->stride(), - frame->size().width(), frame->size().height(), - pixels_data, result.rowBytes(), - scaled_rect.width(), scaled_rect.height(), - libyuv::kFilterBilinear); - - // Set alpha channel values to 255 for all pixels. - // TODO(sergeyu): Fix screen/window capturers to capture alpha channel and - // remove this code. Currently screen/window capturers (at least some - // implementations) only capture R, G and B channels and set Alpha to 0. - // crbug.com/264424 - for (int y = 0; y < result.height(); ++y) { - for (int x = 0; x < result.width(); ++x) { - pixels_data[result.rowBytes() * y + x * result.bytesPerPixel() + 3] = - 0xff; - } - } - - result.unlockPixels(); - - return gfx::ImageSkia::CreateFrom1xBitmap(result); -} - -} // namespace - -NativeDesktopMediaList::SourceDescription::SourceDescription( - DesktopMediaID id, - const base::string16& name) - : id(id), - name(name) { -} - -class NativeDesktopMediaList::Worker - : public webrtc::DesktopCapturer::Callback { - public: - Worker(base::WeakPtr media_list, - std::unique_ptr screen_capturer, - std::unique_ptr window_capturer); - ~Worker() override; - - void Refresh(const gfx::Size& thumbnail_size, - content::DesktopMediaID::Id view_dialog_id); - - private: - typedef std::map ImageHashesMap; - - // webrtc::DesktopCapturer::Callback interface. - void OnCaptureCompleted(webrtc::DesktopFrame* frame) override; - - base::WeakPtr media_list_; - - std::unique_ptr screen_capturer_; - std::unique_ptr window_capturer_; - - std::unique_ptr current_frame_; - - ImageHashesMap image_hashes_; - - DISALLOW_COPY_AND_ASSIGN(Worker); -}; - -NativeDesktopMediaList::Worker::Worker( - base::WeakPtr media_list, - std::unique_ptr screen_capturer, - std::unique_ptr window_capturer) - : media_list_(media_list), - screen_capturer_(std::move(screen_capturer)), - window_capturer_(std::move(window_capturer)) { - if (screen_capturer_) - screen_capturer_->Start(this); - if (window_capturer_) - window_capturer_->Start(this); -} - -NativeDesktopMediaList::Worker::~Worker() {} - -void NativeDesktopMediaList::Worker::Refresh( - const gfx::Size& thumbnail_size, - content::DesktopMediaID::Id view_dialog_id) { - std::vector sources; - - if (screen_capturer_) { - webrtc::ScreenCapturer::ScreenList screens; - if (screen_capturer_->GetScreenList(&screens)) { - bool mutiple_screens = screens.size() > 1; - base::string16 title; - for (size_t i = 0; i < screens.size(); ++i) { - if (mutiple_screens) { - title = base::UTF8ToUTF16("Screen " + base::IntToString(i+1)); - } else { - title = base::UTF8ToUTF16("Entire screen"); - } - sources.push_back(SourceDescription(DesktopMediaID( - DesktopMediaID::TYPE_SCREEN, screens[i].id), title)); - } - } - } - - if (window_capturer_) { - webrtc::WindowCapturer::WindowList windows; - if (window_capturer_->GetWindowList(&windows)) { - for (webrtc::WindowCapturer::WindowList::iterator it = windows.begin(); - it != windows.end(); ++it) { - // Skip the picker dialog window. - if (it->id != view_dialog_id) { - sources.push_back(SourceDescription( - DesktopMediaID(DesktopMediaID::TYPE_WINDOW, it->id), - base::UTF8ToUTF16(it->title))); - } - } - } - } - // Update list of windows before updating thumbnails. - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&NativeDesktopMediaList::OnSourcesList, - media_list_, sources)); - - ImageHashesMap new_image_hashes; - - // Get a thumbnail for each source. - for (size_t i = 0; i < sources.size(); ++i) { - SourceDescription& source = sources[i]; - switch (source.id.type) { - case DesktopMediaID::TYPE_SCREEN: - if (!screen_capturer_->SelectScreen(source.id.id)) - continue; - screen_capturer_->Capture(webrtc::DesktopRegion()); - break; - - case DesktopMediaID::TYPE_WINDOW: - if (!window_capturer_->SelectWindow(source.id.id)) - continue; - window_capturer_->Capture(webrtc::DesktopRegion()); - break; - - default: - NOTREACHED(); - } - - // Expect that DesktopCapturer to always captures frames synchronously. - // |current_frame_| may be NULL if capture failed (e.g. because window has - // been closed). - if (current_frame_) { - uint32_t frame_hash = GetFrameHash(current_frame_.get()); - new_image_hashes[source.id] = frame_hash; - - // Scale the image only if it has changed. - ImageHashesMap::iterator it = image_hashes_.find(source.id); - if (it == image_hashes_.end() || it->second != frame_hash) { - gfx::ImageSkia thumbnail = - ScaleDesktopFrame(std::move(current_frame_), thumbnail_size); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, - media_list_, i, thumbnail)); - } - } - } - - image_hashes_.swap(new_image_hashes); - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&NativeDesktopMediaList::OnRefreshFinished, media_list_)); -} - -void NativeDesktopMediaList::Worker::OnCaptureCompleted( - webrtc::DesktopFrame* frame) { - current_frame_.reset(frame); -} - -NativeDesktopMediaList::NativeDesktopMediaList( - std::unique_ptr screen_capturer, - std::unique_ptr window_capturer) - : screen_capturer_(std::move(screen_capturer)), - window_capturer_(std::move(window_capturer)), - update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), - thumbnail_size_(100, 100), - view_dialog_id_(-1), - observer_(NULL), - weak_factory_(this) { - base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool(); - capture_task_runner_ = worker_pool->GetSequencedTaskRunner( - worker_pool->GetSequenceToken()); -} - -NativeDesktopMediaList::~NativeDesktopMediaList() { - capture_task_runner_->DeleteSoon(FROM_HERE, worker_.release()); -} - -void NativeDesktopMediaList::SetUpdatePeriod(base::TimeDelta period) { - DCHECK(!observer_); - update_period_ = period; -} - -void NativeDesktopMediaList::SetThumbnailSize( - const gfx::Size& thumbnail_size) { - thumbnail_size_ = thumbnail_size; -} - -void NativeDesktopMediaList::SetViewDialogWindowId( - content::DesktopMediaID::Id dialog_id) { - view_dialog_id_ = dialog_id; -} - -void NativeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) { - DCHECK(!observer_); - DCHECK(screen_capturer_ || window_capturer_); - - observer_ = observer; - - worker_.reset(new Worker(weak_factory_.GetWeakPtr(), - std::move(screen_capturer_), - std::move(window_capturer_))); - Refresh(); -} - -int NativeDesktopMediaList::GetSourceCount() const { - return sources_.size(); -} - -const DesktopMediaList::Source& NativeDesktopMediaList::GetSource( - int index) const { - return sources_[index]; -} - -std::vector NativeDesktopMediaList::GetSources() const { - return sources_; -} - -void NativeDesktopMediaList::Refresh() { - capture_task_runner_->PostTask( - FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), - thumbnail_size_, view_dialog_id_)); -} - -void NativeDesktopMediaList::OnSourcesList( - const std::vector& new_sources) { - typedef std::set SourceSet; - SourceSet new_source_set; - for (size_t i = 0; i < new_sources.size(); ++i) { - new_source_set.insert(new_sources[i].id); - } - // Iterate through the old sources to find the removed sources. - for (size_t i = 0; i < sources_.size(); ++i) { - if (new_source_set.find(sources_[i].id) == new_source_set.end()) { - observer_->OnSourceRemoved(i); - sources_.erase(sources_.begin() + i); - --i; - } - } - // Iterate through the new sources to find the added sources. - if (new_sources.size() > sources_.size()) { - SourceSet old_source_set; - for (size_t i = 0; i < sources_.size(); ++i) { - old_source_set.insert(sources_[i].id); - } - - for (size_t i = 0; i < new_sources.size(); ++i) { - if (old_source_set.find(new_sources[i].id) == old_source_set.end()) { - sources_.insert(sources_.begin() + i, Source()); - sources_[i].id = new_sources[i].id; - sources_[i].name = new_sources[i].name; - observer_->OnSourceAdded(i); - } - } - } - DCHECK_EQ(new_sources.size(), sources_.size()); - - // Find the moved/changed sources. - size_t pos = 0; - while (pos < sources_.size()) { - if (!(sources_[pos].id == new_sources[pos].id)) { - // Find the source that should be moved to |pos|, starting from |pos + 1| - // of |sources_|, because entries before |pos| should have been sorted. - size_t old_pos = pos + 1; - for (; old_pos < sources_.size(); ++old_pos) { - if (sources_[old_pos].id == new_sources[pos].id) - break; - } - DCHECK(sources_[old_pos].id == new_sources[pos].id); - - // Move the source from |old_pos| to |pos|. - Source temp = sources_[old_pos]; - sources_.erase(sources_.begin() + old_pos); - sources_.insert(sources_.begin() + pos, temp); - - observer_->OnSourceMoved(old_pos, pos); - } - - if (sources_[pos].name != new_sources[pos].name) { - sources_[pos].name = new_sources[pos].name; - observer_->OnSourceNameChanged(pos); - } - ++pos; - } -} - -void NativeDesktopMediaList::OnSourceThumbnail( - int index, - const gfx::ImageSkia& image) { - DCHECK_LT(index, static_cast(sources_.size())); - sources_[index].thumbnail = image; - observer_->OnSourceThumbnailChanged(index); -} - -void NativeDesktopMediaList::OnRefreshFinished() { - // Give a chance to the observer to stop the refresh work. - bool is_continue = observer_->OnRefreshFinished(); - if (is_continue) { - BrowserThread::PostDelayedTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&NativeDesktopMediaList::Refresh, - weak_factory_.GetWeakPtr()), - update_period_); - } -} diff --git a/chromium_src/chrome/browser/media/native_desktop_media_list.h b/chromium_src/chrome/browser/media/native_desktop_media_list.h deleted file mode 100644 index 9814849a290b5..0000000000000 --- a/chromium_src/chrome/browser/media/native_desktop_media_list.h +++ /dev/null @@ -1,99 +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_MEDIA_NATIVE_DESKTOP_MEDIA_LIST_H_ -#define CHROME_BROWSER_MEDIA_NATIVE_DESKTOP_MEDIA_LIST_H_ - -#include "base/memory/weak_ptr.h" -#include "base/sequenced_task_runner.h" -#include "chrome/browser/media/desktop_media_list.h" -#include "content/public/browser/desktop_media_id.h" -#include "ui/gfx/image/image_skia.h" - -namespace webrtc { -class ScreenCapturer; -class WindowCapturer; -} - -// Implementation of DesktopMediaList that shows native screens and -// native windows. -class NativeDesktopMediaList : public DesktopMediaList { - public: - // Caller may pass NULL for either of the arguments in case when only some - // types of sources the model should be populated with (e.g. it will only - // contain windows, if |screen_capturer| is NULL). - NativeDesktopMediaList( - std::unique_ptr screen_capturer, - std::unique_ptr window_capturer); - ~NativeDesktopMediaList() override; - - // DesktopMediaList interface. - void SetUpdatePeriod(base::TimeDelta period) override; - void SetThumbnailSize(const gfx::Size& thumbnail_size) override; - void StartUpdating(DesktopMediaListObserver* observer) override; - int GetSourceCount() const override; - const Source& GetSource(int index) const override; - std::vector GetSources() const override; - void SetViewDialogWindowId(content::DesktopMediaID::Id dialog_id) override; - - private: - class Worker; - friend class Worker; - - // Struct used to represent sources list the model gets from the Worker. - struct SourceDescription { - SourceDescription(content::DesktopMediaID id, const base::string16& name); - - content::DesktopMediaID id; - base::string16 name; - }; - - // Order comparator for sources. Used to sort list of sources. - static bool CompareSources(const SourceDescription& a, - const SourceDescription& b); - - // Post a task for the |worker_| to update list of windows and get thumbnails. - void Refresh(); - - // Called by |worker_| to refresh the model. First it posts tasks for - // OnSourcesList() with the fresh list of sources, then follows with - // OnSourceThumbnail() for each changed thumbnail and then calls - // OnRefreshFinished() at the end. - void OnSourcesList(const std::vector& sources); - void OnSourceThumbnail(int index, const gfx::ImageSkia& thumbnail); - void OnRefreshFinished(); - - // Capturers specified in SetCapturers() and passed to the |worker_| later. - std::unique_ptr screen_capturer_; - std::unique_ptr window_capturer_; - - // Time interval between mode updates. - base::TimeDelta update_period_; - - // Size of thumbnails generated by the model. - gfx::Size thumbnail_size_; - - // ID of the hosting dialog. - content::DesktopMediaID::Id view_dialog_id_; - - // The observer passed to StartUpdating(). - DesktopMediaListObserver* observer_; - - // Task runner used for the |worker_|. - scoped_refptr capture_task_runner_; - - // An object that does all the work of getting list of sources on a background - // thread (see |capture_task_runner_|). Destroyed on |capture_task_runner_| - // after the model is destroyed. - std::unique_ptr worker_; - - // Current list of sources. - std::vector sources_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(NativeDesktopMediaList); -}; - -#endif // CHROME_BROWSER_MEDIA_NATIVE_DESKTOP_MEDIA_LIST_H_ diff --git a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc deleted file mode 100644 index 0d23a7c6d5a58..0000000000000 --- a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.cc +++ /dev/null @@ -1,498 +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. - -#include "chrome/browser/printing/pdf_to_emf_converter.h" - -#include - -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/logging.h" -#include "chrome/common/chrome_utility_messages.h" -#include "chrome/common/print_messages.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/child_process_data.h" -#include "content/public/browser/utility_process_host.h" -#include "content/public/browser/utility_process_host_client.h" -#include "printing/emf_win.h" -#include "printing/pdf_render_settings.h" - -namespace printing { - -namespace { - -using content::BrowserThread; - -class PdfToEmfConverterImpl; - -// Allows to delete temporary directory after all temporary files created inside -// are closed. Windows cannot delete directory with opened files. Directory is -// used to store PDF and metafiles. PDF should be gone by the time utility -// process exits. Metafiles should be gone when all LazyEmf destroyed. -class RefCountedTempDir - : public base::RefCountedThreadSafe { - public: - RefCountedTempDir() { ignore_result(temp_dir_.CreateUniqueTempDir()); } - bool IsValid() const { return temp_dir_.IsValid(); } - const base::FilePath& GetPath() const { return temp_dir_.path(); } - - private: - friend struct BrowserThread::DeleteOnThread; - friend class base::DeleteHelper; - ~RefCountedTempDir() {} - - base::ScopedTempDir temp_dir_; - DISALLOW_COPY_AND_ASSIGN(RefCountedTempDir); -}; - -typedef std::unique_ptr - ScopedTempFile; - -// Wrapper for Emf to keep only file handle in memory, and load actual data only -// on playback. Emf::InitFromFile() can play metafile directly from disk, but it -// can't open file handles. We need file handles to reliably delete temporary -// files, and to efficiently interact with utility process. -class LazyEmf : public MetafilePlayer { - public: - LazyEmf(const scoped_refptr& temp_dir, ScopedTempFile file) - : temp_dir_(temp_dir), file_(std::move(file)) {} - virtual ~LazyEmf() { Close(); } - - virtual bool SafePlayback(HDC hdc) const override; - virtual bool SaveTo(base::File* file) const override; - - private: - void Close() const; - bool LoadEmf(Emf* emf) const; - - mutable scoped_refptr temp_dir_; - mutable ScopedTempFile file_; // Mutable because of consts in base class. - - DISALLOW_COPY_AND_ASSIGN(LazyEmf); -}; - -// Converts PDF into EMF. -// Class uses 3 threads: UI, IO and FILE. -// Internal workflow is following: -// 1. Create instance on the UI thread. (files_, settings_,) -// 2. Create pdf file on the FILE thread. -// 3. Start utility process and start conversion on the IO thread. -// 4. Utility process returns page count. -// 5. For each page: -// 1. Clients requests page with file handle to a temp file. -// 2. Utility converts the page, save it to the file and reply. -// -// All these steps work sequentially, so no data should be accessed -// simultaneously by several threads. -class PdfToEmfUtilityProcessHostClient - : public content::UtilityProcessHostClient { - public: - PdfToEmfUtilityProcessHostClient( - base::WeakPtr converter, - const PdfRenderSettings& settings); - - void Start(const scoped_refptr& data, - const PdfToEmfConverter::StartCallback& start_callback); - - void GetPage(int page_number, - const PdfToEmfConverter::GetPageCallback& get_page_callback); - - void Stop(); - - // UtilityProcessHostClient implementation. - virtual void OnProcessCrashed(int exit_code) override; - virtual void OnProcessLaunchFailed(int exit_code) override; - virtual bool OnMessageReceived(const IPC::Message& message) override; - - private: - class GetPageCallbackData { - MOVE_ONLY_TYPE_FOR_CPP_03(GetPageCallbackData); - - public: - GetPageCallbackData(int page_number, - PdfToEmfConverter::GetPageCallback callback) - : page_number_(page_number), callback_(callback) {} - - GetPageCallbackData(GetPageCallbackData&& other) { - *this = std::move(other); - } - - GetPageCallbackData& operator=(GetPageCallbackData&& rhs) { - page_number_ = rhs.page_number_; - callback_ = rhs.callback_; - emf_ = std::move(rhs.emf_); - return *this; - } - - int page_number() const { return page_number_; } - const PdfToEmfConverter::GetPageCallback& callback() const { - return callback_; - } - ScopedTempFile TakeEmf() { return std::move(emf_); } - void set_emf(ScopedTempFile emf) { emf_ = std::move(emf); } - - private: - int page_number_; - PdfToEmfConverter::GetPageCallback callback_; - ScopedTempFile emf_; - }; - - virtual ~PdfToEmfUtilityProcessHostClient(); - - bool Send(IPC::Message* msg); - - // Message handlers. - void OnProcessStarted(); - void OnPageCount(int page_count); - void OnPageDone(bool success, float scale_factor); - - void OnFailed(); - void OnTempPdfReady(ScopedTempFile pdf); - void OnTempEmfReady(GetPageCallbackData* callback_data, ScopedTempFile emf); - - scoped_refptr temp_dir_; - - // Used to suppress callbacks after PdfToEmfConverterImpl is deleted. - base::WeakPtr converter_; - PdfRenderSettings settings_; - scoped_refptr data_; - - // Document loaded callback. - PdfToEmfConverter::StartCallback start_callback_; - - // Process host for IPC. - base::WeakPtr utility_process_host_; - - // Queue of callbacks for GetPage() requests. Utility process should reply - // with PageDone in the same order as requests were received. - // Use containers that keeps element pointers valid after push() and pop(). - typedef std::queue GetPageCallbacks; - GetPageCallbacks get_page_callbacks_; - - DISALLOW_COPY_AND_ASSIGN(PdfToEmfUtilityProcessHostClient); -}; - -class PdfToEmfConverterImpl : public PdfToEmfConverter { - public: - PdfToEmfConverterImpl(); - - virtual ~PdfToEmfConverterImpl(); - - virtual void Start(const scoped_refptr& data, - const PdfRenderSettings& conversion_settings, - const StartCallback& start_callback) override; - - virtual void GetPage(int page_number, - const GetPageCallback& get_page_callback) override; - - // Helps to cancel callbacks if this object is destroyed. - void RunCallback(const base::Closure& callback); - - private: - scoped_refptr utility_client_; - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(PdfToEmfConverterImpl); -}; - -ScopedTempFile CreateTempFile(scoped_refptr* temp_dir) { - if (!temp_dir->get()) - *temp_dir = new RefCountedTempDir(); - ScopedTempFile file; - if (!(*temp_dir)->IsValid()) - return file; - base::FilePath path; - if (!base::CreateTemporaryFileInDir((*temp_dir)->GetPath(), &path)) - return file; - file.reset(new base::File(path, - base::File::FLAG_CREATE_ALWAYS | - base::File::FLAG_WRITE | - base::File::FLAG_READ | - base::File::FLAG_DELETE_ON_CLOSE | - base::File::FLAG_TEMPORARY)); - if (!file->IsValid()) - file.reset(); - return file; -} - -ScopedTempFile CreateTempPdfFile( - const scoped_refptr& data, - scoped_refptr* temp_dir) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); - - ScopedTempFile pdf_file = CreateTempFile(temp_dir); - if (!pdf_file || - static_cast(data->size()) != - pdf_file->WriteAtCurrentPos(data->front_as(), data->size())) { - pdf_file.reset(); - } - pdf_file->Seek(base::File::FROM_BEGIN, 0); - return pdf_file; -} - -bool LazyEmf::SafePlayback(HDC hdc) const { - Emf emf; - bool result = LoadEmf(&emf) && emf.SafePlayback(hdc); - // TODO(vitalybuka): Fix destruction of metafiles. For some reasons - // instances of Emf are not deleted. crbug.com/411683 - // It's known that the Emf going to be played just once to a printer. So just - // release file here. - Close(); - return result; -} - -bool LazyEmf::SaveTo(base::File* file) const { - Emf emf; - return LoadEmf(&emf) && emf.SaveTo(file); -} - -void LazyEmf::Close() const { - file_.reset(); - temp_dir_ = NULL; -} - -bool LazyEmf::LoadEmf(Emf* emf) const { - file_->Seek(base::File::FROM_BEGIN, 0); - int64_t size = file_->GetLength(); - if (size <= 0) - return false; - std::vector data(size); - if (file_->ReadAtCurrentPos(data.data(), data.size()) != size) - return false; - return emf->InitFromData(data.data(), data.size()); -} - -PdfToEmfUtilityProcessHostClient::PdfToEmfUtilityProcessHostClient( - base::WeakPtr converter, - const PdfRenderSettings& settings) - : converter_(converter), settings_(settings) { -} - -PdfToEmfUtilityProcessHostClient::~PdfToEmfUtilityProcessHostClient() { -} - -void PdfToEmfUtilityProcessHostClient::Start( - const scoped_refptr& data, - const PdfToEmfConverter::StartCallback& start_callback) { - if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { - BrowserThread::PostTask(BrowserThread::IO, - FROM_HERE, - base::Bind(&PdfToEmfUtilityProcessHostClient::Start, - this, - data, - start_callback)); - return; - } - data_ = data; - - // Store callback before any OnFailed() call to make it called on failure. - start_callback_ = start_callback; - - // NOTE: This process _must_ be sandboxed, otherwise the pdf dll will load - // gdiplus.dll, change how rendering happens, and not be able to correctly - // generate when sent to a metafile DC. - utility_process_host_ = - content::UtilityProcessHost::Create( - this, base::MessageLoop::current()->task_runner())->AsWeakPtr(); - if (!utility_process_host_) - return OnFailed(); - // Should reply with OnProcessStarted(). - Send(new ChromeUtilityMsg_StartupPing); -} - -void PdfToEmfUtilityProcessHostClient::OnProcessStarted() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!utility_process_host_) - return OnFailed(); - - scoped_refptr data = data_; - data_ = NULL; - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&CreateTempPdfFile, data, &temp_dir_), - base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempPdfReady, this)); -} - -void PdfToEmfUtilityProcessHostClient::OnTempPdfReady(ScopedTempFile pdf) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!utility_process_host_ || !pdf) - return OnFailed(); - // Should reply with OnPageCount(). - Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles( - IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false), - settings_)); -} - -void PdfToEmfUtilityProcessHostClient::OnPageCount(int page_count) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (start_callback_.is_null()) - return OnFailed(); - BrowserThread::PostTask(BrowserThread::UI, - FROM_HERE, - base::Bind(&PdfToEmfConverterImpl::RunCallback, - converter_, - base::Bind(start_callback_, page_count))); - start_callback_.Reset(); -} - -void PdfToEmfUtilityProcessHostClient::GetPage( - int page_number, - const PdfToEmfConverter::GetPageCallback& get_page_callback) { - if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&PdfToEmfUtilityProcessHostClient::GetPage, - this, - page_number, - get_page_callback)); - return; - } - - // Store callback before any OnFailed() call to make it called on failure. - get_page_callbacks_.push(GetPageCallbackData(page_number, get_page_callback)); - - if (!utility_process_host_) - return OnFailed(); - - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&CreateTempFile, &temp_dir_), - base::Bind(&PdfToEmfUtilityProcessHostClient::OnTempEmfReady, - this, - &get_page_callbacks_.back())); -} - -void PdfToEmfUtilityProcessHostClient::OnTempEmfReady( - GetPageCallbackData* callback_data, - ScopedTempFile emf) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!utility_process_host_ || !emf) - return OnFailed(); - IPC::PlatformFileForTransit transit = - IPC::GetPlatformFileForTransit(emf->GetPlatformFile(), false); - callback_data->set_emf(std::move(emf)); - // Should reply with OnPageDone(). - Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage( - callback_data->page_number(), transit)); -} - -void PdfToEmfUtilityProcessHostClient::OnPageDone(bool success, - float scale_factor) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (get_page_callbacks_.empty()) - return OnFailed(); - GetPageCallbackData& data = get_page_callbacks_.front(); - std::unique_ptr emf; - - if (success) { - ScopedTempFile temp_emf = data.TakeEmf(); - if (!temp_emf) // Unexpected message from utility process. - return OnFailed(); - emf.reset(new LazyEmf(temp_dir_, std::move(temp_emf))); - } - - BrowserThread::PostTask(BrowserThread::UI, - FROM_HERE, - base::Bind(&PdfToEmfConverterImpl::RunCallback, - converter_, - base::Bind(data.callback(), - data.page_number(), - scale_factor, - base::Passed(&emf)))); - get_page_callbacks_.pop(); -} - -void PdfToEmfUtilityProcessHostClient::Stop() { - if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&PdfToEmfUtilityProcessHostClient::Stop, this)); - return; - } - Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop()); -} - -void PdfToEmfUtilityProcessHostClient::OnProcessCrashed(int exit_code) { - OnFailed(); -} - -void PdfToEmfUtilityProcessHostClient::OnProcessLaunchFailed(int exit_code) { - OnFailed(); -} - -bool PdfToEmfUtilityProcessHostClient::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PdfToEmfUtilityProcessHostClient, message) - IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted, OnProcessStarted) - IPC_MESSAGE_HANDLER( - ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, OnPageCount) - IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, - OnPageDone) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -bool PdfToEmfUtilityProcessHostClient::Send(IPC::Message* msg) { - if (utility_process_host_) - return utility_process_host_->Send(msg); - delete msg; - return false; -} - -void PdfToEmfUtilityProcessHostClient::OnFailed() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (!start_callback_.is_null()) - OnPageCount(0); - while (!get_page_callbacks_.empty()) - OnPageDone(false, 0.0f); - utility_process_host_.reset(); -} - -PdfToEmfConverterImpl::PdfToEmfConverterImpl() : weak_ptr_factory_(this) { -} - -PdfToEmfConverterImpl::~PdfToEmfConverterImpl() { - if (utility_client_.get()) - utility_client_->Stop(); -} - -void PdfToEmfConverterImpl::Start( - const scoped_refptr& data, - const PdfRenderSettings& conversion_settings, - const StartCallback& start_callback) { - DCHECK(!utility_client_.get()); - utility_client_ = new PdfToEmfUtilityProcessHostClient( - weak_ptr_factory_.GetWeakPtr(), conversion_settings); - utility_client_->Start(data, start_callback); -} - -void PdfToEmfConverterImpl::GetPage(int page_number, - const GetPageCallback& get_page_callback) { - utility_client_->GetPage(page_number, get_page_callback); -} - -void PdfToEmfConverterImpl::RunCallback(const base::Closure& callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - callback.Run(); -} - -} // namespace - -PdfToEmfConverter::~PdfToEmfConverter() { -} - -// static -std::unique_ptr PdfToEmfConverter::CreateDefault() { - return std::unique_ptr(new PdfToEmfConverterImpl()); -} - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h b/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h deleted file mode 100644 index bd292dd476a10..0000000000000 --- a/chromium_src/chrome/browser/printing/pdf_to_emf_converter.h +++ /dev/null @@ -1,49 +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. - -#ifndef CHROME_BROWSER_PRINTING_PDF_TO_EMF_CONVERTER_H_ -#define CHROME_BROWSER_PRINTING_PDF_TO_EMF_CONVERTER_H_ - -#include - -#include "base/callback.h" -#include "base/memory/ref_counted_memory.h" - -namespace base { -class FilePath; -} - -namespace printing { - -class MetafilePlayer; -class PdfRenderSettings; - -class PdfToEmfConverter { - public: - typedef base::Callback StartCallback; - typedef base::Callback emf)> GetPageCallback; - - virtual ~PdfToEmfConverter(); - - static std::unique_ptr CreateDefault(); - - // Starts conversion of PDF provided as |data|. Calls |start_callback| - // with positive |page_count|. |page_count| is 0 if initialization failed. - virtual void Start(const scoped_refptr& data, - const PdfRenderSettings& conversion_settings, - const StartCallback& start_callback) = 0; - - // Requests conversion of the page. |page_number| is 0-base page number in - // PDF provided in Start() call. - // Calls |get_page_callback| after conversion. |emf| of callback in not NULL - // if conversion succeeded. - virtual void GetPage(int page_number, - const GetPageCallback& get_page_callback) = 0; -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PDF_TO_EMF_CONVERTER_H_ diff --git a/chromium_src/chrome/browser/printing/print_job.cc b/chromium_src/chrome/browser/printing/print_job.cc deleted file mode 100644 index 87971055e68f4..0000000000000 --- a/chromium_src/chrome/browser/printing/print_job.cc +++ /dev/null @@ -1,463 +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/printing/print_job.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/message_loop/message_loop.h" -#include "base/threading/thread_restrictions.h" -#include "base/threading/worker_pool.h" -#include "base/timer/timer.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/printing/print_job_worker.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_service.h" -#include "printing/printed_document.h" -#include "printing/printed_page.h" - -#if defined(OS_WIN) -#include "chrome/browser/printing/pdf_to_emf_converter.h" -#include "printing/pdf_render_settings.h" -#endif - - -using base::TimeDelta; - -namespace { - -// Helper function to ensure |owner| is valid until at least |callback| returns. -void HoldRefCallback(const scoped_refptr& owner, - const base::Closure& callback) { - callback.Run(); -} - -} // namespace - -namespace printing { - -PrintJob::PrintJob() - : source_(NULL), - worker_(), - settings_(), - is_job_pending_(false), - is_canceling_(false), - quit_factory_(this) { - // This is normally a UI message loop, but in unit tests, the message loop is - // of the 'default' type. - DCHECK(base::MessageLoopForUI::IsCurrent() || - base::MessageLoop::current()->type() == - base::MessageLoop::TYPE_DEFAULT); -} - -PrintJob::~PrintJob() { - // The job should be finished (or at least canceled) when it is destroyed. - DCHECK(!is_job_pending_); - DCHECK(!is_canceling_); - DCHECK(!worker_ || !worker_->IsRunning()); - DCHECK(RunsTasksOnCurrentThread()); -} - -void PrintJob::Initialize(PrintJobWorkerOwner* job, - PrintedPagesSource* source, - int page_count) { - DCHECK(!source_); - DCHECK(!worker_.get()); - DCHECK(!is_job_pending_); - DCHECK(!is_canceling_); - DCHECK(!document_.get()); - source_ = source; - worker_.reset(job->DetachWorker(this)); - settings_ = job->settings(); - - PrintedDocument* new_doc = - new PrintedDocument(settings_, - source_, - job->cookie(), - content::BrowserThread::GetBlockingPool()); - new_doc->set_page_count(page_count); - UpdatePrintedDocument(new_doc); - - // Don't forget to register to our own messages. - registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, - content::Source(this)); -} - -void PrintJob::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK(RunsTasksOnCurrentThread()); - switch (type) { - case chrome::NOTIFICATION_PRINT_JOB_EVENT: { - OnNotifyPrintJobEvent(*content::Details(details).ptr()); - break; - } - default: { - break; - } - } -} - -void PrintJob::GetSettingsDone(const PrintSettings& new_settings, - PrintingContext::Result result) { - NOTREACHED(); -} - -PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) { - NOTREACHED(); - return NULL; -} - -const PrintSettings& PrintJob::settings() const { - return settings_; -} - -int PrintJob::cookie() const { - if (!document_.get()) - // Always use an invalid cookie in this case. - return 0; - return document_->cookie(); -} - -void PrintJob::StartPrinting() { - DCHECK(RunsTasksOnCurrentThread()); - DCHECK(worker_->IsRunning()); - DCHECK(!is_job_pending_); - if (!worker_->IsRunning() || is_job_pending_) - return; - - // Real work is done in PrintJobWorker::StartPrinting(). - worker_->PostTask(FROM_HERE, - base::Bind(&HoldRefCallback, - make_scoped_refptr(this), - base::Bind(&PrintJobWorker::StartPrinting, - base::Unretained(worker_.get()), - base::RetainedRef(document_)))); - // Set the flag right now. - is_job_pending_ = true; - - // Tell everyone! - scoped_refptr details( - new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), NULL)); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PRINT_JOB_EVENT, - content::Source(this), - content::Details(details.get())); -} - -void PrintJob::Stop() { - DCHECK(RunsTasksOnCurrentThread()); - - if (quit_factory_.HasWeakPtrs()) { - // In case we're running a nested message loop to wait for a job to finish, - // and we finished before the timeout, quit the nested loop right away. - Quit(); - quit_factory_.InvalidateWeakPtrs(); - } - - // Be sure to live long enough. - scoped_refptr handle(this); - - if (worker_->IsRunning()) { - ControlledWorkerShutdown(); - } else { - // Flush the cached document. - UpdatePrintedDocument(NULL); - } -} - -void PrintJob::Cancel() { - if (is_canceling_) - return; - is_canceling_ = true; - - // Be sure to live long enough. - scoped_refptr handle(this); - - DCHECK(RunsTasksOnCurrentThread()); - if (worker_ && worker_->IsRunning()) { - // Call this right now so it renders the context invalid. Do not use - // InvokeLater since it would take too much time. - worker_->Cancel(); - } - // Make sure a Cancel() is broadcast. - scoped_refptr details( - new JobEventDetails(JobEventDetails::FAILED, NULL, NULL)); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PRINT_JOB_EVENT, - content::Source(this), - content::Details(details.get())); - Stop(); - is_canceling_ = false; -} - -bool PrintJob::FlushJob(base::TimeDelta timeout) { - // Make sure the object outlive this message loop. - scoped_refptr handle(this); - - base::MessageLoop::current()->PostDelayedTask(FROM_HERE, - base::Bind(&PrintJob::Quit, quit_factory_.GetWeakPtr()), timeout); - - base::MessageLoop::ScopedNestableTaskAllower allow( - base::MessageLoop::current()); - base::MessageLoop::current()->Run(); - - return true; -} - -void PrintJob::DisconnectSource() { - source_ = NULL; - if (document_.get()) - document_->DisconnectSource(); -} - -bool PrintJob::is_job_pending() const { - return is_job_pending_; -} - -PrintedDocument* PrintJob::document() const { - return document_.get(); -} - -#if defined(OS_WIN) - -class PrintJob::PdfToEmfState { - public: - PdfToEmfState(const gfx::Size& page_size, const gfx::Rect& content_area) - : page_count_(0), - current_page_(0), - pages_in_progress_(0), - page_size_(page_size), - content_area_(content_area), - converter_(PdfToEmfConverter::CreateDefault()) {} - - void Start(const scoped_refptr& data, - const PdfRenderSettings& conversion_settings, - const PdfToEmfConverter::StartCallback& start_callback) { - converter_->Start(data, conversion_settings, start_callback); - } - - void GetMorePages( - const PdfToEmfConverter::GetPageCallback& get_page_callback) { - const int kMaxNumberOfTempFilesPerDocument = 3; - while (pages_in_progress_ < kMaxNumberOfTempFilesPerDocument && - current_page_ < page_count_) { - ++pages_in_progress_; - converter_->GetPage(current_page_++, get_page_callback); - } - } - - void OnPageProcessed( - const PdfToEmfConverter::GetPageCallback& get_page_callback) { - --pages_in_progress_; - GetMorePages(get_page_callback); - // Release converter if we don't need this any more. - if (!pages_in_progress_ && current_page_ >= page_count_) - converter_.reset(); - } - - void set_page_count(int page_count) { page_count_ = page_count; } - gfx::Size page_size() const { return page_size_; } - gfx::Rect content_area() const { return content_area_; } - - private: - int page_count_; - int current_page_; - int pages_in_progress_; - gfx::Size page_size_; - gfx::Rect content_area_; - std::unique_ptr converter_; -}; - -void PrintJob::StartPdfToEmfConversion( - const scoped_refptr& bytes, - const gfx::Size& page_size, - const gfx::Rect& content_area) { - DCHECK(!ptd_to_emf_state_.get()); - ptd_to_emf_state_.reset(new PdfToEmfState(page_size, content_area)); - const int kPrinterDpi = settings().dpi(); - ptd_to_emf_state_->Start( - bytes, - printing::PdfRenderSettings(content_area, kPrinterDpi, true), - base::Bind(&PrintJob::OnPdfToEmfStarted, this)); -} - -void PrintJob::OnPdfToEmfStarted(int page_count) { - if (page_count <= 0) { - ptd_to_emf_state_.reset(); - Cancel(); - return; - } - ptd_to_emf_state_->set_page_count(page_count); - ptd_to_emf_state_->GetMorePages( - base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); -} - -void PrintJob::OnPdfToEmfPageConverted(int page_number, - float scale_factor, - std::unique_ptr emf) { - DCHECK(ptd_to_emf_state_); - if (!document_.get() || !emf) { - ptd_to_emf_state_.reset(); - Cancel(); - return; - } - - // Update the rendered document. It will send notifications to the listener. - document_->SetPage(page_number, - std::move(emf), - scale_factor, - ptd_to_emf_state_->page_size(), - ptd_to_emf_state_->content_area()); - - ptd_to_emf_state_->GetMorePages( - base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); -} - -#endif // OS_WIN - -void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) { - if (document_.get() == new_document) - return; - - document_ = new_document; - - if (document_.get()) { - settings_ = document_->settings(); - } - - if (worker_) { - DCHECK(!is_job_pending_); - // Sync the document with the worker. - worker_->PostTask(FROM_HERE, - base::Bind(&HoldRefCallback, - make_scoped_refptr(this), - base::Bind(&PrintJobWorker::OnDocumentChanged, - base::Unretained(worker_.get()), - base::RetainedRef(document_)))); - } -} - -void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) { - switch (event_details.type()) { - case JobEventDetails::FAILED: { - settings_.Clear(); - // No need to cancel since the worker already canceled itself. - Stop(); - break; - } - case JobEventDetails::USER_INIT_DONE: - case JobEventDetails::DEFAULT_INIT_DONE: - case JobEventDetails::USER_INIT_CANCELED: { - DCHECK_EQ(event_details.document(), document_.get()); - break; - } - case JobEventDetails::NEW_DOC: - case JobEventDetails::NEW_PAGE: - case JobEventDetails::JOB_DONE: - case JobEventDetails::ALL_PAGES_REQUESTED: { - // Don't care. - break; - } - case JobEventDetails::DOC_DONE: { - // This will call Stop() and broadcast a JOB_DONE message. - base::MessageLoop::current()->PostTask( - FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this)); - break; - } - case JobEventDetails::PAGE_DONE: -#if defined(OS_WIN) - ptd_to_emf_state_->OnPageProcessed( - base::Bind(&PrintJob::OnPdfToEmfPageConverted, this)); -#endif // OS_WIN - break; - default: { - NOTREACHED(); - break; - } - } -} - -void PrintJob::OnDocumentDone() { - // Be sure to live long enough. The instance could be destroyed by the - // JOB_DONE broadcast. - scoped_refptr handle(this); - - // Stop the worker thread. - Stop(); - - scoped_refptr details( - new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), NULL)); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PRINT_JOB_EVENT, - content::Source(this), - content::Details(details.get())); -} - -void PrintJob::ControlledWorkerShutdown() { - DCHECK(RunsTasksOnCurrentThread()); - - // The deadlock this code works around is specific to window messaging on - // Windows, so we aren't likely to need it on any other platforms. -#if defined(OS_WIN) - // We could easily get into a deadlock case if worker_->Stop() is used; the - // printer driver created a window as a child of the browser window. By - // canceling the job, the printer driver initiated dialog box is destroyed, - // which sends a blocking message to its parent window. If the browser window - // thread is not processing messages, a deadlock occurs. - // - // This function ensures that the dialog box will be destroyed in a timely - // manner by the mere fact that the thread will terminate. So the potential - // deadlock is eliminated. - worker_->StopSoon(); - - // Delay shutdown until the worker terminates. We want this code path - // to wait on the thread to quit before continuing. - if (worker_->IsRunning()) { - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&PrintJob::ControlledWorkerShutdown, this), - base::TimeDelta::FromMilliseconds(100)); - return; - } -#endif - - - // Now make sure the thread object is cleaned up. Do this on a worker - // thread because it may block. - base::WorkerPool::PostTaskAndReply( - FROM_HERE, - base::Bind(&PrintJobWorker::Stop, base::Unretained(worker_.get())), - base::Bind(&PrintJob::HoldUntilStopIsCalled, this), - false); - - is_job_pending_ = false; - registrar_.RemoveAll(); - UpdatePrintedDocument(NULL); -} - -void PrintJob::HoldUntilStopIsCalled() { -} - -void PrintJob::Quit() { - base::MessageLoop::current()->QuitWhenIdle(); -} - -// Takes settings_ ownership and will be deleted in the receiving thread. -JobEventDetails::JobEventDetails(Type type, - PrintedDocument* document, - PrintedPage* page) - : document_(document), - page_(page), - type_(type) { -} - -JobEventDetails::~JobEventDetails() { -} - -PrintedDocument* JobEventDetails::document() const { return document_.get(); } - -PrintedPage* JobEventDetails::page() const { return page_.get(); } - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_job.h b/chromium_src/chrome/browser/printing/print_job.h deleted file mode 100644 index 420622a7e9686..0000000000000 --- a/chromium_src/chrome/browser/printing/print_job.h +++ /dev/null @@ -1,225 +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_PRINTING_PRINT_JOB_H_ -#define CHROME_BROWSER_PRINTING_PRINT_JOB_H_ - -#include - -#include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" -#include "chrome/browser/printing/print_job_worker_owner.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" - -class Thread; - -namespace base { -class RefCountedMemory; -} - -namespace printing { - -class JobEventDetails; -class MetafilePlayer; -class PdfToEmfConverter; -class PrintJobWorker; -class PrintedDocument; -class PrintedPage; -class PrintedPagesSource; -class PrinterQuery; - -// Manages the print work for a specific document. Talks to the printer through -// PrintingContext through PrintJobWorker. Hides access to PrintingContext in a -// worker thread so the caller never blocks. PrintJob will send notifications on -// any state change. While printing, the PrintJobManager instance keeps a -// reference to the job to be sure it is kept alive. All the code in this class -// runs in the UI thread. -class PrintJob : public PrintJobWorkerOwner, - public content::NotificationObserver { - public: - // Create a empty PrintJob. When initializing with this constructor, - // post-constructor initialization must be done with Initialize(). - PrintJob(); - - // Grabs the ownership of the PrintJobWorker from another job, which is - // usually a PrinterQuery. Set the expected page count of the print job. - void Initialize(PrintJobWorkerOwner* job, PrintedPagesSource* source, - int page_count); - - // content::NotificationObserver implementation. - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - // PrintJobWorkerOwner implementation. - virtual void GetSettingsDone(const PrintSettings& new_settings, - PrintingContext::Result result) override; - virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) override; - virtual const PrintSettings& settings() const override; - virtual int cookie() const override; - - // Starts the actual printing. Signals the worker that it should begin to - // spool as soon as data is available. - void StartPrinting(); - - // Asks for the worker thread to finish its queued tasks and disconnects the - // delegate object. The PrintJobManager will remove its reference. This may - // have the side-effect of destroying the object if the caller doesn't have a - // handle to the object. Use PrintJob::is_stopped() to check whether the - // worker thread has actually stopped. - void Stop(); - - // Cancels printing job and stops the worker thread. Takes effect immediately. - void Cancel(); - - // Synchronously wait for the job to finish. It is mainly useful when the - // process is about to be shut down and we're waiting for the spooler to eat - // our data. - bool FlushJob(base::TimeDelta timeout); - - // Disconnects the PrintedPage source (PrintedPagesSource). It is done when - // the source is being destroyed. - void DisconnectSource(); - - // Returns true if the print job is pending, i.e. between a StartPrinting() - // and the end of the spooling. - bool is_job_pending() const; - - // Access the current printed document. Warning: may be NULL. - PrintedDocument* document() const; - -#if defined(OS_WIN) - void StartPdfToEmfConversion( - const scoped_refptr& bytes, - const gfx::Size& page_size, - const gfx::Rect& content_area); - - void OnPdfToEmfStarted(int page_count); - void OnPdfToEmfPageConverted(int page_number, - float scale_factor, - std::unique_ptr emf); - -#endif // OS_WIN - - protected: - virtual ~PrintJob(); - - private: - // Updates document_ to a new instance. - void UpdatePrintedDocument(PrintedDocument* new_document); - - // Processes a NOTIFY_PRINT_JOB_EVENT notification. - void OnNotifyPrintJobEvent(const JobEventDetails& event_details); - - // Releases the worker thread by calling Stop(), then broadcasts a JOB_DONE - // notification. - void OnDocumentDone(); - - // Terminates the worker thread in a very controlled way, to work around any - // eventual deadlock. - void ControlledWorkerShutdown(); - - // Called at shutdown when running a nested message loop. - void Quit(); - - void HoldUntilStopIsCalled(); - - content::NotificationRegistrar registrar_; - - // Source that generates the PrintedPage's (i.e. a WebContents). It will be - // set back to NULL if the source is deleted before this object. - PrintedPagesSource* source_; - - // All the UI is done in a worker thread because many Win32 print functions - // are blocking and enters a message loop without your consent. There is one - // worker thread per print job. - std::unique_ptr worker_; - - // Cache of the print context settings for access in the UI thread. - PrintSettings settings_; - - // The printed document. - scoped_refptr document_; - - // Is the worker thread printing. - bool is_job_pending_; - - // Is Canceling? If so, try to not cause recursion if on FAILED notification, - // the notified calls Cancel() again. - bool is_canceling_; - -#if defined(OS_WIN) - class PdfToEmfState; - std::unique_ptr ptd_to_emf_state_; -#endif // OS_WIN - - // Used at shutdown so that we can quit a nested message loop. - base::WeakPtrFactory quit_factory_; - - DISALLOW_COPY_AND_ASSIGN(PrintJob); -}; - -// Details for a NOTIFY_PRINT_JOB_EVENT notification. The members may be NULL. -class JobEventDetails : public base::RefCountedThreadSafe { - public: - // Event type. - enum Type { - // Print... dialog box has been closed with OK button. - USER_INIT_DONE, - - // Print... dialog box has been closed with CANCEL button. - USER_INIT_CANCELED, - - // An automated initialization has been done, e.g. Init(false, NULL). - DEFAULT_INIT_DONE, - - // A new document started printing. - NEW_DOC, - - // A new page started printing. - NEW_PAGE, - - // A page is done printing. - PAGE_DONE, - - // A document is done printing. The worker thread is still alive. Warning: - // not a good moment to release the handle to PrintJob. - DOC_DONE, - - // The worker thread is finished. A good moment to release the handle to - // PrintJob. - JOB_DONE, - - // All missing pages have been requested. - ALL_PAGES_REQUESTED, - - // An error occured. Printing is canceled. - FAILED, - }; - - JobEventDetails(Type type, PrintedDocument* document, PrintedPage* page); - - // Getters. - PrintedDocument* document() const; - PrintedPage* page() const; - Type type() const { - return type_; - } - - private: - friend class base::RefCountedThreadSafe; - - ~JobEventDetails(); - - scoped_refptr document_; - scoped_refptr page_; - const Type type_; - - DISALLOW_COPY_AND_ASSIGN(JobEventDetails); -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_H_ diff --git a/chromium_src/chrome/browser/printing/print_job_manager.cc b/chromium_src/chrome/browser/printing/print_job_manager.cc deleted file mode 100644 index ec08a9892335e..0000000000000 --- a/chromium_src/chrome/browser/printing/print_job_manager.cc +++ /dev/null @@ -1,164 +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/printing/print_job_manager.h" - -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/printing/print_job.h" -#include "chrome/browser/printing/printer_query.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_service.h" -#include "printing/printed_document.h" -#include "printing/printed_page.h" - -namespace printing { - -PrintQueriesQueue::PrintQueriesQueue() { -} - -PrintQueriesQueue::~PrintQueriesQueue() { - base::AutoLock lock(lock_); - queued_queries_.clear(); -} - -void PrintQueriesQueue::QueuePrinterQuery(PrinterQuery* job) { - base::AutoLock lock(lock_); - DCHECK(job); - queued_queries_.push_back(make_scoped_refptr(job)); - DCHECK(job->is_valid()); -} - -scoped_refptr PrintQueriesQueue::PopPrinterQuery( - int document_cookie) { - base::AutoLock lock(lock_); - for (PrinterQueries::iterator itr = queued_queries_.begin(); - itr != queued_queries_.end(); ++itr) { - if ((*itr)->cookie() == document_cookie && !(*itr)->is_callback_pending()) { - scoped_refptr current_query(*itr); - queued_queries_.erase(itr); - DCHECK(current_query->is_valid()); - return current_query; - } - } - return NULL; -} - -scoped_refptr PrintQueriesQueue::CreatePrinterQuery( - int render_process_id, - int render_view_id) { - scoped_refptr job = - new printing::PrinterQuery(render_process_id, render_view_id); - return job; -} - -void PrintQueriesQueue::Shutdown() { - PrinterQueries queries_to_stop; - { - base::AutoLock lock(lock_); - queued_queries_.swap(queries_to_stop); - } - // Stop all pending queries, requests to generate print preview do not have - // corresponding PrintJob, so any pending preview requests are not covered - // by PrintJobManager::StopJobs and should be stopped explicitly. - for (PrinterQueries::iterator itr = queries_to_stop.begin(); - itr != queries_to_stop.end(); ++itr) { - (*itr)->PostTask(FROM_HERE, base::Bind(&PrinterQuery::StopWorker, *itr)); - } -} - -PrintJobManager::PrintJobManager() : is_shutdown_(false) { - registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, - content::NotificationService::AllSources()); -} - -PrintJobManager::~PrintJobManager() { -} - -scoped_refptr PrintJobManager::queue() { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - if (!queue_.get()) - queue_ = new PrintQueriesQueue(); - return queue_; -} - -void PrintJobManager::Shutdown() { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - DCHECK(!is_shutdown_); - is_shutdown_ = true; - registrar_.RemoveAll(); - StopJobs(true); - if (queue_.get()) - queue_->Shutdown(); - queue_ = NULL; -} - -void PrintJobManager::StopJobs(bool wait_for_finish) { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - // Copy the array since it can be modified in transit. - PrintJobs to_stop; - to_stop.swap(current_jobs_); - - for (PrintJobs::const_iterator job = to_stop.begin(); job != to_stop.end(); - ++job) { - // Wait for two minutes for the print job to be spooled. - if (wait_for_finish) - (*job)->FlushJob(base::TimeDelta::FromMinutes(2)); - (*job)->Stop(); - } -} - -void PrintJobManager::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - switch (type) { - case chrome::NOTIFICATION_PRINT_JOB_EVENT: { - OnPrintJobEvent(content::Source(source).ptr(), - *content::Details(details).ptr()); - break; - } - default: { - NOTREACHED(); - break; - } - } -} - -void PrintJobManager::OnPrintJobEvent( - PrintJob* print_job, - const JobEventDetails& event_details) { - switch (event_details.type()) { - case JobEventDetails::NEW_DOC: { - DCHECK(current_jobs_.end() == current_jobs_.find(print_job)); - // Causes a AddRef(). - current_jobs_.insert(print_job); - break; - } - case JobEventDetails::JOB_DONE: { - DCHECK(current_jobs_.end() != current_jobs_.find(print_job)); - current_jobs_.erase(print_job); - break; - } - case JobEventDetails::FAILED: { - current_jobs_.erase(print_job); - break; - } - case JobEventDetails::USER_INIT_DONE: - case JobEventDetails::USER_INIT_CANCELED: - case JobEventDetails::DEFAULT_INIT_DONE: - case JobEventDetails::NEW_PAGE: - case JobEventDetails::PAGE_DONE: - case JobEventDetails::DOC_DONE: - case JobEventDetails::ALL_PAGES_REQUESTED: { - // Don't care. - break; - } - default: { - NOTREACHED(); - break; - } - } -} - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_job_manager.h b/chromium_src/chrome/browser/printing/print_job_manager.h deleted file mode 100644 index ddb4e97b42bf8..0000000000000 --- a/chromium_src/chrome/browser/printing/print_job_manager.h +++ /dev/null @@ -1,100 +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_PRINTING_PRINT_JOB_MANAGER_H_ -#define CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_ - -#include -#include -#include - -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/lock.h" -#include "base/threading/non_thread_safe.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" - -namespace printing { - -class JobEventDetails; -class PrintJob; -class PrinterQuery; - -class PrintQueriesQueue : public base::RefCountedThreadSafe { - public: - PrintQueriesQueue(); - - // Queues a semi-initialized worker thread. Can be called from any thread. - // Current use case is queuing from the I/O thread. - // TODO(maruel): Have them vanish after a timeout (~5 minutes?) - void QueuePrinterQuery(PrinterQuery* job); - - // Pops a queued PrintJobWorkerOwner object that was previously queued or - // create new one. Can be called from any thread. - scoped_refptr PopPrinterQuery(int document_cookie); - - // Creates new query. - scoped_refptr CreatePrinterQuery(int render_process_id, - int render_view_id); - - void Shutdown(); - - private: - friend class base::RefCountedThreadSafe; - typedef std::vector > PrinterQueries; - - virtual ~PrintQueriesQueue(); - - // Used to serialize access to queued_workers_. - base::Lock lock_; - - PrinterQueries queued_queries_; - - DISALLOW_COPY_AND_ASSIGN(PrintQueriesQueue); -}; - -class PrintJobManager : public content::NotificationObserver { - public: - PrintJobManager(); - virtual ~PrintJobManager(); - - // On browser quit, we should wait to have the print job finished. - void Shutdown(); - - // content::NotificationObserver - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - // Returns queries queue. Never returns NULL. Must be called on Browser UI - // Thread. Reference could be stored and used from any thread. - scoped_refptr queue(); - - private: - typedef std::set > PrintJobs; - - // Processes a NOTIFY_PRINT_JOB_EVENT notification. - void OnPrintJobEvent(PrintJob* print_job, - const JobEventDetails& event_details); - - // Stops all printing jobs. If wait_for_finish is true, tries to give jobs - // a chance to complete before stopping them. - void StopJobs(bool wait_for_finish); - - content::NotificationRegistrar registrar_; - - // Current print jobs that are active. - PrintJobs current_jobs_; - - scoped_refptr queue_; - - bool is_shutdown_; - - DISALLOW_COPY_AND_ASSIGN(PrintJobManager); -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_ diff --git a/chromium_src/chrome/browser/printing/print_job_worker.cc b/chromium_src/chrome/browser/printing/print_job_worker.cc deleted file mode 100644 index 7a88a8570c420..0000000000000 --- a/chromium_src/chrome/browser/printing/print_job_worker.cc +++ /dev/null @@ -1,404 +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/printing/print_job_worker.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/message_loop/message_loop.h" -#include "base/values.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/printing/print_job.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" -#include "printing/print_job_constants.h" -#include "printing/printed_document.h" -#include "printing/printed_page.h" -#include "printing/printing_utils.h" -#include "ui/base/l10n/l10n_util.h" - -using content::BrowserThread; - -namespace printing { - -namespace { - -// Helper function to ensure |owner| is valid until at least |callback| returns. -void HoldRefCallback(const scoped_refptr& owner, - const base::Closure& callback) { - callback.Run(); -} - -class PrintingContextDelegate : public PrintingContext::Delegate { - public: - PrintingContextDelegate(int render_process_id, int render_view_id); - virtual ~PrintingContextDelegate(); - - virtual gfx::NativeView GetParentView() override; - virtual std::string GetAppLocale() override; - - private: - int render_process_id_; - int render_view_id_; -}; - -PrintingContextDelegate::PrintingContextDelegate(int render_process_id, - int render_view_id) - : render_process_id_(render_process_id), - render_view_id_(render_view_id) { -} - -PrintingContextDelegate::~PrintingContextDelegate() { -} - -gfx::NativeView PrintingContextDelegate::GetParentView() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::RenderViewHost* view = - content::RenderViewHost::FromID(render_process_id_, render_view_id_); - if (!view) - return NULL; - content::WebContents* wc = content::WebContents::FromRenderViewHost(view); - return wc ? wc->GetNativeView() : NULL; -} - -std::string PrintingContextDelegate::GetAppLocale() { - return g_browser_process->GetApplicationLocale(); -} - -void NotificationCallback(PrintJobWorkerOwner* print_job, - JobEventDetails::Type detail_type, - PrintedDocument* document, - PrintedPage* page) { - JobEventDetails* details = new JobEventDetails(detail_type, document, page); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PRINT_JOB_EVENT, - // We know that is is a PrintJob object in this circumstance. - content::Source(static_cast(print_job)), - content::Details(details)); -} - -} // namespace - -PrintJobWorker::PrintJobWorker(int render_process_id, - int render_view_id, - PrintJobWorkerOwner* owner) - : owner_(owner), thread_("Printing_Worker"), weak_factory_(this) { - // The object is created in the IO thread. - DCHECK(owner_->RunsTasksOnCurrentThread()); - - printing_context_delegate_.reset( - new PrintingContextDelegate(render_process_id, render_view_id)); - printing_context_ = PrintingContext::Create(printing_context_delegate_.get()); -} - -PrintJobWorker::~PrintJobWorker() { - // The object is normally deleted in the UI thread, but when the user - // cancels printing or in the case of print preview, the worker is destroyed - // on the I/O thread. - DCHECK(owner_->RunsTasksOnCurrentThread()); - Stop(); -} - -void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) { - DCHECK(page_number_ == PageNumber::npos()); - owner_ = new_owner; -} - -void PrintJobWorker::GetSettings( - bool ask_user_for_settings, - int document_page_count, - bool has_selection, - MarginType margin_type) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - DCHECK_EQ(page_number_, PageNumber::npos()); - - // Recursive task processing is needed for the dialog in case it needs to be - // destroyed by a task. - // TODO(thestig): This code is wrong. SetNestableTasksAllowed(true) is needed - // on the thread where the PrintDlgEx is called, and definitely both calls - // should happen on the same thread. See http://crbug.com/73466 - // MessageLoop::current()->SetNestableTasksAllowed(true); - printing_context_->set_margin_type(margin_type); - - // When we delegate to a destination, we don't ask the user for settings. - // TODO(mad): Ask the destination for settings. - if (ask_user_for_settings) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), - base::Bind(&PrintJobWorker::GetSettingsWithUI, - base::Unretained(this), - document_page_count, - has_selection))); - } else { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&HoldRefCallback, make_scoped_refptr(owner_), - base::Bind(&PrintJobWorker::UseDefaultSettings, - base::Unretained(this)))); - } -} - -void PrintJobWorker::SetSettings( - std::unique_ptr new_settings) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&HoldRefCallback, - make_scoped_refptr(owner_), - base::Bind(&PrintJobWorker::UpdatePrintSettings, - base::Unretained(this), - base::Passed(&new_settings)))); -} - -void PrintJobWorker::UpdatePrintSettings( - std::unique_ptr new_settings) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - PrintingContext::Result result = - printing_context_->UpdatePrintSettings(*new_settings); - GetSettingsDone(result); -} - -void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) { - // Most PrintingContext functions may start a message loop and process - // message recursively, so disable recursive task processing. - // TODO(thestig): See above comment. SetNestableTasksAllowed(false) needs to - // be called on the same thread as the previous call. See - // http://crbug.com/73466 - // MessageLoop::current()->SetNestableTasksAllowed(false); - - // We can't use OnFailure() here since owner_ may not support notifications. - - // PrintJob will create the new PrintedDocument. - owner_->PostTask(FROM_HERE, - base::Bind(&PrintJobWorkerOwner::GetSettingsDone, - make_scoped_refptr(owner_), - printing_context_->settings(), - result)); -} - -void PrintJobWorker::GetSettingsWithUI( - int document_page_count, - bool has_selection) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - printing_context_->AskUserForSettings( - document_page_count, - has_selection, - false, - base::Bind(&PrintJobWorker::GetSettingsWithUIDone, - base::Unretained(this))); -} - -void PrintJobWorker::GetSettingsWithUIDone(PrintingContext::Result result) { - PostTask(FROM_HERE, - base::Bind(&HoldRefCallback, - make_scoped_refptr(owner_), - base::Bind(&PrintJobWorker::GetSettingsDone, - base::Unretained(this), - result))); -} - -void PrintJobWorker::UseDefaultSettings() { - PrintingContext::Result result = printing_context_->UseDefaultSettings(); - GetSettingsDone(result); -} - -void PrintJobWorker::StartPrinting(PrintedDocument* new_document) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - DCHECK_EQ(page_number_, PageNumber::npos()); - DCHECK_EQ(document_.get(), new_document); - DCHECK(document_.get()); - - if (!document_.get() || page_number_ != PageNumber::npos() || - document_.get() != new_document) { - return; - } - - base::string16 document_name = - printing::SimplifyDocumentTitle(document_->name()); - if (document_name.empty()) { - } - PrintingContext::Result result = - printing_context_->NewDocument(document_name); - if (result != PrintingContext::OK) { - OnFailure(); - return; - } - - // Try to print already cached data. It may already have been generated for - // the print preview. - OnNewPage(); - // Don't touch this anymore since the instance could be destroyed. It happens - // if all the pages are printed a one sweep and the client doesn't have a - // handle to us anymore. There's a timing issue involved between the worker - // thread and the UI thread. Take no chance. -} - -void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - DCHECK_EQ(page_number_, PageNumber::npos()); - - if (page_number_ != PageNumber::npos()) - return; - - document_ = new_document; -} - -void PrintJobWorker::OnNewPage() { - if (!document_.get()) // Spurious message. - return; - - // message_loop() could return NULL when the print job is cancelled. - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - - if (page_number_ == PageNumber::npos()) { - // Find first page to print. - int page_count = document_->page_count(); - if (!page_count) { - // We still don't know how many pages the document contains. We can't - // start to print the document yet since the header/footer may refer to - // the document's page count. - return; - } - // We have enough information to initialize page_number_. - page_number_.Init(document_->settings(), page_count); - } - DCHECK_NE(page_number_, PageNumber::npos()); - - while (true) { - // Is the page available? - scoped_refptr page = document_->GetPage(page_number_.ToInt()); - if (!page.get()) { - // We need to wait for the page to be available. - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&PrintJobWorker::OnNewPage, weak_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(500)); - break; - } - // The page is there, print it. - SpoolPage(page.get()); - ++page_number_; - if (page_number_ == PageNumber::npos()) { - OnDocumentDone(); - // Don't touch this anymore since the instance could be destroyed. - break; - } - } -} - -void PrintJobWorker::Cancel() { - // This is the only function that can be called from any thread. - printing_context_->Cancel(); - // Cannot touch any member variable since we don't know in which thread - // context we run. -} - -bool PrintJobWorker::IsRunning() const { - return thread_.IsRunning(); -} - -bool PrintJobWorker::PostTask(const tracked_objects::Location& from_here, - const base::Closure& task) { - if (task_runner_.get()) - return task_runner_->PostTask(from_here, task); - return false; -} - -void PrintJobWorker::StopSoon() { - thread_.StopSoon(); -} - -void PrintJobWorker::Stop() { - thread_.Stop(); -} - -bool PrintJobWorker::Start() { - bool result = thread_.Start(); - task_runner_ = thread_.task_runner(); - return result; -} - -void PrintJobWorker::OnDocumentDone() { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - DCHECK_EQ(page_number_, PageNumber::npos()); - DCHECK(document_.get()); - - if (printing_context_->DocumentDone() != PrintingContext::OK) { - OnFailure(); - return; - } - - owner_->PostTask(FROM_HERE, - base::Bind(&NotificationCallback, base::RetainedRef(owner_), - JobEventDetails::DOC_DONE, - base::RetainedRef(document_), nullptr)); - - // Makes sure the variables are reinitialized. - document_ = NULL; -} - -void PrintJobWorker::SpoolPage(PrintedPage* page) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - DCHECK_NE(page_number_, PageNumber::npos()); - - // Signal everyone that the page is about to be printed. - owner_->PostTask(FROM_HERE, - base::Bind(&NotificationCallback, base::RetainedRef(owner_), - JobEventDetails::NEW_PAGE, base::RetainedRef(document_), - base::RetainedRef(page))); - - // Preprocess. - if (printing_context_->NewPage() != PrintingContext::OK) { - OnFailure(); - return; - } - - // Actual printing. -#if defined(OS_WIN) || defined(OS_MACOSX) - document_->RenderPrintedPage(*page, printing_context_->context()); -#elif defined(OS_POSIX) - document_->RenderPrintedPage(*page, printing_context_.get()); -#endif - - // Postprocess. - if (printing_context_->PageDone() != PrintingContext::OK) { - OnFailure(); - return; - } - - // Signal everyone that the page is printed. - owner_->PostTask( - FROM_HERE, - base::Bind(&NotificationCallback, base::RetainedRef(owner_), - JobEventDetails::PAGE_DONE, base::RetainedRef(document_), - base::RetainedRef(page))); -} - -void PrintJobWorker::OnFailure() { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - - // We may loose our last reference by broadcasting the FAILED event. - scoped_refptr handle(owner_); - - owner_->PostTask( - FROM_HERE, - base::Bind(&NotificationCallback, base::RetainedRef(owner_), - JobEventDetails::FAILED, - base::RetainedRef(document_), nullptr)); - Cancel(); - - // Makes sure the variables are reinitialized. - document_ = NULL; - page_number_ = PageNumber::npos(); -} - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_job_worker.h b/chromium_src/chrome/browser/printing/print_job_worker.h deleted file mode 100644 index 343c0fa15f297..0000000000000 --- a/chromium_src/chrome/browser/printing/print_job_worker.h +++ /dev/null @@ -1,160 +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_PRINTING_PRINT_JOB_WORKER_H_ -#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_ - -#include - -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread.h" -#include "content/public/browser/browser_thread.h" -#include "printing/page_number.h" -#include "printing/print_job_constants.h" -#include "printing/printing_context.h" - -namespace base { -class DictionaryValue; -} - -namespace printing { - -class PrintJob; -class PrintJobWorkerOwner; -class PrintedDocument; -class PrintedPage; - -// Worker thread code. It manages the PrintingContext, which can be blocking -// and/or run a message loop. This is the object that generates most -// NOTIFY_PRINT_JOB_EVENT notifications, but they are generated through a -// NotificationTask task to be executed from the right thread, the UI thread. -// PrintJob always outlives its worker instance. -class PrintJobWorker { - public: - PrintJobWorker(int render_process_id, - int render_view_id, - PrintJobWorkerOwner* owner); - virtual ~PrintJobWorker(); - - void SetNewOwner(PrintJobWorkerOwner* new_owner); - - // Initializes the print settings. If |ask_user_for_settings| is true, a - // Print... dialog box will be shown to ask the user his preference. - void GetSettings( - bool ask_user_for_settings, - int document_page_count, - bool has_selection, - MarginType margin_type); - - // Set the new print settings. - void SetSettings(std::unique_ptr new_settings); - - // Starts the printing loop. Every pages are printed as soon as the data is - // available. Makes sure the new_document is the right one. - void StartPrinting(PrintedDocument* new_document); - - // Updates the printed document. - void OnDocumentChanged(PrintedDocument* new_document); - - // Dequeues waiting pages. Called when PrintJob receives a - // NOTIFY_PRINTED_DOCUMENT_UPDATED notification. It's time to look again if - // the next page can be printed. - void OnNewPage(); - - // This is the only function that can be called in a thread. - void Cancel(); - - // Returns true if the thread has been started, and not yet stopped. - bool IsRunning() const; - - // Posts the given task to be run. - bool PostTask(const tracked_objects::Location& from_here, - const base::Closure& task); - - // Signals the thread to exit in the near future. - void StopSoon(); - - // Signals the thread to exit and returns once the thread has exited. - void Stop(); - - // Starts the thread. - bool Start(); - - protected: - // Retrieves the context for testing only. - PrintingContext* printing_context() { return printing_context_.get(); } - - private: - // The shared NotificationService service can only be accessed from the UI - // thread, so this class encloses the necessary information to send the - // notification from the right thread. Most NOTIFY_PRINT_JOB_EVENT - // notifications are sent this way, except USER_INIT_DONE, USER_INIT_CANCELED - // and DEFAULT_INIT_DONE. These three are sent through PrintJob::InitDone(). - class NotificationTask; - - // Renders a page in the printer. - void SpoolPage(PrintedPage* page); - - // Closes the job since spooling is done. - void OnDocumentDone(); - - // Discards the current document, the current page and cancels the printing - // context. - void OnFailure(); - - // Asks the user for print settings. Must be called on the UI thread. - // Required on Mac and Linux. Windows can display UI from non-main threads, - // but sticks with this for consistency. - void GetSettingsWithUI( - int document_page_count, - bool has_selection); - - // The callback used by PrintingContext::GetSettingsWithUI() to notify this - // object that the print settings are set. This is needed in order to bounce - // back into the IO thread for GetSettingsDone(). - void GetSettingsWithUIDone(PrintingContext::Result result); - - // Called on the UI thread to update the print settings. - void UpdatePrintSettings(std::unique_ptr new_settings); - - // Reports settings back to owner_. - void GetSettingsDone(PrintingContext::Result result); - - // Use the default settings. When using GTK+ or Mac, this can still end up - // displaying a dialog. So this needs to happen from the UI thread on these - // systems. - void UseDefaultSettings(); - - // Printing context delegate. - std::unique_ptr printing_context_delegate_; - - // Information about the printer setting. - std::unique_ptr printing_context_; - - // The printed document. Only has read-only access. - scoped_refptr document_; - - // The print job owning this worker thread. It is guaranteed to outlive this - // object. - PrintJobWorkerOwner* owner_; - - // Current page number to print. - PageNumber page_number_; - - // Thread to run worker tasks. - base::Thread thread_; - - // Tread-safe pointer to task runner of the |thread_|. - scoped_refptr task_runner_; - - // Used to generate a WeakPtr for callbacks. - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(PrintJobWorker); -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_ diff --git a/chromium_src/chrome/browser/printing/print_job_worker_owner.cc b/chromium_src/chrome/browser/printing/print_job_worker_owner.cc deleted file mode 100644 index 843ab4616d187..0000000000000 --- a/chromium_src/chrome/browser/printing/print_job_worker_owner.cc +++ /dev/null @@ -1,27 +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. - -#include "chrome/browser/printing/print_job_worker_owner.h" - -#include "base/message_loop/message_loop.h" - -namespace printing { - -PrintJobWorkerOwner::PrintJobWorkerOwner() - : task_runner_(base::MessageLoop::current()->task_runner()) { -} - -PrintJobWorkerOwner::~PrintJobWorkerOwner() { -} - -bool PrintJobWorkerOwner::RunsTasksOnCurrentThread() const { - return task_runner_->RunsTasksOnCurrentThread(); -} - -bool PrintJobWorkerOwner::PostTask(const tracked_objects::Location& from_here, - const base::Closure& task) { - return task_runner_->PostTask(from_here, task); -} - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_job_worker_owner.h b/chromium_src/chrome/browser/printing/print_job_worker_owner.h deleted file mode 100644 index 00a561a39bb65..0000000000000 --- a/chromium_src/chrome/browser/printing/print_job_worker_owner.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2011 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_PRINTING_PRINT_JOB_WORKER_OWNER_H__ -#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__ - -#include "base/memory/ref_counted.h" -#include "printing/printing_context.h" - -namespace base { -class MessageLoop; -class SequencedTaskRunner; -} - -namespace tracked_objects { -class Location; -} - -namespace printing { - -class PrintJobWorker; -class PrintSettings; - -class PrintJobWorkerOwner - : public base::RefCountedThreadSafe { - public: - PrintJobWorkerOwner(); - - // Finishes the initialization began by PrintJobWorker::GetSettings(). - // Creates a new PrintedDocument if necessary. Solely meant to be called by - // PrintJobWorker. - virtual void GetSettingsDone(const PrintSettings& new_settings, - PrintingContext::Result result) = 0; - - // Detach the PrintJobWorker associated to this object. - virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) = 0; - - // Access the current settings. - virtual const PrintSettings& settings() const = 0; - - // Cookie uniquely identifying the PrintedDocument and/or loaded settings. - virtual int cookie() const = 0; - - // Returns true if the current thread is a thread on which a task - // may be run, and false if no task will be run on the current - // thread. - bool RunsTasksOnCurrentThread() const; - - // Posts the given task to be run. - bool PostTask(const tracked_objects::Location& from_here, - const base::Closure& task); - - protected: - friend class base::RefCountedThreadSafe; - - virtual ~PrintJobWorkerOwner(); - - // Task runner reference. Used to send notifications in the right - // thread. - scoped_refptr task_runner_; -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__ diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc deleted file mode 100644 index d1f3660f8d2de..0000000000000 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ /dev/null @@ -1,140 +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/printing/print_preview_message_handler.h" - -#include "base/bind.h" -#include "base/memory/shared_memory.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/printing/print_job_manager.h" -#include "chrome/browser/printing/printer_query.h" -#include "chrome/common/print_messages.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" -#include "printing/page_size_margins.h" -#include "printing/print_job_constants.h" -#include "printing/pdf_metafile_skia.h" - -#include "atom/common/node_includes.h" - -using content::BrowserThread; -using content::WebContents; - -DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintPreviewMessageHandler); - -namespace { - -void StopWorker(int document_cookie) { - if (document_cookie <= 0) - return; - scoped_refptr queue = - g_browser_process->print_job_manager()->queue(); - scoped_refptr printer_query = - queue->PopPrinterQuery(document_cookie); - if (printer_query.get()) { - BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, - base::Bind(&printing::PrinterQuery::StopWorker, - printer_query)); - } -} - -char* CopyPDFDataOnIOThread( - const PrintHostMsg_DidPreviewDocument_Params& params) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - std::unique_ptr shared_buf( - new base::SharedMemory(params.metafile_data_handle, true)); - if (!shared_buf->Map(params.data_size)) - return nullptr; - char* memory_pdf_data = static_cast(shared_buf->memory()); - char* pdf_data = new char[params.data_size]; - memcpy(pdf_data, memory_pdf_data, params.data_size); - return pdf_data; -} - -} // namespace - -namespace printing { - - -PrintPreviewMessageHandler::PrintPreviewMessageHandler( - WebContents* web_contents) - : content::WebContentsObserver(web_contents) { - DCHECK(web_contents); -} - -PrintPreviewMessageHandler::~PrintPreviewMessageHandler() { -} - -void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( - const PrintHostMsg_DidPreviewDocument_Params& params) { - // Always try to stop the worker. - StopWorker(params.document_cookie); - - if (params.expected_pages_count <= 0) { - NOTREACHED(); - return; - } - - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::IO, - FROM_HERE, - base::Bind(&CopyPDFDataOnIOThread, params), - base::Bind(&PrintPreviewMessageHandler::RunPrintToPDFCallback, - base::Unretained(this), - params.preview_request_id, - params.data_size)); -} - -void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie, - int request_id) { - StopWorker(document_cookie); - RunPrintToPDFCallback(request_id, 0, nullptr); -} - -bool PrintPreviewMessageHandler::OnMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PrintPreviewMessageHandler, message) - IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting, - OnMetafileReadyForPrinting) - IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewFailed, - OnPrintPreviewFailed) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void PrintPreviewMessageHandler::PrintToPDF( - const base::DictionaryValue& options, - const atom::api::WebContents::PrintToPDFCallback& callback) { - int request_id; - options.GetInteger(printing::kPreviewRequestID, &request_id); - print_to_pdf_callback_map_[request_id] = callback; - - content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); - rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), options)); -} - -void PrintPreviewMessageHandler::RunPrintToPDFCallback( - int request_id, uint32_t data_size, char* data) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::Locker locker(isolate); - v8::HandleScope handle_scope(isolate); - if (data) { - v8::Local buffer = node::Buffer::New(isolate, - data, static_cast(data_size)).ToLocalChecked(); - print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate), buffer); - } else { - v8::Local error_message = v8::String::NewFromUtf8(isolate, - "Fail to generate PDF"); - print_to_pdf_callback_map_[request_id].Run( - v8::Exception::Error(error_message), v8::Null(isolate)); - } - print_to_pdf_callback_map_.erase(request_id); -} - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h deleted file mode 100644 index 1aac74baa2299..0000000000000 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ /dev/null @@ -1,59 +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_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_ -#define CHROME_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_ - -#include - -#include "atom/browser/api/atom_api_web_contents.h" -#include "base/compiler_specific.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_user_data.h" - -struct PrintHostMsg_DidPreviewDocument_Params; - -namespace content { -class WebContents; -} - -namespace printing { - -struct PageSizeMargins; - -// Manages the print preview handling for a WebContents. -class PrintPreviewMessageHandler - : public content::WebContentsObserver, - public content::WebContentsUserData { - public: - ~PrintPreviewMessageHandler() override; - - // content::WebContentsObserver implementation. - bool OnMessageReceived(const IPC::Message& message) override; - - void PrintToPDF(const base::DictionaryValue& options, - const atom::api::WebContents::PrintToPDFCallback& callback); - - private: - typedef std::map - PrintToPDFCallbackMap; - - explicit PrintPreviewMessageHandler(content::WebContents* web_contents); - friend class content::WebContentsUserData; - - // Message handlers. - void OnMetafileReadyForPrinting( - const PrintHostMsg_DidPreviewDocument_Params& params); - void OnPrintPreviewFailed(int document_cookie, int request_id); - - void RunPrintToPDFCallback(int request_id, uint32_t data_size, char* data); - - PrintToPDFCallbackMap print_to_pdf_callback_map_; - - DISALLOW_COPY_AND_ASSIGN(PrintPreviewMessageHandler); -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_ diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.cc b/chromium_src/chrome/browser/printing/print_view_manager_base.cc deleted file mode 100644 index f771f6963d401..0000000000000 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.cc +++ /dev/null @@ -1,498 +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. - -#include "chrome/browser/printing/print_view_manager_base.h" - -#include - -#include "base/bind.h" -#include "components/prefs/pref_service.h" -#include "base/strings/utf_string_conversions.h" -#include "base/timer/timer.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/printing/print_job.h" -#include "chrome/browser/printing/print_job_manager.h" -#include "chrome/browser/printing/printer_query.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/simple_message_box.h" -#include "chrome/common/pref_names.h" -#include "chrome/common/print_messages.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" -#include "printing/pdf_metafile_skia.h" -#include "printing/printed_document.h" -#include "ui/base/l10n/l10n_util.h" - -#if defined(ENABLE_FULL_PRINTING) -#include "chrome/browser/printing/print_error_dialog.h" -#endif - -using base::TimeDelta; -using content::BrowserThread; - -namespace printing { - -namespace { - -} // namespace - -PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents) - : content::WebContentsObserver(web_contents), - number_pages_(0), - printing_succeeded_(false), - inside_inner_message_loop_(false), - cookie_(0), - queue_(g_browser_process->print_job_manager()->queue()) { - DCHECK(queue_.get()); -#if !defined(OS_MACOSX) - expecting_first_page_ = true; -#endif // OS_MACOSX - printing_enabled_ = true; -} - -PrintViewManagerBase::~PrintViewManagerBase() { - ReleasePrinterQuery(); - DisconnectFromCurrentPrintJob(); -} - -#if !defined(DISABLE_BASIC_PRINTING) -bool PrintViewManagerBase::PrintNow(bool silent, bool print_background) { - return PrintNowInternal(new PrintMsg_PrintPages( - routing_id(), silent, print_background)); -} -#endif // !DISABLE_BASIC_PRINTING - -void PrintViewManagerBase::NavigationStopped() { - // Cancel the current job, wait for the worker to finish. - TerminatePrintJob(true); -} - -void PrintViewManagerBase::RenderProcessGone(base::TerminationStatus status) { - ReleasePrinterQuery(); - - if (!print_job_.get()) - return; - - scoped_refptr document(print_job_->document()); - if (document.get()) { - // If IsComplete() returns false, the document isn't completely rendered. - // Since our renderer is gone, there's nothing to do, cancel it. Otherwise, - // the print job may finish without problem. - TerminatePrintJob(!document->IsComplete()); - } -} - -base::string16 PrintViewManagerBase::RenderSourceName() { - base::string16 name(web_contents()->GetTitle()); - return name; -} - -void PrintViewManagerBase::OnDidGetPrintedPagesCount(int cookie, - int number_pages) { - DCHECK_GT(cookie, 0); - DCHECK_GT(number_pages, 0); - number_pages_ = number_pages; - OpportunisticallyCreatePrintJob(cookie); -} - -void PrintViewManagerBase::OnDidGetDocumentCookie(int cookie) { - cookie_ = cookie; -} - -void PrintViewManagerBase::OnDidPrintPage( - const PrintHostMsg_DidPrintPage_Params& params) { - if (!OpportunisticallyCreatePrintJob(params.document_cookie)) - return; - - PrintedDocument* document = print_job_->document(); - if (!document || params.document_cookie != document->cookie()) { - // Out of sync. It may happen since we are completely asynchronous. Old - // spurious messages can be received if one of the processes is overloaded. - return; - } - -#if defined(OS_MACOSX) - const bool metafile_must_be_valid = true; -#else - const bool metafile_must_be_valid = expecting_first_page_; - expecting_first_page_ = false; -#endif // OS_MACOSX - - base::SharedMemory shared_buf(params.metafile_data_handle, true); - if (metafile_must_be_valid) { - if (!shared_buf.Map(params.data_size)) { - NOTREACHED() << "couldn't map"; - web_contents()->Stop(); - return; - } - } - - std::unique_ptr metafile(new PdfMetafileSkia); - if (metafile_must_be_valid) { - if (!metafile->InitFromData(shared_buf.memory(), params.data_size)) { - NOTREACHED() << "Invalid metafile header"; - web_contents()->Stop(); - return; - } - } - -#if !defined(OS_WIN) - // Update the rendered document. It will send notifications to the listener. - document->SetPage(params.page_number, - std::move(metafile), - params.page_size, - params.content_area); - - ShouldQuitFromInnerMessageLoop(); -#else - if (metafile_must_be_valid) { - scoped_refptr bytes = new base::RefCountedBytes( - reinterpret_cast(shared_buf.memory()), - params.data_size); - - document->DebugDumpData(bytes.get(), FILE_PATH_LITERAL(".pdf")); - print_job_->StartPdfToEmfConversion( - bytes, params.page_size, params.content_area); - } -#endif // !OS_WIN -} - -void PrintViewManagerBase::OnPrintingFailed(int cookie) { - if (cookie != cookie_) { - NOTREACHED(); - return; - } - - ReleasePrinterQuery(); - - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PRINT_JOB_RELEASED, - content::Source(web_contents()), - content::NotificationService::NoDetails()); -} - -void PrintViewManagerBase::OnShowInvalidPrinterSettingsError() { - LOG(ERROR) << "Invalid printer settings"; -} - -bool PrintViewManagerBase::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBase, message) - IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetPrintedPagesCount, - OnDidGetPrintedPagesCount) - IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetDocumentCookie, - OnDidGetDocumentCookie) - IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage) - IPC_MESSAGE_HANDLER(PrintHostMsg_PrintingFailed, OnPrintingFailed) - IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError, - OnShowInvalidPrinterSettingsError); - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void PrintViewManagerBase::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - switch (type) { - case chrome::NOTIFICATION_PRINT_JOB_EVENT: { - OnNotifyPrintJobEvent(*content::Details(details).ptr()); - break; - } - default: { - NOTREACHED(); - break; - } - } -} - -void PrintViewManagerBase::OnNotifyPrintJobEvent( - const JobEventDetails& event_details) { - switch (event_details.type()) { - case JobEventDetails::FAILED: { - TerminatePrintJob(true); - - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PRINT_JOB_RELEASED, - content::Source(web_contents()), - content::NotificationService::NoDetails()); - break; - } - case JobEventDetails::USER_INIT_DONE: - case JobEventDetails::DEFAULT_INIT_DONE: - case JobEventDetails::USER_INIT_CANCELED: { - NOTREACHED(); - break; - } - case JobEventDetails::ALL_PAGES_REQUESTED: { - ShouldQuitFromInnerMessageLoop(); - break; - } - case JobEventDetails::NEW_DOC: - case JobEventDetails::NEW_PAGE: - case JobEventDetails::PAGE_DONE: - case JobEventDetails::DOC_DONE: { - // Don't care about the actual printing process. - break; - } - case JobEventDetails::JOB_DONE: { - // Printing is done, we don't need it anymore. - // print_job_->is_job_pending() may still be true, depending on the order - // of object registration. - printing_succeeded_ = true; - ReleasePrintJob(); - - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_PRINT_JOB_RELEASED, - content::Source(web_contents()), - content::NotificationService::NoDetails()); - break; - } - default: { - NOTREACHED(); - break; - } - } -} - -bool PrintViewManagerBase::RenderAllMissingPagesNow() { - if (!print_job_.get() || !print_job_->is_job_pending()) - return false; - - // We can't print if there is no renderer. - if (!web_contents() || - !web_contents()->GetRenderViewHost() || - !web_contents()->GetRenderViewHost()->IsRenderViewLive()) { - return false; - } - - // Is the document already complete? - if (print_job_->document() && print_job_->document()->IsComplete()) { - printing_succeeded_ = true; - return true; - } - - // WebContents is either dying or a second consecutive request to print - // happened before the first had time to finish. We need to render all the - // pages in an hurry if a print_job_ is still pending. No need to wait for it - // to actually spool the pages, only to have the renderer generate them. Run - // a message loop until we get our signal that the print job is satisfied. - // PrintJob will send a ALL_PAGES_REQUESTED after having received all the - // pages it needs. MessageLoop::current()->Quit() will be called as soon as - // print_job_->document()->IsComplete() is true on either ALL_PAGES_REQUESTED - // or in DidPrintPage(). The check is done in - // ShouldQuitFromInnerMessageLoop(). - // BLOCKS until all the pages are received. (Need to enable recursive task) - if (!RunInnerMessageLoop()) { - // This function is always called from DisconnectFromCurrentPrintJob() so we - // know that the job will be stopped/canceled in any case. - return false; - } - return true; -} - -void PrintViewManagerBase::ShouldQuitFromInnerMessageLoop() { - // Look at the reason. - DCHECK(print_job_->document()); - if (print_job_->document() && - print_job_->document()->IsComplete() && - inside_inner_message_loop_) { - // We are in a message loop created by RenderAllMissingPagesNow. Quit from - // it. - base::MessageLoop::current()->QuitWhenIdle(); - inside_inner_message_loop_ = false; - } -} - -bool PrintViewManagerBase::CreateNewPrintJob(PrintJobWorkerOwner* job) { - DCHECK(!inside_inner_message_loop_); - - // Disconnect the current print_job_. - DisconnectFromCurrentPrintJob(); - - // We can't print if there is no renderer. - if (!web_contents()->GetRenderViewHost() || - !web_contents()->GetRenderViewHost()->IsRenderViewLive()) { - return false; - } - - // Ask the renderer to generate the print preview, create the print preview - // view and switch to it, initialize the printer and show the print dialog. - DCHECK(!print_job_.get()); - DCHECK(job); - if (!job) - return false; - - print_job_ = new PrintJob(); - print_job_->Initialize(job, this, number_pages_); - registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, - content::Source(print_job_.get())); - printing_succeeded_ = false; - return true; -} - -void PrintViewManagerBase::DisconnectFromCurrentPrintJob() { - // Make sure all the necessary rendered page are done. Don't bother with the - // return value. - bool result = RenderAllMissingPagesNow(); - - // Verify that assertion. - if (print_job_.get() && - print_job_->document() && - !print_job_->document()->IsComplete()) { - DCHECK(!result); - // That failed. - TerminatePrintJob(true); - } else { - // DO NOT wait for the job to finish. - ReleasePrintJob(); - } -#if !defined(OS_MACOSX) - expecting_first_page_ = true; -#endif // OS_MACOSX -} - -void PrintViewManagerBase::PrintingDone(bool success) { - if (!print_job_.get()) - return; - Send(new PrintMsg_PrintingDone(routing_id(), success)); -} - -void PrintViewManagerBase::TerminatePrintJob(bool cancel) { - if (!print_job_.get()) - return; - - if (cancel) { - // We don't need the metafile data anymore because the printing is canceled. - print_job_->Cancel(); - inside_inner_message_loop_ = false; - } else { - DCHECK(!inside_inner_message_loop_); - DCHECK(!print_job_->document() || print_job_->document()->IsComplete()); - - // WebContents is either dying or navigating elsewhere. We need to render - // all the pages in an hurry if a print job is still pending. This does the - // trick since it runs a blocking message loop: - print_job_->Stop(); - } - ReleasePrintJob(); -} - -void PrintViewManagerBase::ReleasePrintJob() { - if (!print_job_.get()) - return; - - PrintingDone(printing_succeeded_); - - registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, - content::Source(print_job_.get())); - print_job_->DisconnectSource(); - // Don't close the worker thread. - print_job_ = NULL; -} - -bool PrintViewManagerBase::RunInnerMessageLoop() { - // This value may actually be too low: - // - // - If we're looping because of printer settings initialization, the premise - // here is that some poor users have their print server away on a VPN over a - // slow connection. In this situation, the simple fact of opening the printer - // can be dead slow. On the other side, we don't want to die infinitely for a - // real network error. Give the printer 60 seconds to comply. - // - // - If we're looping because of renderer page generation, the renderer could - // be CPU bound, the page overly complex/large or the system just - // memory-bound. - static const int kPrinterSettingsTimeout = 60000; - base::OneShotTimer quit_timer; - quit_timer.Start( - FROM_HERE, TimeDelta::FromMilliseconds(kPrinterSettingsTimeout), - base::MessageLoop::current(), &base::MessageLoop::QuitWhenIdle); - - inside_inner_message_loop_ = true; - - // Need to enable recursive task. - { - base::MessageLoop::ScopedNestableTaskAllower allow( - base::MessageLoop::current()); - base::MessageLoop::current()->Run(); - } - - bool success = true; - if (inside_inner_message_loop_) { - // Ok we timed out. That's sad. - inside_inner_message_loop_ = false; - success = false; - } - - return success; -} - -bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) { - if (print_job_.get()) - return true; - - if (!cookie) { - // Out of sync. It may happens since we are completely asynchronous. Old - // spurious message can happen if one of the processes is overloaded. - return false; - } - - // The job was initiated by a script. Time to get the corresponding worker - // thread. - scoped_refptr queued_query = queue_->PopPrinterQuery(cookie); - if (!queued_query.get()) { - NOTREACHED(); - return false; - } - - if (!CreateNewPrintJob(queued_query.get())) { - // Don't kill anything. - return false; - } - - // Settings are already loaded. Go ahead. This will set - // print_job_->is_job_pending() to true. - print_job_->StartPrinting(); - return true; -} - -bool PrintViewManagerBase::PrintNowInternal(IPC::Message* message) { - // Don't print / print preview interstitials. - if (web_contents()->ShowingInterstitialPage()) { - delete message; - return false; - } - return Send(message); -} - -void PrintViewManagerBase::ReleasePrinterQuery() { - if (!cookie_) - return; - - int cookie = cookie_; - cookie_ = 0; - - printing::PrintJobManager* print_job_manager = - g_browser_process->print_job_manager(); - // May be NULL in tests. - if (!print_job_manager) - return; - - scoped_refptr printer_query; - printer_query = queue_->PopPrinterQuery(cookie); - if (!printer_query.get()) - return; - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&PrinterQuery::StopWorker, printer_query.get())); -} - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_view_manager_base.h b/chromium_src/chrome/browser/printing/print_view_manager_base.h deleted file mode 100644 index 78e5729a5fb1a..0000000000000 --- a/chromium_src/chrome/browser/printing/print_view_manager_base.h +++ /dev/null @@ -1,163 +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_PRINTING_PRINT_VIEW_MANAGER_BASE_H_ -#define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_ - -#include "base/memory/ref_counted.h" -#include "components/prefs/pref_member.h" -#include "base/strings/string16.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_user_data.h" -#include "printing/printed_pages_source.h" - -struct PrintHostMsg_DidPrintPage_Params; - -namespace content { -class RenderViewHost; -} - -namespace printing { - -class JobEventDetails; -class MetafilePlayer; -class PrintJob; -class PrintJobWorkerOwner; -class PrintQueriesQueue; - -// Base class for managing the print commands for a WebContents. -class PrintViewManagerBase : public content::NotificationObserver, - public PrintedPagesSource, - public content::WebContentsObserver { - public: - virtual ~PrintViewManagerBase(); - -#if !defined(DISABLE_BASIC_PRINTING) - // Prints the current document immediately. Since the rendering is - // asynchronous, the actual printing will not be completed on the return of - // this function. Returns false if printing is impossible at the moment. - virtual bool PrintNow(bool silent, bool print_background); -#endif // !DISABLE_BASIC_PRINTING - - // PrintedPagesSource implementation. - virtual base::string16 RenderSourceName() override; - - protected: - explicit PrintViewManagerBase(content::WebContents* web_contents); - - // Helper method for Print*Now(). - bool PrintNowInternal(IPC::Message* message); - - // Terminates or cancels the print job if one was pending. - virtual void RenderProcessGone(base::TerminationStatus status) override; - - // content::WebContentsObserver implementation. - virtual bool OnMessageReceived(const IPC::Message& message) override; - - // IPC Message handlers. - virtual void OnPrintingFailed(int cookie); - - private: - // content::NotificationObserver implementation. - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - // Cancels the print job. - virtual void NavigationStopped() override; - - // IPC Message handlers. - void OnDidGetPrintedPagesCount(int cookie, int number_pages); - void OnDidGetDocumentCookie(int cookie); - void OnDidPrintPage(const PrintHostMsg_DidPrintPage_Params& params); - void OnShowInvalidPrinterSettingsError(); - - // Processes a NOTIFY_PRINT_JOB_EVENT notification. - void OnNotifyPrintJobEvent(const JobEventDetails& event_details); - - // Requests the RenderView to render all the missing pages for the print job. - // No-op if no print job is pending. Returns true if at least one page has - // been requested to the renderer. - bool RenderAllMissingPagesNow(); - - // Quits the current message loop if these conditions hold true: a document is - // loaded and is complete and waiting_for_pages_to_be_rendered_ is true. This - // function is called in DidPrintPage() or on ALL_PAGES_REQUESTED - // notification. The inner message loop is created was created by - // RenderAllMissingPagesNow(). - void ShouldQuitFromInnerMessageLoop(); - - // Creates a new empty print job. It has no settings loaded. If there is - // currently a print job, safely disconnect from it. Returns false if it is - // impossible to safely disconnect from the current print job or it is - // impossible to create a new print job. - bool CreateNewPrintJob(PrintJobWorkerOwner* job); - - // Makes sure the current print_job_ has all its data before continuing, and - // disconnect from it. - void DisconnectFromCurrentPrintJob(); - - // Notify that the printing is done. - void PrintingDone(bool success); - - // Terminates the print job. No-op if no print job has been created. If - // |cancel| is true, cancel it instead of waiting for the job to finish. Will - // call ReleasePrintJob(). - void TerminatePrintJob(bool cancel); - - // Releases print_job_. Correctly deregisters from notifications. No-op if - // no print job has been created. - void ReleasePrintJob(); - - // Runs an inner message loop. It will set inside_inner_message_loop_ to true - // while the blocking inner message loop is running. This is useful in cases - // where the RenderView is about to be destroyed while a printing job isn't - // finished. - bool RunInnerMessageLoop(); - - // In the case of Scripted Printing, where the renderer is controlling the - // control flow, print_job_ is initialized whenever possible. No-op is - // print_job_ is initialized. - bool OpportunisticallyCreatePrintJob(int cookie); - - // Release the PrinterQuery associated with our |cookie_|. - void ReleasePrinterQuery(); - - content::NotificationRegistrar registrar_; - - // Manages the low-level talk to the printer. - scoped_refptr print_job_; - - // Number of pages to print in the print job. - int number_pages_; - - // Indication of success of the print job. - bool printing_succeeded_; - - // Running an inner message loop inside RenderAllMissingPagesNow(). This means - // we are _blocking_ until all the necessary pages have been rendered or the - // print settings are being loaded. - bool inside_inner_message_loop_; - -#if !defined(OS_MACOSX) - // Set to true when OnDidPrintPage() should be expecting the first page. - bool expecting_first_page_; -#endif // OS_MACOSX - - // The document cookie of the current PrinterQuery. - int cookie_; - - // Whether printing is enabled. - bool printing_enabled_; - - scoped_refptr queue_; - - DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBase); -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_ diff --git a/chromium_src/chrome/browser/printing/print_view_manager_basic.cc b/chromium_src/chrome/browser/printing/print_view_manager_basic.cc deleted file mode 100644 index d978999a07105..0000000000000 --- a/chromium_src/chrome/browser/printing/print_view_manager_basic.cc +++ /dev/null @@ -1,48 +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. - -#include "chrome/browser/printing/print_view_manager_basic.h" - -#if defined(OS_ANDROID) -#include "base/file_descriptor_posix.h" -#include "chrome/common/print_messages.h" -#include "printing/printing_context_android.h" -#endif - -DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManagerBasic); - -namespace printing { - -PrintViewManagerBasic::PrintViewManagerBasic(content::WebContents* web_contents) - : PrintViewManagerBase(web_contents) { -} - -PrintViewManagerBasic::~PrintViewManagerBasic() { -} - -#if defined(OS_ANDROID) -void PrintViewManagerBasic::RenderProcessGone(base::TerminationStatus status) { - PrintingContextAndroid::PdfWritingDone(file_descriptor_.fd, false); - file_descriptor_ = base::FileDescriptor(-1, false); - PrintViewManagerBase::RenderProcessGone(status); -} - -void PrintViewManagerBasic::OnPrintingFailed(int cookie) { - PrintingContextAndroid::PdfWritingDone(file_descriptor_.fd, false); - file_descriptor_ = base::FileDescriptor(-1, false); - PrintViewManagerBase::OnPrintingFailed(cookie); -} - -bool PrintViewManagerBasic::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBasic, message) - IPC_MESSAGE_HANDLER(PrintHostMsg_PrintingFailed, OnPrintingFailed) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - return handled ? true : PrintViewManagerBase::OnMessageReceived(message); -} -#endif - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_view_manager_basic.h b/chromium_src/chrome/browser/printing/print_view_manager_basic.h deleted file mode 100644 index 553c555cc3a6b..0000000000000 --- a/chromium_src/chrome/browser/printing/print_view_manager_basic.h +++ /dev/null @@ -1,57 +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_PRINTING_PRINT_VIEW_MANAGER_BASIC_H_ -#define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASIC_H_ - -#include "chrome/browser/printing/print_view_manager_base.h" -#include "content/public/browser/web_contents_user_data.h" - -#if defined(OS_ANDROID) -#include "base/file_descriptor_posix.h" -#endif - -namespace printing { - -// Manages the print commands for a WebContents - basic version. -class PrintViewManagerBasic - : public PrintViewManagerBase, - public content::WebContentsUserData { - public: - virtual ~PrintViewManagerBasic(); - -#if defined(OS_ANDROID) - // Sets the file descriptor into which the PDF will be written. - void set_file_descriptor(const base::FileDescriptor& file_descriptor) { - file_descriptor_ = file_descriptor; - } - - // Gets the file descriptor into which the PDF will be written. - base::FileDescriptor file_descriptor() const { return file_descriptor_; } - - // content::WebContentsObserver implementation. - // Terminates or cancels the print job if one was pending. - virtual void RenderProcessGone(base::TerminationStatus status) override; - - // content::WebContentsObserver implementation. - virtual bool OnMessageReceived(const IPC::Message& message) override; -#endif - - private: - explicit PrintViewManagerBasic(content::WebContents* web_contents); - friend class content::WebContentsUserData; - -#if defined(OS_ANDROID) - virtual void OnPrintingFailed(int cookie) override; - - // The file descriptor into which the PDF of the page will be written. - base::FileDescriptor file_descriptor_; -#endif - - DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBasic); -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASIC_H_ diff --git a/chromium_src/chrome/browser/printing/print_view_manager_observer.h b/chromium_src/chrome/browser/printing/print_view_manager_observer.h deleted file mode 100644 index 55cd28c62d2e1..0000000000000 --- a/chromium_src/chrome/browser/printing/print_view_manager_observer.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2011 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_PRINTING_PRINT_VIEW_MANAGER_OBSERVER_H_ -#define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_OBSERVER_H_ - -namespace printing { - -// An interface the PrintViewManager uses to notify an observer when the print -// dialog is shown. Register the observer via PrintViewManager::set_observer. -class PrintViewManagerObserver { - public: - // Notifies the observer that the print dialog was shown. - virtual void OnPrintDialogShown() = 0; - - protected: - virtual ~PrintViewManagerObserver() {} -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_OBSERVER_H_ diff --git a/chromium_src/chrome/browser/printing/printer_query.cc b/chromium_src/chrome/browser/printing/printer_query.cc deleted file mode 100644 index 72e2b85f635c4..0000000000000 --- a/chromium_src/chrome/browser/printing/printer_query.cc +++ /dev/null @@ -1,128 +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/printing/printer_query.h" - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/message_loop/message_loop.h" -#include "base/threading/thread_restrictions.h" -#include "base/values.h" -#include "chrome/browser/printing/print_job_worker.h" - -namespace printing { - -PrinterQuery::PrinterQuery(int render_process_id, int render_view_id) - : worker_(new PrintJobWorker(render_process_id, render_view_id, this)), - is_print_dialog_box_shown_(false), - cookie_(PrintSettings::NewCookie()), - last_status_(PrintingContext::FAILED) { - DCHECK(base::MessageLoopForIO::IsCurrent()); -} - -PrinterQuery::~PrinterQuery() { - // The job should be finished (or at least canceled) when it is destroyed. - DCHECK(!is_print_dialog_box_shown_); - // If this fires, it is that this pending printer context has leaked. - DCHECK(!worker_.get()); -} - -void PrinterQuery::GetSettingsDone(const PrintSettings& new_settings, - PrintingContext::Result result) { - is_print_dialog_box_shown_ = false; - last_status_ = result; - if (result != PrintingContext::FAILED) { - settings_ = new_settings; - cookie_ = PrintSettings::NewCookie(); - } else { - // Failure. - cookie_ = 0; - } - - if (!callback_.is_null()) { - // This may cause reentrancy like to call StopWorker(). - callback_.Run(); - callback_.Reset(); - } -} - -PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) { - DCHECK(callback_.is_null()); - DCHECK(worker_.get()); - - worker_->SetNewOwner(new_owner); - return worker_.release(); -} - -const PrintSettings& PrinterQuery::settings() const { - return settings_; -} - -int PrinterQuery::cookie() const { - return cookie_; -} - -void PrinterQuery::GetSettings( - GetSettingsAskParam ask_user_for_settings, - int expected_page_count, - bool has_selection, - MarginType margin_type, - const base::Closure& callback) { - DCHECK(RunsTasksOnCurrentThread()); - DCHECK(!is_print_dialog_box_shown_); - - StartWorker(callback); - - // Real work is done in PrintJobWorker::GetSettings(). - is_print_dialog_box_shown_ = ask_user_for_settings == ASK_USER; - worker_->PostTask(FROM_HERE, - base::Bind(&PrintJobWorker::GetSettings, - base::Unretained(worker_.get()), - is_print_dialog_box_shown_, - expected_page_count, - has_selection, - margin_type)); -} - -void PrinterQuery::SetSettings(std::unique_ptr new_settings, - const base::Closure& callback) { - StartWorker(callback); - - worker_->PostTask(FROM_HERE, - base::Bind(&PrintJobWorker::SetSettings, - base::Unretained(worker_.get()), - base::Passed(&new_settings))); -} - -void PrinterQuery::StartWorker(const base::Closure& callback) { - DCHECK(callback_.is_null()); - DCHECK(worker_.get()); - - // Lazily create the worker thread. There is one worker thread per print job. - if (!worker_->IsRunning()) - worker_->Start(); - - callback_ = callback; -} - -void PrinterQuery::StopWorker() { - if (worker_.get()) { - // http://crbug.com/66082: We're blocking on the PrinterQuery's worker - // thread. It's not clear to me if this may result in blocking the current - // thread for an unacceptable time. We should probably fix it. - base::ThreadRestrictions::ScopedAllowIO allow_io; - worker_->Stop(); - worker_.reset(); - } -} - -bool PrinterQuery::is_callback_pending() const { - return !callback_.is_null(); -} - -bool PrinterQuery::is_valid() const { - return worker_.get() != NULL; -} - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/printer_query.h b/chromium_src/chrome/browser/printing/printer_query.h deleted file mode 100644 index d2f017d1895ca..0000000000000 --- a/chromium_src/chrome/browser/printing/printer_query.h +++ /dev/null @@ -1,99 +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_PRINTING_PRINTER_QUERY_H_ -#define CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_ - -#include - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "chrome/browser/printing/print_job_worker_owner.h" -#include "printing/print_job_constants.h" - -namespace base { -class DictionaryValue; -} - -namespace printing { - -class PrintDestinationInterface; -class PrintJobWorker; - -// Query the printer for settings. -class PrinterQuery : public PrintJobWorkerOwner { - public: - // GetSettings() UI parameter. - enum GetSettingsAskParam { - DEFAULTS, - ASK_USER, - }; - - PrinterQuery(int render_process_id, int render_view_id); - - // PrintJobWorkerOwner implementation. - virtual void GetSettingsDone(const PrintSettings& new_settings, - PrintingContext::Result result) override; - virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) override; - virtual const PrintSettings& settings() const override; - virtual int cookie() const override; - - // Initializes the printing context. It is fine to call this function multiple - // times to reinitialize the settings. |web_contents_observer| can be queried - // to find the owner of the print setting dialog box. It is unused when - // |ask_for_user_settings| is DEFAULTS. - void GetSettings( - GetSettingsAskParam ask_user_for_settings, - int expected_page_count, - bool has_selection, - MarginType margin_type, - const base::Closure& callback); - - // Updates the current settings with |new_settings| dictionary values. - void SetSettings(std::unique_ptr new_settings, - const base::Closure& callback); - - // Stops the worker thread since the client is done with this object. - void StopWorker(); - - // Returns true if a GetSettings() call is pending completion. - bool is_callback_pending() const; - - PrintingContext::Result last_status() const { return last_status_; } - - // Returns if a worker thread is still associated to this instance. - bool is_valid() const; - - private: - virtual ~PrinterQuery(); - - // Lazy create the worker thread. There is one worker thread per print job. - void StartWorker(const base::Closure& callback); - - // All the UI is done in a worker thread because many Win32 print functions - // are blocking and enters a message loop without your consent. There is one - // worker thread per print job. - std::unique_ptr worker_; - - // Cache of the print context settings for access in the UI thread. - PrintSettings settings_; - - // Is the Print... dialog box currently shown. - bool is_print_dialog_box_shown_; - - // Cookie that make this instance unique. - int cookie_; - - // Results from the last GetSettingsDone() callback. - PrintingContext::Result last_status_; - - // Callback waiting to be run. - base::Closure callback_; - - DISALLOW_COPY_AND_ASSIGN(PrinterQuery); -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_ diff --git a/chromium_src/chrome/browser/printing/printing_message_filter.cc b/chromium_src/chrome/browser/printing/printing_message_filter.cc deleted file mode 100644 index 819c6af5b0202..0000000000000 --- a/chromium_src/chrome/browser/printing/printing_message_filter.cc +++ /dev/null @@ -1,426 +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/printing/printing_message_filter.h" - -#include - -#include "base/bind.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/printing/print_job_manager.h" -#include "chrome/browser/printing/printer_query.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_io_data.h" -#include "chrome/common/print_messages.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/child_process_host.h" - -#if defined(ENABLE_FULL_PRINTING) -#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" -#endif - -#if defined(OS_CHROMEOS) -#include - -#include - -#include "base/files/file_util.h" -#include "base/lazy_instance.h" -#include "chrome/browser/printing/print_dialog_cloud.h" -#endif - -#if defined(OS_ANDROID) -#include "base/strings/string_number_conversions.h" -#include "chrome/browser/printing/print_view_manager_basic.h" -#include "printing/printing_context_android.h" -#endif - -using content::BrowserThread; - -namespace printing { - -namespace { - -#if defined(OS_CHROMEOS) -typedef std::map SequenceToPathMap; - -struct PrintingSequencePathMap { - SequenceToPathMap map; - int sequence; -}; - -// No locking, only access on the FILE thread. -static base::LazyInstance - g_printing_file_descriptor_map = LAZY_INSTANCE_INITIALIZER; -#endif - -void RenderParamsFromPrintSettings(const PrintSettings& settings, - PrintMsg_Print_Params* params) { - params->page_size = settings.page_setup_device_units().physical_size(); - params->content_size.SetSize( - settings.page_setup_device_units().content_area().width(), - settings.page_setup_device_units().content_area().height()); - params->printable_area.SetRect( - settings.page_setup_device_units().printable_area().x(), - settings.page_setup_device_units().printable_area().y(), - settings.page_setup_device_units().printable_area().width(), - settings.page_setup_device_units().printable_area().height()); - params->margin_top = settings.page_setup_device_units().content_area().y(); - params->margin_left = settings.page_setup_device_units().content_area().x(); - params->dpi = settings.dpi(); - // Currently hardcoded at 72dpi. See PrintSettings' constructor. - params->desired_dpi = settings.desired_dpi(); - // Always use an invalid cookie. - params->document_cookie = 0; - params->selection_only = settings.selection_only(); - params->supports_alpha_blend = settings.supports_alpha_blend(); - params->should_print_backgrounds = settings.should_print_backgrounds(); - params->title = settings.title(); - params->url = settings.url(); -} - -} // namespace - -PrintingMessageFilter::PrintingMessageFilter(int render_process_id) - : BrowserMessageFilter(PrintMsgStart), - render_process_id_(render_process_id), - queue_(g_browser_process->print_job_manager()->queue()) { - DCHECK(queue_.get()); -} - -PrintingMessageFilter::~PrintingMessageFilter() { -} - -void PrintingMessageFilter::OverrideThreadForMessage( - const IPC::Message& message, BrowserThread::ID* thread) { -#if defined(OS_CHROMEOS) - if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID || - message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) { - *thread = BrowserThread::FILE; - } -#elif defined(OS_ANDROID) - if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID || - message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) { - *thread = BrowserThread::UI; - } -#endif -} - -bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PrintingMessageFilter, message) -#if defined(OS_WIN) - IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection) -#endif -#if defined(OS_CHROMEOS) || defined(OS_ANDROID) - IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting, - OnAllocateTempFileForPrinting) - IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten, - OnTempFileForPrintingWritten) -#endif - IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, - OnGetDefaultPrintSettings) - IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint) - IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings, - OnUpdatePrintSettings) -#if defined(ENABLE_FULL_PRINTING) - IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel) -#endif - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -#if defined(OS_WIN) -void PrintingMessageFilter::OnDuplicateSection( - base::SharedMemoryHandle renderer_handle, - base::SharedMemoryHandle* browser_handle) { - // Duplicate the handle in this process right now so the memory is kept alive - // (even if it is not mapped) - base::SharedMemory shared_buf(renderer_handle, true); - shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle); -} -#endif - -#if defined(OS_CHROMEOS) || defined(OS_ANDROID) -void PrintingMessageFilter::OnAllocateTempFileForPrinting( - int render_view_id, - base::FileDescriptor* temp_file_fd, - int* sequence_number) { -#if defined(OS_CHROMEOS) - // TODO(thestig): Use |render_view_id| for Chrome OS. - DCHECK_CURRENTLY_ON(BrowserThread::FILE); - temp_file_fd->fd = *sequence_number = -1; - temp_file_fd->auto_close = false; - - SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map; - *sequence_number = g_printing_file_descriptor_map.Get().sequence++; - - base::FilePath path; - if (base::CreateTemporaryFile(&path)) { - int fd = open(path.value().c_str(), O_WRONLY); - if (fd >= 0) { - SequenceToPathMap::iterator it = map->find(*sequence_number); - if (it != map->end()) { - NOTREACHED() << "Sequence number already in use. seq=" << - *sequence_number; - } else { - (*map)[*sequence_number] = path; - temp_file_fd->fd = fd; - temp_file_fd->auto_close = true; - } - } - } -#elif defined(OS_ANDROID) - DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::WebContents* wc = GetWebContentsForRenderView(render_view_id); - if (!wc) - return; - PrintViewManagerBasic* print_view_manager = - PrintViewManagerBasic::FromWebContents(wc); - // The file descriptor is originally created in & passed from the Android - // side, and it will handle the closing. - const base::FileDescriptor& file_descriptor = - print_view_manager->file_descriptor(); - temp_file_fd->fd = file_descriptor.fd; - temp_file_fd->auto_close = false; -#endif -} - -void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id, - int sequence_number) { -#if defined(OS_CHROMEOS) - DCHECK_CURRENTLY_ON(BrowserThread::FILE); - SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map; - SequenceToPathMap::iterator it = map->find(sequence_number); - if (it == map->end()) { - NOTREACHED() << "Got a sequence that we didn't pass to the " - "renderer: " << sequence_number; - return; - } - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&PrintingMessageFilter::CreatePrintDialogForFile, - this, render_view_id, it->second)); - - // Erase the entry in the map. - map->erase(it); -#elif defined(OS_ANDROID) - DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::WebContents* wc = GetWebContentsForRenderView(render_view_id); - if (!wc) - return; - PrintViewManagerBasic* print_view_manager = - PrintViewManagerBasic::FromWebContents(wc); - const base::FileDescriptor& file_descriptor = - print_view_manager->file_descriptor(); - PrintingContextAndroid::PdfWritingDone(file_descriptor.fd, true); - // Invalidate the file descriptor so it doesn't accidentally get reused. - print_view_manager->set_file_descriptor(base::FileDescriptor(-1, false)); -#endif -} -#endif // defined(OS_CHROMEOS) || defined(OS_ANDROID) - -#if defined(OS_CHROMEOS) -void PrintingMessageFilter::CreatePrintDialogForFile( - int render_view_id, - const base::FilePath& path) { - content::WebContents* wc = GetWebContentsForRenderView(render_view_id); - if (!wc) - return; - print_dialog_cloud::CreatePrintDialogForFile( - wc->GetBrowserContext(), - wc->GetTopLevelNativeWindow(), - path, - wc->GetTitle(), - base::string16(), - std::string("application/pdf")); -} -#endif // defined(OS_CHROMEOS) - -content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView( - int render_view_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::RenderViewHost* view = content::RenderViewHost::FromID( - render_process_id_, render_view_id); - return view ? content::WebContents::FromRenderViewHost(view) : NULL; -} - -void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - scoped_refptr printer_query; -#if 0 - if (!profile_io_data_->printing_enabled()->GetValue()) { - // Reply with NULL query. - OnGetDefaultPrintSettingsReply(printer_query, reply_msg); - return; - } -#endif - printer_query = queue_->PopPrinterQuery(0); - if (!printer_query.get()) { - printer_query = - queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id()); - } - - // Loads default settings. This is asynchronous, only the IPC message sender - // will hang until the settings are retrieved. - printer_query->GetSettings( - PrinterQuery::DEFAULTS, - 0, - false, - DEFAULT_MARGINS, - base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply, - this, - printer_query, - reply_msg)); -} - -void PrintingMessageFilter::OnGetDefaultPrintSettingsReply( - scoped_refptr printer_query, - IPC::Message* reply_msg) { - PrintMsg_Print_Params params; - if (!printer_query.get() || - printer_query->last_status() != PrintingContext::OK) { - params.Reset(); - } else { - RenderParamsFromPrintSettings(printer_query->settings(), ¶ms); - params.document_cookie = printer_query->cookie(); - } - PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, params); - Send(reply_msg); - // If printing was enabled. - if (printer_query.get()) { - // If user hasn't cancelled. - if (printer_query->cookie() && printer_query->settings().dpi()) { - queue_->QueuePrinterQuery(printer_query.get()); - } else { - printer_query->StopWorker(); - } - } -} - -void PrintingMessageFilter::OnScriptedPrint( - const PrintHostMsg_ScriptedPrint_Params& params, - IPC::Message* reply_msg) { - scoped_refptr printer_query = - queue_->PopPrinterQuery(params.cookie); - if (!printer_query.get()) { - printer_query = - queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id()); - } - printer_query->GetSettings( - PrinterQuery::ASK_USER, - params.expected_pages_count, - params.has_selection, - params.margin_type, - base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, - this, - printer_query, - reply_msg)); -} - -void PrintingMessageFilter::OnScriptedPrintReply( - scoped_refptr printer_query, - IPC::Message* reply_msg) { - PrintMsg_PrintPages_Params params; -#if defined(OS_ANDROID) - // We need to save the routing ID here because Send method below deletes the - // |reply_msg| before we can get the routing ID for the Android code. - int routing_id = reply_msg->routing_id(); -#endif - if (printer_query->last_status() != PrintingContext::OK || - !printer_query->settings().dpi()) { - params.Reset(); - } else { - RenderParamsFromPrintSettings(printer_query->settings(), ¶ms.params); - params.params.document_cookie = printer_query->cookie(); - params.pages = PageRange::GetPages(printer_query->settings().ranges()); - } - PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params); - Send(reply_msg); - if (params.params.dpi && params.params.document_cookie) { -#if defined(OS_ANDROID) - int file_descriptor; - const base::string16& device_name = printer_query->settings().device_name(); - if (base::StringToInt(device_name, &file_descriptor)) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&PrintingMessageFilter::UpdateFileDescriptor, this, - routing_id, file_descriptor)); - } -#endif - queue_->QueuePrinterQuery(printer_query.get()); - } else { - printer_query->StopWorker(); - } -} - -#if defined(OS_ANDROID) -void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::WebContents* wc = GetWebContentsForRenderView(render_view_id); - if (!wc) - return; - PrintViewManagerBasic* print_view_manager = - PrintViewManagerBasic::FromWebContents(wc); - print_view_manager->set_file_descriptor(base::FileDescriptor(fd, false)); -} -#endif - -void PrintingMessageFilter::OnUpdatePrintSettings( - int document_cookie, const base::DictionaryValue& job_settings, - IPC::Message* reply_msg) { - std::unique_ptr new_settings(job_settings.DeepCopy()); - - scoped_refptr printer_query; - printer_query = queue_->PopPrinterQuery(document_cookie); - if (!printer_query.get()) { - int host_id = render_process_id_; - int routing_id = reply_msg->routing_id(); - if (!new_settings->GetInteger(printing::kPreviewInitiatorHostId, - &host_id) || - !new_settings->GetInteger(printing::kPreviewInitiatorRoutingId, - &routing_id)) { - host_id = content::ChildProcessHost::kInvalidUniqueID; - routing_id = content::ChildProcessHost::kInvalidUniqueID; - } - printer_query = queue_->CreatePrinterQuery(host_id, routing_id); - } - printer_query->SetSettings( - std::move(new_settings), - base::Bind(&PrintingMessageFilter::OnUpdatePrintSettingsReply, this, - printer_query, reply_msg)); -} - -void PrintingMessageFilter::OnUpdatePrintSettingsReply( - scoped_refptr printer_query, - IPC::Message* reply_msg) { - PrintMsg_PrintPages_Params params; - if (!printer_query.get() || - printer_query->last_status() != PrintingContext::OK) { - params.Reset(); - } else { - RenderParamsFromPrintSettings(printer_query->settings(), ¶ms.params); - params.params.document_cookie = printer_query->cookie(); - params.pages = PageRange::GetPages(printer_query->settings().ranges()); - } - PrintHostMsg_UpdatePrintSettings::WriteReplyParams( - reply_msg, - params, - printer_query.get() && - (printer_query->last_status() == printing::PrintingContext::CANCEL)); - Send(reply_msg); - // If user hasn't cancelled. - if (printer_query.get()) { - if (printer_query->cookie() && printer_query->settings().dpi()) { - queue_->QueuePrinterQuery(printer_query.get()); - } else { - printer_query->StopWorker(); - } - } -} - -} // namespace printing diff --git a/chromium_src/chrome/browser/printing/printing_message_filter.h b/chromium_src/chrome/browser/printing/printing_message_filter.h deleted file mode 100644 index e8536a69c5a34..0000000000000 --- a/chromium_src/chrome/browser/printing/printing_message_filter.h +++ /dev/null @@ -1,124 +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_PRINTING_PRINTING_MESSAGE_FILTER_H_ -#define CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_ - -#include - -#include "base/compiler_specific.h" -#include "content/public/browser/browser_message_filter.h" - -#if defined(OS_WIN) -#include "base/memory/shared_memory.h" -#endif - -struct PrintHostMsg_ScriptedPrint_Params; -class Profile; -class ProfileIOData; - -namespace base { -class DictionaryValue; -class FilePath; -} - -namespace content { -class WebContents; -} - -namespace printing { - -class PrintJobManager; -class PrintQueriesQueue; -class PrinterQuery; - -// This class filters out incoming printing related IPC messages for the -// renderer process on the IPC thread. -class PrintingMessageFilter : public content::BrowserMessageFilter { - public: - PrintingMessageFilter(int render_process_id); - - // content::BrowserMessageFilter methods. - void OverrideThreadForMessage( - const IPC::Message& message, - content::BrowserThread::ID* thread) override; - bool OnMessageReceived(const IPC::Message& message) override; - - private: - virtual ~PrintingMessageFilter(); - -#if defined(OS_WIN) - // Used to pass resulting EMF from renderer to browser in printing. - void OnDuplicateSection(base::SharedMemoryHandle renderer_handle, - base::SharedMemoryHandle* browser_handle); -#endif - -#if defined(OS_CHROMEOS) || defined(OS_ANDROID) - // Used to ask the browser allocate a temporary file for the renderer - // to fill in resulting PDF in renderer. - void OnAllocateTempFileForPrinting(int render_view_id, - base::FileDescriptor* temp_file_fd, - int* sequence_number); - void OnTempFileForPrintingWritten(int render_view_id, int sequence_number); -#endif - -#if defined(OS_CHROMEOS) - void CreatePrintDialogForFile(int render_view_id, const base::FilePath& path); -#endif - -#if defined(OS_ANDROID) - // Updates the file descriptor for the PrintViewManagerBasic of a given - // render_view_id. - void UpdateFileDescriptor(int render_view_id, int fd); -#endif - - // Given a render_view_id get the corresponding WebContents. - // Must be called on the UI thread. - content::WebContents* GetWebContentsForRenderView(int render_view_id); - - // GetPrintSettingsForRenderView must be called via PostTask and - // base::Bind. Collapse the settings-specific params into a - // struct to avoid running into issues with too many params - // to base::Bind. - struct GetPrintSettingsForRenderViewParams; - - // Get the default print setting. - void OnGetDefaultPrintSettings(IPC::Message* reply_msg); - void OnGetDefaultPrintSettingsReply(scoped_refptr printer_query, - IPC::Message* reply_msg); - - // The renderer host have to show to the user the print dialog and returns - // the selected print settings. The task is handled by the print worker - // thread and the UI thread. The reply occurs on the IO thread. - void OnScriptedPrint(const PrintHostMsg_ScriptedPrint_Params& params, - IPC::Message* reply_msg); - void OnScriptedPrintReply(scoped_refptr printer_query, - IPC::Message* reply_msg); - - // Modify the current print settings based on |job_settings|. The task is - // handled by the print worker thread and the UI thread. The reply occurs on - // the IO thread. - void OnUpdatePrintSettings(int document_cookie, - const base::DictionaryValue& job_settings, - IPC::Message* reply_msg); - void OnUpdatePrintSettingsReply(scoped_refptr printer_query, - IPC::Message* reply_msg); - -#if defined(ENABLE_FULL_PRINTING) - // Check to see if print preview has been cancelled. - void OnCheckForCancel(int32_t preview_ui_id, - int preview_request_id, - bool* cancel); -#endif - - const int render_process_id_; - - scoped_refptr queue_; - - DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilter); -}; - -} // namespace printing - -#endif // CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.cc b/chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.cc deleted file mode 100644 index 311d62192f984..0000000000000 --- a/chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.cc +++ /dev/null @@ -1,19 +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. - -#include "chrome/browser/printing/printing_ui_web_contents_observer.h" - -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/web_contents.h" - -PrintingUIWebContentsObserver::PrintingUIWebContentsObserver( - content::WebContents* web_contents) - : content::WebContentsObserver(web_contents) { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); -} - -gfx::NativeView PrintingUIWebContentsObserver::GetParentView() { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - return web_contents() ? web_contents()->GetNativeView() : NULL; -} diff --git a/chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.h b/chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.h deleted file mode 100644 index de969f5cdb550..0000000000000 --- a/chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.h +++ /dev/null @@ -1,24 +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_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_ -#define CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_ - -#include "content/public/browser/web_contents_observer.h" -#include "ui/gfx/native_widget_types.h" - -// Wrapper used to keep track of the lifetime of a WebContents. -// Lives on the UI thread. -class PrintingUIWebContentsObserver : public content::WebContentsObserver { - public: - explicit PrintingUIWebContentsObserver(content::WebContents* web_contents); - - // Return the parent NativeView of the observed WebContents. - gfx::NativeView GetParentView(); - - private: - DISALLOW_COPY_AND_ASSIGN(PrintingUIWebContentsObserver); -}; - -#endif // CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_ diff --git a/chromium_src/chrome/browser/process_singleton.h b/chromium_src/chrome/browser/process_singleton.h deleted file mode 100644 index eab6c35479a35..0000000000000 --- a/chromium_src/chrome/browser/process_singleton.h +++ /dev/null @@ -1,181 +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/threading/non_thread_safe.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 base::NonThreadSafe { - 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::Callback; - - 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(); - - // 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::Callback; - 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::Callback& 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_; -#endif - - 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 bb999fb500cfe..0000000000000 --- a/chromium_src/chrome/browser/process_singleton_posix.cc +++ /dev/null @@ -1,1078 +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 "atom/common/atom_command_line.h" -#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/location.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.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/threading/platform_thread.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/time/time.h" -#include "base/timer/timer.h" -#include "content/public/browser/browser_thread.h" -#include "net/base/network_interfaces.h" -#include "ui/base/l10n/l10n_util.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 = arraysize(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, NULL, NULL, &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() < arraysize(addr->sun_path)) - << "Socket path too long: " << path; - base::strlcpy(addr->sun_path, path.c_str(), arraysize(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"; - - int rv = base::SetNonBlocking(sock); - DCHECK_EQ(0, rv) << "Failed to make non-blocking socket."; - 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) { - // TODO: yolo - 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()); - 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::Uint64ToString(base::RandUint64()); -} - -bool CheckCookie(const base::FilePath& path, const base::FilePath& cookie) { - return (cookie == ReadLink(path)); -} - -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_MACOSX) -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, false)) { - PLOG(ERROR) << "Could not delete old singleton lock."; - return false; - } - - return SymlinkPath(symlink_content, lock_path); -} -#endif // defined(OS_MACOSX) - -} // 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::MessageLoopForIO::Watcher, - public base::MessageLoop::DestructionObserver, - public base::RefCountedThreadSafe { - public: - // A helper class to read message from an established socket. - class SocketReader : public base::MessageLoopForIO::Watcher { - public: - SocketReader(ProcessSingleton::LinuxWatcher* parent, - base::MessageLoop* ui_message_loop, - int fd) - : parent_(parent), - ui_message_loop_(ui_message_loop), - fd_(fd), - bytes_read_(0) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - // Wait for reads. - base::MessageLoopForIO::current()->WatchFileDescriptor( - fd, true, base::MessageLoopForIO::WATCH_READ, &fd_reader_, 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() override { CloseSocket(fd_); } - - // MessageLoopForIO::Watcher impl. - void OnFileCanReadWithoutBlocking(int fd) override; - void OnFileCanWriteWithoutBlocking(int fd) override { - // SocketReader only watches for accept (read) events. - NOTREACHED(); - } - - // 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 CleanupAndDeleteSelf() { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - - parent_->RemoveSocketReader(this); - // We're deleted beyond this point. - } - - base::MessageLoopForIO::FileDescriptorWatcher fd_reader_; - - // The ProcessSingleton::LinuxWatcher that owns us. - ProcessSingleton::LinuxWatcher* const parent_; - - // A reference to the UI message loop. - base::MessageLoop* const ui_message_loop_; - - // 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_message_loop_(base::MessageLoop::current()), - 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); - - // MessageLoopForIO::Watcher impl. These run on the IO thread. - void OnFileCanReadWithoutBlocking(int fd) override; - void OnFileCanWriteWithoutBlocking(int fd) override { - // ProcessSingleton only watches for accept (read) events. - NOTREACHED(); - } - - // MessageLoop::DestructionObserver - void WillDestroyCurrentMessageLoop() override { - fd_watcher_.StopWatchingFileDescriptor(); - } - - private: - friend struct BrowserThread::DeleteOnThread; - friend class base::DeleteHelper; - - ~LinuxWatcher() override { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - STLDeleteElements(&readers_); - - base::MessageLoopForIO* ml = base::MessageLoopForIO::current(); - ml->RemoveDestructionObserver(this); - } - - // Removes and deletes the SocketReader. - void RemoveSocketReader(SocketReader* reader); - - base::MessageLoopForIO::FileDescriptorWatcher fd_watcher_; - - // A reference to the UI message loop (i.e., the message loop we were - // constructed on). - base::MessageLoop* ui_message_loop_; - - // The ProcessSingleton that owns us. - ProcessSingleton* const parent_; - - std::set readers_; - - DISALLOW_COPY_AND_ASSIGN(LinuxWatcher); -}; - -void ProcessSingleton::LinuxWatcher::OnFileCanReadWithoutBlocking(int fd) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - // Accepting incoming client. - sockaddr_un from; - socklen_t from_len = sizeof(from); - int connection_socket = HANDLE_EINTR(accept( - fd, reinterpret_cast(&from), &from_len)); - if (-1 == connection_socket) { - PLOG(ERROR) << "accept() failed"; - return; - } - int rv = base::SetNonBlocking(connection_socket); - DCHECK_EQ(0, rv) << "Failed to make non-blocking socket."; - SocketReader* reader = new SocketReader(this, - ui_message_loop_, - connection_socket); - readers_.insert(reader); -} - -void ProcessSingleton::LinuxWatcher::StartListening(int socket) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - // Watch for client connections on this socket. - base::MessageLoopForIO* ml = base::MessageLoopForIO::current(); - ml->AddDestructionObserver(this); - ml->WatchFileDescriptor(socket, true, base::MessageLoopForIO::WATCH_READ, - &fd_watcher_, this); -} - -void ProcessSingleton::LinuxWatcher::HandleMessage( - const std::string& current_dir, const std::vector& argv, - SocketReader* reader) { - DCHECK(ui_message_loop_ == base::MessageLoop::current()); - 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, arraysize(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, arraysize(kShutdownToken) - 1); - return; - } -} - -void ProcessSingleton::LinuxWatcher::RemoveSocketReader(SocketReader* reader) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK(reader); - readers_.erase(reader); - delete reader; -} - -/////////////////////////////////////////////////////////////////////////////// -// ProcessSingleton::LinuxWatcher::SocketReader -// - -void ProcessSingleton::LinuxWatcher::SocketReader::OnFileCanReadWithoutBlocking( - int fd) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - DCHECK_EQ(fd, fd_); - 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 = arraysize(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_message_loop_->task_runner()->PostTask( - FROM_HERE, base::Bind(&ProcessSingleton::LinuxWatcher::HandleMessage, - parent_, current_dir, tokens, this)); - fd_reader_.StopWatchingFileDescriptor(); - - // 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"; - - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&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::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::Bind(&ProcessSingleton::KillProcess, - base::Unretained(this)); -} - -ProcessSingleton::~ProcessSingleton() { -} - -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 (!PathService::Get(base::DIR_CURRENT, ¤t_dir)) - return PROCESS_NONE; - to_send.append(current_dir.value()); - - const std::vector& argv = atom::AtomCommandLine::argv(); - for (std::vector::const_iterator it = argv.begin(); - it != argv.end(); ++it) { - to_send.push_back(kTokenDelimiter); - to_send.append(*it); - } - - // 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, arraysize(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, arraysize(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)); -} - -ProcessSingleton::NotifyResult -ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate( - const base::CommandLine& command_line, - int retry_attempts, - const base::TimeDelta& timeout) { - NotifyResult result = NotifyOtherProcessWithTimeout( - command_line, retry_attempts, timeout, true); - if (result != PROCESS_NONE) - return result; - if (Create()) - 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_NONE) - return result; - - return LOCK_ERROR; -} - -void ProcessSingleton::OverrideCurrentPidForTesting(base::ProcessId pid) { - current_pid_ = pid; -} - -void ProcessSingleton::OverrideKillCallbackForTesting( - const base::Callback& callback) { - kill_callback_ = callback; -} - -void ProcessSingleton::DisablePromptForTesting() { - g_disable_prompt = true; -} - -bool ProcessSingleton::Create() { - 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_MACOSX) - // 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 defined(MAS_BUILD) - // For Mac App Store build, 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; - } -#endif - - // Check that the directory was created with the correct permissions. - int dir_mode = 0; - CHECK(base::GetPosixFilePermissions(socket_dir_.path(), &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_.path().Append(kSingletonSocketFilename); - base::FilePath cookie(GenerateCookie()); - base::FilePath remote_cookie_path = - socket_dir_.path().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); - - // In Electron the ProcessSingleton is created earlier than the IO - // thread gets created, so we have to postpone the call until message - // loop is up an running. - scoped_refptr task_runner = - base::ThreadTaskRunnerHandle::Get(); - task_runner->PostTask( - FROM_HERE, - base::Bind(&ProcessSingleton::StartListening, - base::Unretained(this), sock)); - - return true; -} - -void ProcessSingleton::Cleanup() { - UnlinkPath(socket_path_); - UnlinkPath(cookie_path_); - UnlinkPath(lock_path_); -} - -void ProcessSingleton::StartListening(int sock) { - watcher_ = new LinuxWatcher(this); - DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO)); - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&ProcessSingleton::LinuxWatcher::StartListening, - watcher_.get(), - sock)); -} - -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 b488ad4576742..0000000000000 --- a/chromium_src/chrome/browser/process_singleton_win.cc +++ /dev/null @@ -1,330 +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/chrome_process_finder_win.h" -#include "content/public/common/result_codes.h" -#include "net/base/escape.h" -#include "ui/base/l10n/l10n_util.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; -} - -// Convert Command line string to argv. -base::CommandLine::StringVector CommandLineStringToArgv( - const std::wstring& command_line_string) { - int num_args = 0; - wchar_t** args = NULL; - args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args); - base::CommandLine::StringVector argv; - for (int i = 0; i < num_args; ++i) - argv.push_back(std::wstring(args[i])); - LocalFree(args); - return argv; -} - -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 = CommandLineStringToArgv(cmd_line); - 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::Bind(&TerminateAppWithError)) { - // The user_data_dir may have not been created yet. - base::CreateDirectoryAndGetError(user_data_dir, nullptr); -} - -ProcessSingleton::~ProcessSingleton() { - 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_, false)) { - 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; -} - -// 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::Bind(&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/renderer_host/pepper/chrome_browser_pepper_host_factory.cc b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc deleted file mode 100644 index 5364aa0b881fe..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc +++ /dev/null @@ -1,93 +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/renderer_host/pepper/chrome_browser_pepper_host_factory.h" - -#include "build/build_config.h" -#include "chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h" -#include "chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h" -#include "chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h" -#include "chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h" -#include "chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h" -#include "content/public/browser/browser_ppapi_host.h" -#include "ppapi/host/message_filter_host.h" -#include "ppapi/host/ppapi_host.h" -#include "ppapi/host/resource_host.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/shared_impl/ppapi_permissions.h" - -using ppapi::host::MessageFilterHost; -using ppapi::host::ResourceHost; -using ppapi::host::ResourceMessageFilter; - -namespace chrome { - -ChromeBrowserPepperHostFactory::ChromeBrowserPepperHostFactory( - content::BrowserPpapiHost* host) - : host_(host) {} - -ChromeBrowserPepperHostFactory::~ChromeBrowserPepperHostFactory() {} - -std::unique_ptr ChromeBrowserPepperHostFactory::CreateResourceHost( - ppapi::host::PpapiHost* host, - PP_Resource resource, - PP_Instance instance, - const IPC::Message& message) { - DCHECK(host == host_->GetPpapiHost()); - - // Make sure the plugin is giving us a valid instance for this resource. - if (!host_->IsValidInstance(instance)) - return std::unique_ptr(); - - // Private interfaces. - if (host_->GetPpapiHost()->permissions().HasPermission( - ppapi::PERMISSION_PRIVATE)) { - switch (message.type()) { - case PpapiHostMsg_Broker_Create::ID: { - scoped_refptr broker_filter( - new PepperBrokerMessageFilter(instance, host_)); - return std::unique_ptr(new MessageFilterHost( - host_->GetPpapiHost(), instance, resource, broker_filter)); - } - } - } - - // Flash interfaces. - if (host_->GetPpapiHost()->permissions().HasPermission( - ppapi::PERMISSION_FLASH)) { - switch (message.type()) { - case PpapiHostMsg_Flash_Create::ID: - return std::unique_ptr( - new PepperFlashBrowserHost(host_, instance, resource)); - case PpapiHostMsg_FlashClipboard_Create::ID: { - scoped_refptr clipboard_filter( - new PepperFlashClipboardMessageFilter); - return std::unique_ptr(new MessageFilterHost( - host_->GetPpapiHost(), instance, resource, clipboard_filter)); - } - case PpapiHostMsg_FlashDRM_Create::ID: - return std::unique_ptr( - new chrome::PepperFlashDRMHost(host_, instance, resource)); - } - } - - // Permissions for the following interfaces will be checked at the - // time of the corresponding instance's methods calls (because - // permission check can be performed only on the UI - // thread). Currently these interfaces are available only for - // whitelisted apps which may not have access to the other private - // interfaces. - if (message.type() == PpapiHostMsg_IsolatedFileSystem_Create::ID) { - PepperIsolatedFileSystemMessageFilter* isolated_fs_filter = - PepperIsolatedFileSystemMessageFilter::Create(instance, host_); - if (!isolated_fs_filter) - return std::unique_ptr(); - return std::unique_ptr( - new MessageFilterHost(host, instance, resource, isolated_fs_filter)); - } - - return std::unique_ptr(); -} - -} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h b/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h deleted file mode 100644 index 84385140ceca7..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h +++ /dev/null @@ -1,38 +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_RENDERER_HOST_PEPPER_CHROME_BROWSER_PEPPER_HOST_FACTORY_H_ -#define CHROME_BROWSER_RENDERER_HOST_PEPPER_CHROME_BROWSER_PEPPER_HOST_FACTORY_H_ - -#include "base/macros.h" -#include "ppapi/host/host_factory.h" - -namespace content { -class BrowserPpapiHost; -} // namespace content - -namespace chrome { - -class ChromeBrowserPepperHostFactory : public ppapi::host::HostFactory { - public: - // Non-owning pointer to the filter must outlive this class. - explicit ChromeBrowserPepperHostFactory(content::BrowserPpapiHost* host); - ~ChromeBrowserPepperHostFactory() override; - - std::unique_ptr CreateResourceHost( - ppapi::host::PpapiHost* host, - PP_Resource resource, - PP_Instance instance, - const IPC::Message& message) override; - - private: - // Non-owning pointer. - content::BrowserPpapiHost* host_; - - DISALLOW_COPY_AND_ASSIGN(ChromeBrowserPepperHostFactory); -}; - -} // namespace chrome - -#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_CHROME_BROWSER_PEPPER_HOST_FACTORY_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.h b/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.h deleted file mode 100644 index cc10ee85780ca..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.h +++ /dev/null @@ -1,52 +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. - -#ifndef CHROME_BROWSER_RENDERER_HOST_PEPPER_MONITOR_FINDER_MAC_H_ -#define CHROME_BROWSER_RENDERER_HOST_PEPPER_MONITOR_FINDER_MAC_H_ - -#include -#include - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/lock.h" - -namespace chrome { - -// MonitorFinder maps a RenderFrameHost to the display ID on which the widget -// is painting. This class operates on the IO thread while the RenderFrameHost -// is on the UI thread, so the value returned by GetMonitor() may be 0 until -// the information can be retrieved asynchronously. -class MonitorFinder : public base::RefCountedThreadSafe { - public: - MonitorFinder(int process_id, int render_frame_id); - - // Gets the native display ID for the tuple. - int64_t GetMonitor(); - - // Checks if the given |monitor_id| represents a built-in display. - static bool IsMonitorBuiltIn(int64_t monitor_id); - - private: - friend class base::RefCountedThreadSafe; - ~MonitorFinder(); - - // Method run on the UI thread to get the display information. - void FetchMonitorFromWidget(); - - const int process_id_; - const int render_frame_id_; - - base::Lock mutex_; // Protects the two members below. - // Whether one request to FetchMonitorFromWidget() has been made already. - bool request_sent_; - // The native display ID for the RenderFrameHost. - CGDirectDisplayID display_id_; - - DISALLOW_COPY_AND_ASSIGN(MonitorFinder); -}; - -} // namespace chrome - -#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_MONITOR_FINDER_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.mm b/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.mm deleted file mode 100644 index 31f6cfd41060f..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/monitor_finder_mac.mm +++ /dev/null @@ -1,62 +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. - -#include "chrome/browser/renderer_host/pepper/monitor_finder_mac.h" - -#import - -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_frame_host.h" - -namespace chrome { - -MonitorFinder::MonitorFinder(int process_id, int render_frame_id) - : process_id_(process_id), - render_frame_id_(render_frame_id), - request_sent_(false), - display_id_(kCGNullDirectDisplay) {} - -MonitorFinder::~MonitorFinder() {} - -int64_t MonitorFinder::GetMonitor() { - { - // The plugin may call this method several times, so avoid spamming the UI - // thread with requests by only allowing one outstanding request at a time. - base::AutoLock lock(mutex_); - if (request_sent_) - return display_id_; - request_sent_ = true; - } - - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&MonitorFinder::FetchMonitorFromWidget, this)); - return display_id_; -} - -// static -bool MonitorFinder::IsMonitorBuiltIn(int64_t display_id) { - return CGDisplayIsBuiltin(display_id); -} - -void MonitorFinder::FetchMonitorFromWidget() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - content::RenderFrameHost* rfh = - content::RenderFrameHost::FromID(process_id_, render_frame_id_); - if (!rfh) - return; - - gfx::NativeView native_view = rfh->GetNativeView(); - NSWindow* window = [native_view window]; - NSScreen* screen = [window screen]; - CGDirectDisplayID display_id = - [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] intValue]; - - base::AutoLock lock(mutex_); - request_sent_ = false; - display_id_ = display_id; -} - -} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc deleted file mode 100644 index c77c8f00f807c..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc +++ /dev/null @@ -1,53 +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/renderer_host/pepper/pepper_broker_message_filter.h" - -#include - -#include "content/public/browser/browser_ppapi_host.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_process_host.h" -#include "ipc/ipc_message_macros.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/host/dispatch_host_message.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "url/gurl.h" - -using content::BrowserPpapiHost; -using content::BrowserThread; - -namespace chrome { - -PepperBrokerMessageFilter::PepperBrokerMessageFilter(PP_Instance instance, - BrowserPpapiHost* host) - : document_url_(host->GetDocumentURLForInstance(instance)) { - int unused; - host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused); -} - -PepperBrokerMessageFilter::~PepperBrokerMessageFilter() {} - -scoped_refptr -PepperBrokerMessageFilter::OverrideTaskRunnerForMessage( - const IPC::Message& message) { - return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); -} - -int32_t PepperBrokerMessageFilter::OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) { - PPAPI_BEGIN_MESSAGE_MAP(PepperBrokerMessageFilter, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Broker_IsAllowed, - OnIsAllowed) - PPAPI_END_MESSAGE_MAP() - return PP_ERROR_FAILED; -} - -int32_t PepperBrokerMessageFilter::OnIsAllowed( - ppapi::host::HostMessageContext* context) { - return PP_OK; -} - -} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h deleted file mode 100644 index 44627c6a35563..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.h +++ /dev/null @@ -1,51 +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_RENDERER_HOST_PEPPER_PEPPER_BROKER_MESSAGE_FILTER_H_ -#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_BROKER_MESSAGE_FILTER_H_ - -#include "base/compiler_specific.h" -#include "ppapi/c/pp_instance.h" -#include "ppapi/host/resource_message_filter.h" -#include "url/gurl.h" - -namespace content { -class BrowserPpapiHost; -} - -namespace ppapi { -namespace host { -struct HostMessageContext; -} -} - -namespace chrome { - -// This filter handles messages for the PepperBrokerHost on the UI thread. -class PepperBrokerMessageFilter : public ppapi::host::ResourceMessageFilter { - public: - PepperBrokerMessageFilter(PP_Instance instance, - content::BrowserPpapiHost* host); - - private: - ~PepperBrokerMessageFilter() override; - - // ppapi::host::ResourceMessageFilter overrides. - scoped_refptr OverrideTaskRunnerForMessage( - const IPC::Message& message) override; - int32_t OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) override; - - int32_t OnIsAllowed(ppapi::host::HostMessageContext* context); - - int render_process_id_; - GURL document_url_; - - DISALLOW_COPY_AND_ASSIGN(PepperBrokerMessageFilter); -}; - -} // namespace chrome - -#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_BROKER_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc deleted file mode 100644 index 96fe8dc8e3822..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc +++ /dev/null @@ -1,113 +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/renderer_host/pepper/pepper_flash_browser_host.h" - -#include "base/time/time.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_ppapi_host.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_process_host.h" -#include "ipc/ipc_message_macros.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/c/private/ppb_flash.h" -#include "ppapi/host/dispatch_host_message.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/proxy/resource_message_params.h" -#include "ppapi/shared_impl/time_conversion.h" -#include "url/gurl.h" - -#if defined(OS_WIN) -#include -#elif defined(OS_MACOSX) -#include -#endif - -using content::BrowserPpapiHost; -using content::BrowserThread; - -namespace chrome { - -PepperFlashBrowserHost::PepperFlashBrowserHost(BrowserPpapiHost* host, - PP_Instance instance, - PP_Resource resource) - : ResourceHost(host->GetPpapiHost(), instance, resource), - host_(host), - weak_factory_(this) { - int unused; - host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused); -} - -PepperFlashBrowserHost::~PepperFlashBrowserHost() {} - -int32_t PepperFlashBrowserHost::OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) { - PPAPI_BEGIN_MESSAGE_MAP(PepperFlashBrowserHost, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Flash_UpdateActivity, - OnUpdateActivity) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_GetLocalTimeZoneOffset, - OnGetLocalTimeZoneOffset) - PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( - PpapiHostMsg_Flash_GetLocalDataRestrictions, OnGetLocalDataRestrictions) - PPAPI_END_MESSAGE_MAP() - return PP_ERROR_FAILED; -} - -int32_t PepperFlashBrowserHost::OnUpdateActivity( - ppapi::host::HostMessageContext* host_context) { -#if defined(OS_WIN) - // Reading then writing back the same value to the screensaver timeout system - // setting resets the countdown which prevents the screensaver from turning - // on "for a while". As long as the plugin pings us with this message faster - // than the screensaver timeout, it won't go on. - int value = 0; - if (SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &value, 0)) - SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, value, NULL, 0); -#elif defined(OS_MACOSX) -// UpdateSystemActivity(OverallAct); -#else -// TODO(brettw) implement this for other platforms. -#endif - return PP_OK; -} - -int32_t PepperFlashBrowserHost::OnGetLocalTimeZoneOffset( - ppapi::host::HostMessageContext* host_context, - const base::Time& t) { - // The reason for this processing being in the browser process is that on - // Linux, the localtime calls require filesystem access prohibited by the - // sandbox. - host_context->reply_msg = PpapiPluginMsg_Flash_GetLocalTimeZoneOffsetReply( - ppapi::PPGetLocalTimeZoneOffset(t)); - return PP_OK; -} - -int32_t PepperFlashBrowserHost::OnGetLocalDataRestrictions( - ppapi::host::HostMessageContext* context) { - // Getting the Flash LSO settings requires using the CookieSettings which - // belong to the profile which lives on the UI thread. We lazily initialize - // |cookie_settings_| by grabbing the reference from the UI thread and then - // call |GetLocalDataRestrictions| with it. - GURL document_url = host_->GetDocumentURLForInstance(pp_instance()); - GURL plugin_url = host_->GetPluginURLForInstance(pp_instance()); - GetLocalDataRestrictions(context->MakeReplyMessageContext(), - document_url, - plugin_url); - return PP_OK_COMPLETIONPENDING; -} - -void PepperFlashBrowserHost::GetLocalDataRestrictions( - ppapi::host::ReplyMessageContext reply_context, - const GURL& document_url, - const GURL& plugin_url) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - PP_FlashLSORestrictions restrictions = PP_FLASHLSORESTRICTIONS_NONE; - SendReply(reply_context, - PpapiPluginMsg_Flash_GetLocalDataRestrictionsReply( - static_cast(restrictions))); -} - -} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h deleted file mode 100644 index 40a03a1ff56fb..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h +++ /dev/null @@ -1,59 +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_RENDERER_HOST_PEPPER_PEPPER_FLASH_BROWSER_HOST_H_ -#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_BROWSER_HOST_H_ - -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "ppapi/host/host_message_context.h" -#include "ppapi/host/resource_host.h" - -namespace base { -class Time; -} - -namespace content { -class BrowserPpapiHost; -class ResourceContext; -} - -class GURL; - -namespace chrome { - -class PepperFlashBrowserHost : public ppapi::host::ResourceHost { - public: - PepperFlashBrowserHost(content::BrowserPpapiHost* host, - PP_Instance instance, - PP_Resource resource); - ~PepperFlashBrowserHost() override; - - // ppapi::host::ResourceHost override. - int32_t OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) override; - - private: - int32_t OnUpdateActivity(ppapi::host::HostMessageContext* host_context); - int32_t OnGetLocalTimeZoneOffset( - ppapi::host::HostMessageContext* host_context, - const base::Time& t); - int32_t OnGetLocalDataRestrictions(ppapi::host::HostMessageContext* context); - - void GetLocalDataRestrictions(ppapi::host::ReplyMessageContext reply_context, - const GURL& document_url, - const GURL& plugin_url); - - content::BrowserPpapiHost* host_; - int render_process_id_; - // For fetching the Flash LSO settings. - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(PepperFlashBrowserHost); -}; - -} // namespace chrome - -#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_BROWSER_HOST_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc deleted file mode 100644 index 4e66d772ec383..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc +++ /dev/null @@ -1,379 +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/renderer_host/pepper/pepper_flash_clipboard_message_filter.h" - -#include - -#include "base/pickle.h" -#include "base/strings/utf_string_conversions.h" -#include "content/public/browser/browser_thread.h" -#include "ipc/ipc_message.h" -#include "ipc/ipc_message_macros.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/c/private/ppb_flash_clipboard.h" -#include "ppapi/host/dispatch_host_message.h" -#include "ppapi/host/host_message_context.h" -#include "ppapi/host/ppapi_host.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/proxy/resource_message_params.h" -#include "ui/base/clipboard/scoped_clipboard_writer.h" - -using content::BrowserThread; - -namespace chrome { - -namespace { - -const size_t kMaxClipboardWriteSize = 1000000; - -ui::ClipboardType ConvertClipboardType(uint32_t type) { - switch (type) { - case PP_FLASH_CLIPBOARD_TYPE_STANDARD: - return ui::CLIPBOARD_TYPE_COPY_PASTE; - case PP_FLASH_CLIPBOARD_TYPE_SELECTION: - return ui::CLIPBOARD_TYPE_SELECTION; - } - NOTREACHED(); - return ui::CLIPBOARD_TYPE_COPY_PASTE; -} - -// Functions to pack/unpack custom data from a pickle. See the header file for -// more detail on custom formats in Pepper. -// TODO(raymes): Currently pepper custom formats are stored in their own -// native format type. However we should be able to store them in the same way -// as "Web Custom" formats are. This would allow clipboard data to be shared -// between pepper applications and web applications. However currently web apps -// assume all data that is placed on the clipboard is UTF16 and pepper allows -// arbitrary data so this change would require some reworking of the chrome -// clipboard interface for custom data. -bool JumpToFormatInPickle(const base::string16& format, - base::PickleIterator* iter) { - uint32_t size = 0; - if (!iter->ReadUInt32(&size)) - return false; - for (uint32_t i = 0; i < size; ++i) { - base::string16 stored_format; - if (!iter->ReadString16(&stored_format)) - return false; - if (stored_format == format) - return true; - int skip_length; - if (!iter->ReadLength(&skip_length)) - return false; - if (!iter->SkipBytes(skip_length)) - return false; - } - return false; -} - -bool IsFormatAvailableInPickle(const base::string16& format, - const base::Pickle& pickle) { - base::PickleIterator iter(pickle); - return JumpToFormatInPickle(format, &iter); -} - -std::string ReadDataFromPickle(const base::string16& format, - const base::Pickle& pickle) { - std::string result; - base::PickleIterator iter(pickle); - if (!JumpToFormatInPickle(format, &iter) || !iter.ReadString(&result)) - return std::string(); - return result; -} - -bool WriteDataToPickle(const std::map& data, - base::Pickle* pickle) { - pickle->WriteUInt32(data.size()); - for (std::map::const_iterator it = data.begin(); - it != data.end(); - ++it) { - if (!pickle->WriteString16(it->first)) - return false; - if (!pickle->WriteString(it->second)) - return false; - } - return true; -} - -} // namespace - -PepperFlashClipboardMessageFilter::PepperFlashClipboardMessageFilter() {} - -PepperFlashClipboardMessageFilter::~PepperFlashClipboardMessageFilter() {} - -scoped_refptr -PepperFlashClipboardMessageFilter::OverrideTaskRunnerForMessage( - const IPC::Message& msg) { - // Clipboard writes should always occur on the UI thread due to the - // restrictions of various platform APIs. In general, the clipboard is not - // thread-safe, so all clipboard calls should be serviced from the UI thread. - if (msg.type() == PpapiHostMsg_FlashClipboard_WriteData::ID) - return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); - -// Windows needs clipboard reads to be serviced from the IO thread because -// these are sync IPCs which can result in deadlocks with plugins if serviced -// from the UI thread. Note that Windows clipboard calls ARE thread-safe so it -// is ok for reads and writes to be serviced from different threads. -#if !defined(OS_WIN) - return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); -#else - return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); -#endif -} - -int32_t PepperFlashClipboardMessageFilter::OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) { - PPAPI_BEGIN_MESSAGE_MAP(PepperFlashClipboardMessageFilter, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL( - PpapiHostMsg_FlashClipboard_RegisterCustomFormat, - OnMsgRegisterCustomFormat) - PPAPI_DISPATCH_HOST_RESOURCE_CALL( - PpapiHostMsg_FlashClipboard_IsFormatAvailable, OnMsgIsFormatAvailable) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_ReadData, - OnMsgReadData) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_WriteData, - OnMsgWriteData) - PPAPI_DISPATCH_HOST_RESOURCE_CALL( - PpapiHostMsg_FlashClipboard_GetSequenceNumber, OnMsgGetSequenceNumber) - PPAPI_END_MESSAGE_MAP() - return PP_ERROR_FAILED; -} - -int32_t PepperFlashClipboardMessageFilter::OnMsgRegisterCustomFormat( - ppapi::host::HostMessageContext* host_context, - const std::string& format_name) { - uint32_t format = custom_formats_.RegisterFormat(format_name); - if (format == PP_FLASH_CLIPBOARD_FORMAT_INVALID) - return PP_ERROR_FAILED; - host_context->reply_msg = - PpapiPluginMsg_FlashClipboard_RegisterCustomFormatReply(format); - return PP_OK; -} - -int32_t PepperFlashClipboardMessageFilter::OnMsgIsFormatAvailable( - ppapi::host::HostMessageContext* host_context, - uint32_t clipboard_type, - uint32_t format) { - if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) { - NOTIMPLEMENTED(); - return PP_ERROR_FAILED; - } - - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - ui::ClipboardType type = ConvertClipboardType(clipboard_type); - bool available = false; - switch (format) { - case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: { - bool plain = clipboard->IsFormatAvailable( - ui::Clipboard::GetPlainTextFormatType(), type); - bool plainw = clipboard->IsFormatAvailable( - ui::Clipboard::GetPlainTextWFormatType(), type); - available = plain || plainw; - break; - } - case PP_FLASH_CLIPBOARD_FORMAT_HTML: - available = clipboard->IsFormatAvailable( - ui::Clipboard::GetHtmlFormatType(), type); - break; - case PP_FLASH_CLIPBOARD_FORMAT_RTF: - available = - clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(), type); - break; - case PP_FLASH_CLIPBOARD_FORMAT_INVALID: - break; - default: - if (custom_formats_.IsFormatRegistered(format)) { - std::string format_name = custom_formats_.GetFormatName(format); - std::string clipboard_data; - clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(), - &clipboard_data); - base::Pickle pickle(clipboard_data.data(), clipboard_data.size()); - available = - IsFormatAvailableInPickle(base::UTF8ToUTF16(format_name), pickle); - } - break; - } - - return available ? PP_OK : PP_ERROR_FAILED; -} - -int32_t PepperFlashClipboardMessageFilter::OnMsgReadData( - ppapi::host::HostMessageContext* host_context, - uint32_t clipboard_type, - uint32_t format) { - if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) { - NOTIMPLEMENTED(); - return PP_ERROR_FAILED; - } - - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - ui::ClipboardType type = ConvertClipboardType(clipboard_type); - std::string clipboard_string; - int32_t result = PP_ERROR_FAILED; - switch (format) { - case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: { - if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(), - type)) { - base::string16 text; - clipboard->ReadText(type, &text); - if (!text.empty()) { - result = PP_OK; - clipboard_string = base::UTF16ToUTF8(text); - break; - } - } - // If the PlainTextW format isn't available or is empty, take the - // ASCII text format. - if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(), - type)) { - result = PP_OK; - clipboard->ReadAsciiText(type, &clipboard_string); - } - break; - } - case PP_FLASH_CLIPBOARD_FORMAT_HTML: { - if (!clipboard->IsFormatAvailable(ui::Clipboard::GetHtmlFormatType(), - type)) { - break; - } - - base::string16 html; - std::string url; - uint32_t fragment_start; - uint32_t fragment_end; - clipboard->ReadHTML(type, &html, &url, &fragment_start, &fragment_end); - result = PP_OK; - clipboard_string = base::UTF16ToUTF8( - html.substr(fragment_start, fragment_end - fragment_start)); - break; - } - case PP_FLASH_CLIPBOARD_FORMAT_RTF: { - if (!clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(), - type)) { - break; - } - result = PP_OK; - clipboard->ReadRTF(type, &clipboard_string); - break; - } - case PP_FLASH_CLIPBOARD_FORMAT_INVALID: - break; - default: { - if (custom_formats_.IsFormatRegistered(format)) { - base::string16 format_name = - base::UTF8ToUTF16(custom_formats_.GetFormatName(format)); - std::string clipboard_data; - clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(), - &clipboard_data); - base::Pickle pickle(clipboard_data.data(), clipboard_data.size()); - if (IsFormatAvailableInPickle(format_name, pickle)) { - result = PP_OK; - clipboard_string = ReadDataFromPickle(format_name, pickle); - } - } - break; - } - } - - if (result == PP_OK) { - host_context->reply_msg = - PpapiPluginMsg_FlashClipboard_ReadDataReply(clipboard_string); - } - return result; -} - -int32_t PepperFlashClipboardMessageFilter::OnMsgWriteData( - ppapi::host::HostMessageContext* host_context, - uint32_t clipboard_type, - const std::vector& formats, - const std::vector& data) { - if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) { - NOTIMPLEMENTED(); - return PP_ERROR_FAILED; - } - if (formats.size() != data.size()) - return PP_ERROR_FAILED; - - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - ui::ClipboardType type = ConvertClipboardType(clipboard_type); - // If no formats are passed in clear the clipboard. - if (formats.size() == 0) { - clipboard->Clear(type); - return PP_OK; - } - - ui::ScopedClipboardWriter scw(type); - std::map custom_data_map; - int32_t res = PP_OK; - for (uint32_t i = 0; i < formats.size(); ++i) { - if (data[i].length() > kMaxClipboardWriteSize) { - res = PP_ERROR_NOSPACE; - break; - } - - switch (formats[i]) { - case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: - scw.WriteText(base::UTF8ToUTF16(data[i])); - break; - case PP_FLASH_CLIPBOARD_FORMAT_HTML: - scw.WriteHTML(base::UTF8ToUTF16(data[i]), std::string()); - break; - case PP_FLASH_CLIPBOARD_FORMAT_RTF: - scw.WriteRTF(data[i]); - break; - case PP_FLASH_CLIPBOARD_FORMAT_INVALID: - res = PP_ERROR_BADARGUMENT; - break; - default: - if (custom_formats_.IsFormatRegistered(formats[i])) { - std::string format_name = custom_formats_.GetFormatName(formats[i]); - custom_data_map[base::UTF8ToUTF16(format_name)] = data[i]; - } else { - // Invalid format. - res = PP_ERROR_BADARGUMENT; - break; - } - } - - if (res != PP_OK) - break; - } - - if (custom_data_map.size() > 0) { - base::Pickle pickle; - if (WriteDataToPickle(custom_data_map, &pickle)) { - scw.WritePickledData(pickle, - ui::Clipboard::GetPepperCustomDataFormatType()); - } else { - res = PP_ERROR_BADARGUMENT; - } - } - - if (res != PP_OK) { - // Need to clear the objects so nothing is written. - scw.Reset(); - } - - return res; -} - -int32_t PepperFlashClipboardMessageFilter::OnMsgGetSequenceNumber( - ppapi::host::HostMessageContext* host_context, - uint32_t clipboard_type) { - if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) { - NOTIMPLEMENTED(); - return PP_ERROR_FAILED; - } - - ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - ui::ClipboardType type = ConvertClipboardType(clipboard_type); - int64_t sequence_number = clipboard->GetSequenceNumber(type); - host_context->reply_msg = - PpapiPluginMsg_FlashClipboard_GetSequenceNumberReply(sequence_number); - return PP_OK; -} - -} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h deleted file mode 100644 index 4c146dd5daa0b..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h +++ /dev/null @@ -1,76 +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_RENDERER_HOST_PEPPER_PEPPER_FLASH_CLIPBOARD_MESSAGE_FILTER_H_ -#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_CLIPBOARD_MESSAGE_FILTER_H_ - -#include -#include - -#include "ppapi/host/resource_message_filter.h" -#include "ppapi/shared_impl/flash_clipboard_format_registry.h" - -namespace ppapi { -namespace host { -struct HostMessageContext; -} -} - -namespace ui { -class ScopedClipboardWriter; -} - -namespace chrome { - -// Resource message filter for accessing the clipboard in Pepper. Pepper -// supports reading/writing custom formats from the clipboard. Currently, all -// custom formats that are read/written from the clipboard through pepper are -// stored in a single real clipboard format (in the same way the "web custom" -// clipboard formats are). This is done so that we don't have to have use real -// clipboard types for each custom clipboard format which may be a limited -// resource on a particular platform. -class PepperFlashClipboardMessageFilter - : public ppapi::host::ResourceMessageFilter { - public: - PepperFlashClipboardMessageFilter(); - - protected: - // ppapi::host::ResourceMessageFilter overrides. - scoped_refptr OverrideTaskRunnerForMessage( - const IPC::Message& msg) override; - int32_t OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) override; - - private: - ~PepperFlashClipboardMessageFilter() override; - - int32_t OnMsgRegisterCustomFormat( - ppapi::host::HostMessageContext* host_context, - const std::string& format_name); - int32_t OnMsgIsFormatAvailable(ppapi::host::HostMessageContext* host_context, - uint32_t clipboard_type, - uint32_t format); - int32_t OnMsgReadData(ppapi::host::HostMessageContext* host_context, - uint32_t clipoard_type, - uint32_t format); - int32_t OnMsgWriteData(ppapi::host::HostMessageContext* host_context, - uint32_t clipboard_type, - const std::vector& formats, - const std::vector& data); - int32_t OnMsgGetSequenceNumber(ppapi::host::HostMessageContext* host_context, - uint32_t clipboard_type); - - int32_t WriteClipboardDataItem(uint32_t format, - const std::string& data, - ui::ScopedClipboardWriter* scw); - - ppapi::FlashClipboardFormatRegistry custom_formats_; - - DISALLOW_COPY_AND_ASSIGN(PepperFlashClipboardMessageFilter); -}; - -} // namespace chrome - -#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_CLIPBOARD_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc deleted file mode 100644 index 34a7ff881f484..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.cc +++ /dev/null @@ -1,217 +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/renderer_host/pepper/pepper_flash_drm_host.h" - -#include - -#if defined(OS_WIN) -#include -#endif - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/strings/string_number_conversions.h" -#include "build/build_config.h" -#include "content/public/browser/browser_ppapi_host.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/child_process_security_policy.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/common/pepper_plugin_info.h" -#include "net/base/network_interfaces.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/host/dispatch_host_message.h" -#include "ppapi/host/host_message_context.h" -#include "ppapi/host/ppapi_host.h" -#include "ppapi/proxy/ppapi_messages.h" - -#if defined(USE_AURA) -#include "ui/aura/window.h" -#include "ui/aura/window_tree_host.h" -#endif - -#if defined(OS_MACOSX) -#include "chrome/browser/renderer_host/pepper/monitor_finder_mac.h" -#endif - -using content::BrowserPpapiHost; - -namespace chrome { - -namespace { - -const char kVoucherFilename[] = "plugin.vch"; - -#if defined(OS_WIN) -bool GetSystemVolumeSerialNumber(std::string* number) { - // Find the system root path (e.g: C:\). - wchar_t system_path[MAX_PATH + 1]; - if (!GetSystemDirectoryW(system_path, MAX_PATH)) - return false; - - wchar_t* first_slash = wcspbrk(system_path, L"\\/"); - if (first_slash != NULL) - *(first_slash + 1) = 0; - - DWORD number_local = 0; - if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL, - NULL, 0)) - return false; - - *number = base::IntToString(std::abs(static_cast(number_local))); - return true; -} -#endif - -} - -#if defined(OS_WIN) -// Helper class to get the UI thread which monitor is showing the -// window associated with the instance's render view. Since we get -// called by the IO thread and we cannot block, the first answer is -// of GetMonitor() may be NULL, but eventually it will contain the -// right monitor. -class MonitorFinder : public base::RefCountedThreadSafe { - public: - MonitorFinder(int process_id, int render_frame_id) - : process_id_(process_id), - render_frame_id_(render_frame_id), - monitor_(NULL), - request_sent_(0) {} - - int64_t GetMonitor() { - // We use |request_sent_| as an atomic boolean so that we - // never have more than one task posted at a given time. We - // do this because we don't know how often our client is going - // to call and we can't cache the |monitor_| value. - if (InterlockedCompareExchange(&request_sent_, 1, 0) == 0) { - content::BrowserThread::PostTask( - content::BrowserThread::UI, - FROM_HERE, - base::Bind(&MonitorFinder::FetchMonitorFromWidget, this)); - } - return reinterpret_cast(monitor_); - } - - private: - friend class base::RefCountedThreadSafe; - ~MonitorFinder() {} - - void FetchMonitorFromWidget() { - InterlockedExchange(&request_sent_, 0); - content::RenderFrameHost* rfh = - content::RenderFrameHost::FromID(process_id_, render_frame_id_); - if (!rfh) - return; - gfx::NativeView native_view = rfh->GetNativeView(); -#if defined(USE_AURA) - aura::WindowTreeHost* host = native_view->GetHost(); - if (!host) - return; - HWND window = host->GetAcceleratedWidget(); -#else - HWND window = native_view; -#endif - HMONITOR monitor = ::MonitorFromWindow(window, MONITOR_DEFAULTTONULL); - InterlockedExchangePointer(reinterpret_cast(&monitor_), - monitor); - } - - const int process_id_; - const int render_frame_id_; - volatile HMONITOR monitor_; - volatile long request_sent_; -}; -#elif !defined(OS_MACOSX) -// TODO(cpu): Support Linux someday. -class MonitorFinder : public base::RefCountedThreadSafe { - public: - MonitorFinder(int, int) {} - int64_t GetMonitor() { return 0; } - - private: - friend class base::RefCountedThreadSafe; - ~MonitorFinder() {} -}; -#endif - -PepperFlashDRMHost::PepperFlashDRMHost(BrowserPpapiHost* host, - PP_Instance instance, - PP_Resource resource) - : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource), - weak_factory_(this) { - // Grant permissions to read the flash voucher file. - int render_process_id; - int render_frame_id; - bool success = host->GetRenderFrameIDsForInstance( - instance, &render_process_id, &render_frame_id); - base::FilePath plugin_dir = host->GetPluginPath().DirName(); - DCHECK(!plugin_dir.empty() && success); - base::FilePath voucher_file = plugin_dir.AppendASCII(kVoucherFilename); - content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile( - render_process_id, voucher_file); - - monitor_finder_ = new MonitorFinder(render_process_id, render_frame_id); - monitor_finder_->GetMonitor(); -} - -PepperFlashDRMHost::~PepperFlashDRMHost() {} - -int32_t PepperFlashDRMHost::OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) { - PPAPI_BEGIN_MESSAGE_MAP(PepperFlashDRMHost, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetDeviceID, - OnHostMsgGetDeviceID) - PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_GetHmonitor, - OnHostMsgGetHmonitor) - PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_FlashDRM_MonitorIsExternal, - OnHostMsgMonitorIsExternal) - PPAPI_END_MESSAGE_MAP() - return PP_ERROR_FAILED; -} - -int32_t PepperFlashDRMHost::OnHostMsgGetDeviceID( - ppapi::host::HostMessageContext* context) { - static std::string id; -#if defined(OS_WIN) - if (id.empty() && !GetSystemVolumeSerialNumber(&id)) - id = net::GetHostName(); -#else - if (id.empty()) - id = net::GetHostName(); -#endif - context->reply_msg = PpapiPluginMsg_FlashDRM_GetDeviceIDReply(id); - return PP_OK; -} - -int32_t PepperFlashDRMHost::OnHostMsgGetHmonitor( - ppapi::host::HostMessageContext* context) { - int64_t monitor_id = monitor_finder_->GetMonitor(); - if (monitor_id) { - context->reply_msg = PpapiPluginMsg_FlashDRM_GetHmonitorReply(monitor_id); - return PP_OK; - } - return PP_ERROR_FAILED; -} - -int32_t PepperFlashDRMHost::OnHostMsgMonitorIsExternal( - ppapi::host::HostMessageContext* context) { - int64_t monitor_id = monitor_finder_->GetMonitor(); - if (!monitor_id) - return PP_ERROR_FAILED; - - PP_Bool is_external = PP_FALSE; -#if defined(OS_MACOSX) - if (!MonitorFinder::IsMonitorBuiltIn(monitor_id)) - is_external = PP_TRUE; -#endif - context->reply_msg = - PpapiPluginMsg_FlashDRM_MonitorIsExternalReply(is_external); - return PP_OK; -} - -} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h deleted file mode 100644 index 91bba9631e68f..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_flash_drm_host.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 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_RENDERER_HOST_PEPPER_PEPPER_FLASH_DRM_HOST_H_ -#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_DRM_HOST_H_ - -#include - -#include - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "ppapi/host/host_message_context.h" -#include "ppapi/host/resource_host.h" - -namespace content { -class BrowserPpapiHost; -} - -namespace IPC { -class Message; -} - -namespace chrome { -class MonitorFinder; - -class PepperFlashDRMHost : public ppapi::host::ResourceHost { - public: - PepperFlashDRMHost(content::BrowserPpapiHost* host, - PP_Instance instance, - PP_Resource resource); - ~PepperFlashDRMHost() override; - - // ResourceHost override. - int32_t OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) override; - - private: - // IPC message handler. - int32_t OnHostMsgGetDeviceID(ppapi::host::HostMessageContext* context); - int32_t OnHostMsgGetHmonitor(ppapi::host::HostMessageContext* context); - int32_t OnHostMsgMonitorIsExternal(ppapi::host::HostMessageContext* context); - - scoped_refptr monitor_finder_; - - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(PepperFlashDRMHost); -}; - -} // namespace chrome - -#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_DRM_HOST_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc b/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc deleted file mode 100644 index 10c07906af9be..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc +++ /dev/null @@ -1,110 +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. - -#include "chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h" - -#include "content/public/browser/browser_ppapi_host.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/child_process_security_policy.h" -#include "content/public/browser/render_view_host.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/host/dispatch_host_message.h" -#include "ppapi/host/host_message_context.h" -#include "ppapi/host/ppapi_host.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/shared_impl/file_system_util.h" -#include "storage/browser/fileapi/isolated_context.h" - -namespace chrome { - -// static -PepperIsolatedFileSystemMessageFilter* -PepperIsolatedFileSystemMessageFilter::Create(PP_Instance instance, - content::BrowserPpapiHost* host) { - int render_process_id; - int unused_render_frame_id; - if (!host->GetRenderFrameIDsForInstance( - instance, &render_process_id, &unused_render_frame_id)) { - return NULL; - } - return new PepperIsolatedFileSystemMessageFilter( - render_process_id, - host->GetProfileDataDirectory(), - host->GetDocumentURLForInstance(instance), - host->GetPpapiHost()); -} - -PepperIsolatedFileSystemMessageFilter::PepperIsolatedFileSystemMessageFilter( - int render_process_id, - const base::FilePath& profile_directory, - const GURL& document_url, - ppapi::host::PpapiHost* ppapi_host) - : render_process_id_(render_process_id), - profile_directory_(profile_directory), - document_url_(document_url), - ppapi_host_(ppapi_host) { -} - -PepperIsolatedFileSystemMessageFilter:: - ~PepperIsolatedFileSystemMessageFilter() {} - -scoped_refptr -PepperIsolatedFileSystemMessageFilter::OverrideTaskRunnerForMessage( - const IPC::Message& msg) { - // In order to reach ExtensionSystem, we need to get ProfileManager first. - // ProfileManager lives in UI thread, so we need to do this in UI thread. - return content::BrowserThread::GetMessageLoopProxyForThread( - content::BrowserThread::UI); -} - -int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) { - PPAPI_BEGIN_MESSAGE_MAP(PepperIsolatedFileSystemMessageFilter, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL( - PpapiHostMsg_IsolatedFileSystem_BrowserOpen, - OnOpenFileSystem) - PPAPI_END_MESSAGE_MAP() - return PP_ERROR_FAILED; -} - -int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem( - ppapi::host::HostMessageContext* context, - PP_IsolatedFileSystemType_Private type) { - switch (type) { - case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_INVALID: - case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_CRX: - break; - case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE: - return OpenPluginPrivateFileSystem(context); - } - NOTREACHED(); - context->reply_msg = - PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(std::string()); - return PP_ERROR_FAILED; -} - -int32_t PepperIsolatedFileSystemMessageFilter::OpenPluginPrivateFileSystem( - ppapi::host::HostMessageContext* context) { - DCHECK(ppapi_host_); - // Only plugins with private permission can open the filesystem. - if (!ppapi_host_->permissions().HasPermission(ppapi::PERMISSION_PRIVATE)) - return PP_ERROR_NOACCESS; - - const std::string& root_name = ppapi::IsolatedFileSystemTypeToRootName( - PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE); - const std::string& fsid = - storage::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath( - storage::kFileSystemTypePluginPrivate, root_name, base::FilePath()); - - // Grant full access of isolated filesystem to renderer process. - content::ChildProcessSecurityPolicy* policy = - content::ChildProcessSecurityPolicy::GetInstance(); - policy->GrantCreateReadWriteFileSystem(render_process_id_, fsid); - - context->reply_msg = PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(fsid); - return PP_OK; -} - -} // namespace chrome diff --git a/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h b/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h deleted file mode 100644 index 6a24feadd150e..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h +++ /dev/null @@ -1,76 +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_RENDERER_HOST_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ -#define CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ - -#include -#include - -#include "base/files/file_path.h" -#include "ppapi/c/pp_instance.h" -#include "ppapi/c/pp_resource.h" -#include "ppapi/c/private/ppb_isolated_file_system_private.h" -#include "ppapi/host/resource_host.h" -#include "ppapi/host/resource_message_filter.h" -#include "url/gurl.h" - -class Profile; - -namespace content { -class BrowserPpapiHost; -} - -namespace ppapi { -namespace host { -struct HostMessageContext; -} // namespace host -} // namespace ppapi - -namespace chrome { - -class PepperIsolatedFileSystemMessageFilter - : public ppapi::host::ResourceMessageFilter { - public: - static PepperIsolatedFileSystemMessageFilter* Create( - PP_Instance instance, - content::BrowserPpapiHost* host); - - // ppapi::host::ResourceMessageFilter implementation. - scoped_refptr OverrideTaskRunnerForMessage( - const IPC::Message& msg) override; - int32_t OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) override; - - private: - PepperIsolatedFileSystemMessageFilter(int render_process_id, - const base::FilePath& profile_directory, - const GURL& document_url, - ppapi::host::PpapiHost* ppapi_host_); - - ~PepperIsolatedFileSystemMessageFilter() override; - - // Returns filesystem id of isolated filesystem if valid, or empty string - // otherwise. This must run on the UI thread because ProfileManager only - // allows access on that thread. - - int32_t OnOpenFileSystem(ppapi::host::HostMessageContext* context, - PP_IsolatedFileSystemType_Private type); - int32_t OpenPluginPrivateFileSystem(ppapi::host::HostMessageContext* context); - - const int render_process_id_; - // Keep a copy from original thread. - const base::FilePath profile_directory_; - const GURL document_url_; - - // Not owned by this object. - ppapi::host::PpapiHost* ppapi_host_; - - DISALLOW_COPY_AND_ASSIGN(PepperIsolatedFileSystemMessageFilter); -}; - -} // namespace chrome - -#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_PEPPER_ISOLATED_FILE_SYSTEM_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.cc b/chromium_src/chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.cc deleted file mode 100644 index c926b9e94aa7f..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 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. - -#include "chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.h" - -#include "base/bind.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/common/webplugininfo.h" -#include "content/public/browser/plugin_service.h" - -using content::PluginService; -using content::WebPluginInfo; -using content::BrowserThread; - -WidevineCdmMessageFilter::WidevineCdmMessageFilter( - int render_process_id, - content::BrowserContext* browser_context) - : BrowserMessageFilter(ChromeMsgStart), - render_process_id_(render_process_id), - browser_context_(browser_context) { -} - -bool WidevineCdmMessageFilter::OnMessageReceived(const IPC::Message& message) { - IPC_BEGIN_MESSAGE_MAP(WidevineCdmMessageFilter, message) -#if defined(ENABLE_PEPPER_CDMS) - IPC_MESSAGE_HANDLER( - ChromeViewHostMsg_IsInternalPluginAvailableForMimeType, - OnIsInternalPluginAvailableForMimeType) -#endif - IPC_MESSAGE_UNHANDLED(return false) - IPC_END_MESSAGE_MAP() - return true; -} - -#if defined(ENABLE_PEPPER_CDMS) -void WidevineCdmMessageFilter::OnIsInternalPluginAvailableForMimeType( - const std::string& mime_type, - bool* is_available, - std::vector* additional_param_names, - std::vector* additional_param_values) { - std::vector plugins; - PluginService::GetInstance()->GetInternalPlugins(&plugins); - - for (size_t i = 0; i < plugins.size(); ++i) { - const WebPluginInfo& plugin = plugins[i]; - const std::vector& mime_types = - plugin.mime_types; - for (size_t j = 0; j < mime_types.size(); ++j) { - - if (mime_types[j].mime_type == mime_type) { - *is_available = true; - *additional_param_names = mime_types[j].additional_param_names; - *additional_param_values = mime_types[j].additional_param_values; - return; - } - } - } - - *is_available = false; -} -#endif // defined(ENABLE_PEPPER_CDMS) - -void WidevineCdmMessageFilter::OnDestruct() const { - BrowserThread::DeleteOnUIThread::Destruct(this); -} - -WidevineCdmMessageFilter::~WidevineCdmMessageFilter() { -} diff --git a/chromium_src/chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.h b/chromium_src/chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.h deleted file mode 100644 index b8f3d562ac78d..0000000000000 --- a/chromium_src/chrome/browser/renderer_host/pepper/widevine_cdm_message_filter.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 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_RENDERER_HOST_PEPPER_WIDEVINE_CDM_MESSAGE_FILTER_H_ -#define CHROME_BROWSER_RENDERER_HOST_PEPPER_WIDEVINE_CDM_MESSAGE_FILTER_H_ - -#include "chrome/common/widevine_cdm_messages.h" -#include "content/public/browser/browser_message_filter.h" - -namespace content { -class BrowserContext; -} - -class WidevineCdmMessageFilter : public content::BrowserMessageFilter { - public: - explicit WidevineCdmMessageFilter(int render_process_id, - content::BrowserContext* browser_context); - bool OnMessageReceived(const IPC::Message& message) override; - void OnDestruct() const override; - - private: - friend class content::BrowserThread; - friend class base::DeleteHelper; - - virtual ~WidevineCdmMessageFilter(); - - #if defined(ENABLE_PEPPER_CDMS) - // Returns whether any internal plugin supporting |mime_type| is registered - // and enabled. Does not determine whether the plugin can actually be - // instantiated (e.g. whether it has all its dependencies). - // When the returned *|is_available| is true, |additional_param_names| and - // |additional_param_values| contain the name-value pairs, if any, specified - // for the *first* non-disabled plugin found that is registered for - // |mime_type|. - void OnIsInternalPluginAvailableForMimeType( - const std::string& mime_type, - bool* is_available, - std::vector* additional_param_names, - std::vector* additional_param_values); -#endif - - int render_process_id_; - content::BrowserContext* browser_context_; - - DISALLOW_COPY_AND_ASSIGN(WidevineCdmMessageFilter); -}; - -#endif // CHROME_BROWSER_RENDERER_HOST_PEPPER_WIDEVINE_CDM_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/browser/speech/tts_controller.h b/chromium_src/chrome/browser/speech/tts_controller.h deleted file mode 100644 index 0587a1b8cb29c..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_controller.h +++ /dev/null @@ -1,343 +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_SPEECH_TTS_CONTROLLER_H_ -#define CHROME_BROWSER_SPEECH_TTS_CONTROLLER_H_ - -#include -#include -#include -#include -#include - -#include "base/memory/singleton.h" -#include "base/memory/weak_ptr.h" -#include "url/gurl.h" - -class Utterance; -class TtsPlatformImpl; - -namespace base { -class Value; -} - -namespace content { -class BrowserContext; -} - -// Events sent back from the TTS engine indicating the progress. -enum TtsEventType { - TTS_EVENT_START, - TTS_EVENT_END, - TTS_EVENT_WORD, - TTS_EVENT_SENTENCE, - TTS_EVENT_MARKER, - TTS_EVENT_INTERRUPTED, - TTS_EVENT_CANCELLED, - TTS_EVENT_ERROR, - TTS_EVENT_PAUSE, - TTS_EVENT_RESUME -}; - -enum TtsGenderType { - TTS_GENDER_NONE, - TTS_GENDER_MALE, - TTS_GENDER_FEMALE -}; - -// Returns true if this event type is one that indicates an utterance -// is finished and can be destroyed. -bool IsFinalTtsEventType(TtsEventType event_type); - -// The continuous parameters that apply to a given utterance. -struct UtteranceContinuousParameters { - UtteranceContinuousParameters(); - - double rate; - double pitch; - double volume; -}; - -// Information about one voice. -struct VoiceData { - VoiceData(); - ~VoiceData(); - - std::string name; - std::string lang; - TtsGenderType gender; - std::string extension_id; - std::set events; - - // If true, the synthesis engine is a remote network resource. - // It may be higher latency and may incur bandwidth costs. - bool remote; - - // If true, this is implemented by this platform's subclass of - // TtsPlatformImpl. If false, this is implemented by an extension. - bool native; - std::string native_voice_identifier; -}; - -// Interface that delegates TTS requests to user-installed extensions. -class TtsEngineDelegate { - public: - virtual ~TtsEngineDelegate() {} - - // Return a list of all available voices registered. - virtual void GetVoices(content::BrowserContext* browser_context, - std::vector* out_voices) = 0; - - // Speak the given utterance by sending an event to the given TTS engine. - virtual void Speak(Utterance* utterance, const VoiceData& voice) = 0; - - // Stop speaking the given utterance by sending an event to the target - // associated with this utterance. - virtual void Stop(Utterance* utterance) = 0; - - // Pause in the middle of speaking this utterance. - virtual void Pause(Utterance* utterance) = 0; - - // Resume speaking this utterance. - virtual void Resume(Utterance* utterance) = 0; - - // Load the built-in component extension for ChromeOS. - virtual bool LoadBuiltInTtsExtension( - content::BrowserContext* browser_context) = 0; -}; - -// Class that wants to receive events on utterances. -class UtteranceEventDelegate { - public: - virtual ~UtteranceEventDelegate() {} - virtual void OnTtsEvent(Utterance* utterance, - TtsEventType event_type, - int char_index, - const std::string& error_message) = 0; -}; - -// Class that wants to be notified when the set of -// voices has changed. -class VoicesChangedDelegate { - public: - virtual ~VoicesChangedDelegate() {} - virtual void OnVoicesChanged() = 0; -}; - -// One speech utterance. -class Utterance { - public: - // Construct an utterance given a profile and a completion task to call - // when the utterance is done speaking. Before speaking this utterance, - // its other parameters like text, rate, pitch, etc. should all be set. - explicit Utterance(content::BrowserContext* browser_context); - ~Utterance(); - - // Sends an event to the delegate. If the event type is TTS_EVENT_END - // or TTS_EVENT_ERROR, deletes the utterance. If |char_index| is -1, - // uses the last good value. - void OnTtsEvent(TtsEventType event_type, - int char_index, - const std::string& error_message); - - // Finish an utterance without sending an event to the delegate. - void Finish(); - - // Getters and setters for the text to speak and other speech options. - void set_text(const std::string& text) { text_ = text; } - const std::string& text() const { return text_; } - - void set_options(const base::Value* options); - const base::Value* options() const { return options_.get(); } - - void set_src_extension_id(const std::string& src_extension_id) { - src_extension_id_ = src_extension_id; - } - const std::string& src_extension_id() { return src_extension_id_; } - - void set_src_id(int src_id) { src_id_ = src_id; } - int src_id() { return src_id_; } - - void set_src_url(const GURL& src_url) { src_url_ = src_url; } - const GURL& src_url() { return src_url_; } - - void set_voice_name(const std::string& voice_name) { - voice_name_ = voice_name; - } - const std::string& voice_name() const { return voice_name_; } - - void set_lang(const std::string& lang) { - lang_ = lang; - } - const std::string& lang() const { return lang_; } - - void set_gender(TtsGenderType gender) { - gender_ = gender; - } - TtsGenderType gender() const { return gender_; } - - void set_continuous_parameters(const UtteranceContinuousParameters& params) { - continuous_parameters_ = params; - } - const UtteranceContinuousParameters& continuous_parameters() { - return continuous_parameters_; - } - - void set_can_enqueue(bool can_enqueue) { can_enqueue_ = can_enqueue; } - bool can_enqueue() const { return can_enqueue_; } - - void set_required_event_types(const std::set& types) { - required_event_types_ = types; - } - const std::set& required_event_types() const { - return required_event_types_; - } - - void set_desired_event_types(const std::set& types) { - desired_event_types_ = types; - } - const std::set& desired_event_types() const { - return desired_event_types_; - } - - const std::string& extension_id() const { return extension_id_; } - void set_extension_id(const std::string& extension_id) { - extension_id_ = extension_id; - } - - UtteranceEventDelegate* event_delegate() const { - return event_delegate_.get(); - } - void set_event_delegate( - base::WeakPtr event_delegate) { - event_delegate_ = event_delegate; - } - - // Getters and setters for internal state. - content::BrowserContext* browser_context() const { return browser_context_; } - int id() const { return id_; } - bool finished() const { return finished_; } - - private: - // The BrowserContext that initiated this utterance. - content::BrowserContext* browser_context_; - - // The extension ID of the extension providing TTS for this utterance, or - // empty if native TTS is being used. - std::string extension_id_; - - // The unique ID of this utterance, used to associate callback functions - // with utterances. - int id_; - - // The id of the next utterance, so we can associate requests with - // responses. - static int next_utterance_id_; - - // The text to speak. - std::string text_; - - // The full options arg passed to tts.speak, which may include fields - // other than the ones we explicitly parse, below. - std::unique_ptr options_; - - // The extension ID of the extension that called speak() and should - // receive events. - std::string src_extension_id_; - - // The source extension's ID of this utterance, so that it can associate - // events with the appropriate callback. - int src_id_; - - // The URL of the page where the source extension called speak. - GURL src_url_; - - // The delegate to be called when an utterance event is fired. - base::WeakPtr event_delegate_; - - // The parsed options. - std::string voice_name_; - std::string lang_; - TtsGenderType gender_; - UtteranceContinuousParameters continuous_parameters_; - bool can_enqueue_; - std::set required_event_types_; - std::set desired_event_types_; - - // The index of the current char being spoken. - int char_index_; - - // True if this utterance received an event indicating it's done. - bool finished_; -}; - -// Singleton class that manages text-to-speech for the TTS and TTS engine -// extension APIs, maintaining a queue of pending utterances and keeping -// track of all state. -class TtsController { - public: - // Get the single instance of this class. - static TtsController* GetInstance(); - - // Returns true if we're currently speaking an utterance. - virtual bool IsSpeaking() = 0; - - // Speak the given utterance. If the utterance's can_enqueue flag is true - // and another utterance is in progress, adds it to the end of the queue. - // Otherwise, interrupts any current utterance and speaks this one - // immediately. - virtual void SpeakOrEnqueue(Utterance* utterance) = 0; - - // Stop all utterances and flush the queue. Implies leaving pause mode - // as well. - virtual void Stop() = 0; - - // Pause the speech queue. Some engines may support pausing in the middle - // of an utterance. - virtual void Pause() = 0; - - // Resume speaking. - virtual void Resume() = 0; - - // Handle events received from the speech engine. Events are forwarded to - // the callback function, and in addition, completion and error events - // trigger finishing the current utterance and starting the next one, if - // any. - virtual void OnTtsEvent(int utterance_id, - TtsEventType event_type, - int char_index, - const std::string& error_message) = 0; - - // Return a list of all available voices, including the native voice, - // if supported, and all voices registered by extensions. - virtual void GetVoices(content::BrowserContext* browser_context, - std::vector* out_voices) = 0; - - // Called by the extension system or platform implementation when the - // list of voices may have changed and should be re-queried. - virtual void VoicesChanged() = 0; - - // Add a delegate that wants to be notified when the set of voices changes. - virtual void AddVoicesChangedDelegate(VoicesChangedDelegate* delegate) = 0; - - // Remove delegate that wants to be notified when the set of voices changes. - virtual void RemoveVoicesChangedDelegate(VoicesChangedDelegate* delegate) = 0; - - // Set the delegate that processes TTS requests with user-installed - // extensions. - virtual void SetTtsEngineDelegate(TtsEngineDelegate* delegate) = 0; - - // Get the delegate that processes TTS requests with user-installed - // extensions. - virtual TtsEngineDelegate* GetTtsEngineDelegate() = 0; - - // For unit testing. - virtual void SetPlatformImpl(TtsPlatformImpl* platform_impl) = 0; - virtual int QueueSize() = 0; - - protected: - virtual ~TtsController() {} -}; - -#endif // CHROME_BROWSER_SPEECH_TTS_CONTROLLER_H_ diff --git a/chromium_src/chrome/browser/speech/tts_controller_impl.cc b/chromium_src/chrome/browser/speech/tts_controller_impl.cc deleted file mode 100644 index 610ce1656759c..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_controller_impl.cc +++ /dev/null @@ -1,463 +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. - -#include "chrome/browser/speech/tts_controller_impl.h" - -#include -#include - -#include "base/values.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/speech/tts_platform.h" - -namespace { -// A value to be used to indicate that there is no char index available. -const int kInvalidCharIndex = -1; - -// Given a language/region code of the form 'fr-FR', returns just the basic -// language portion, e.g. 'fr'. -std::string TrimLanguageCode(std::string lang) { - if (lang.size() >= 5 && lang[2] == '-') - return lang.substr(0, 2); - else - return lang; -} - -} // namespace - -bool IsFinalTtsEventType(TtsEventType event_type) { - return (event_type == TTS_EVENT_END || - event_type == TTS_EVENT_INTERRUPTED || - event_type == TTS_EVENT_CANCELLED || - event_type == TTS_EVENT_ERROR); -} - -// -// UtteranceContinuousParameters -// - - -UtteranceContinuousParameters::UtteranceContinuousParameters() - : rate(-1), - pitch(-1), - volume(-1) {} - - -// -// VoiceData -// - - -VoiceData::VoiceData() - : gender(TTS_GENDER_NONE), - remote(false), - native(false) {} - -VoiceData::~VoiceData() {} - - -// -// Utterance -// - -// static -int Utterance::next_utterance_id_ = 0; - -Utterance::Utterance(content::BrowserContext* browser_context) - : browser_context_(browser_context), - id_(next_utterance_id_++), - src_id_(-1), - gender_(TTS_GENDER_NONE), - can_enqueue_(false), - char_index_(0), - finished_(false) { - options_.reset(new base::DictionaryValue()); -} - -Utterance::~Utterance() { - DCHECK(finished_); -} - -void Utterance::OnTtsEvent(TtsEventType event_type, - int char_index, - const std::string& error_message) { - if (char_index >= 0) - char_index_ = char_index; - if (IsFinalTtsEventType(event_type)) - finished_ = true; - - if (event_delegate_) - event_delegate_->OnTtsEvent(this, event_type, char_index, error_message); - if (finished_) - event_delegate_.reset(); -} - -void Utterance::Finish() { - finished_ = true; -} - -void Utterance::set_options(const base::Value* options) { - options_.reset(options->DeepCopy()); -} - -TtsController* TtsController::GetInstance() { - return TtsControllerImpl::GetInstance(); -} - -// -// TtsControllerImpl -// - -// static -TtsControllerImpl* TtsControllerImpl::GetInstance() { - return base::Singleton::get(); -} - -TtsControllerImpl::TtsControllerImpl() - : current_utterance_(NULL), - paused_(false), - platform_impl_(NULL), - tts_engine_delegate_(NULL) { -} - -TtsControllerImpl::~TtsControllerImpl() { - if (current_utterance_) { - current_utterance_->Finish(); - delete current_utterance_; - } - - // Clear any queued utterances too. - ClearUtteranceQueue(false); // Don't sent events. -} - -void TtsControllerImpl::SpeakOrEnqueue(Utterance* utterance) { - // If we're paused and we get an utterance that can't be queued, - // flush the queue but stay in the paused state. - if (paused_ && !utterance->can_enqueue()) { - Stop(); - paused_ = true; - delete utterance; - return; - } - - if (paused_ || (IsSpeaking() && utterance->can_enqueue())) { - utterance_queue_.push(utterance); - } else { - Stop(); - SpeakNow(utterance); - } -} - -void TtsControllerImpl::SpeakNow(Utterance* utterance) { - // Ensure we have all built-in voices loaded. This is a no-op if already - // loaded. - bool loaded_built_in = - GetPlatformImpl()->LoadBuiltInTtsExtension(utterance->browser_context()); - - // Get all available voices and try to find a matching voice. - std::vector voices; - GetVoices(utterance->browser_context(), &voices); - int index = GetMatchingVoice(utterance, voices); - - VoiceData voice; - if (index != -1) { - // Select the matching voice. - voice = voices[index]; - } else { - // However, if no match was found on a platform without native tts voices, - // attempt to get a voice based only on the current locale without respect - // to any supplied voice names. - std::vector native_voices; - - if (GetPlatformImpl()->PlatformImplAvailable()) - GetPlatformImpl()->GetVoices(&native_voices); - - if (native_voices.empty() && !voices.empty()) { - // TODO(dtseng): Notify extension caller of an error. - utterance->set_voice_name(""); - // TODO(gaochun): Replace the global variable g_browser_process with - // GetContentClient()->browser() to eliminate the dependency of browser - // once TTS implementation was moved to content. - utterance->set_lang(g_browser_process->GetApplicationLocale()); - index = GetMatchingVoice(utterance, voices); - - // If even that fails, just take the first available voice. - if (index == -1) - index = 0; - voice = voices[index]; - } else { - // Otherwise, simply give native voices a chance to handle this utterance. - voice.native = true; - } - } - - GetPlatformImpl()->WillSpeakUtteranceWithVoice(utterance, voice); - - if (!voice.native) { -#if !defined(OS_ANDROID) - DCHECK(!voice.extension_id.empty()); - current_utterance_ = utterance; - utterance->set_extension_id(voice.extension_id); - if (tts_engine_delegate_) - tts_engine_delegate_->Speak(utterance, voice); - bool sends_end_event = - voice.events.find(TTS_EVENT_END) != voice.events.end(); - if (!sends_end_event) { - utterance->Finish(); - delete utterance; - current_utterance_ = NULL; - SpeakNextUtterance(); - } -#endif - } else { - // It's possible for certain platforms to send start events immediately - // during |speak|. - current_utterance_ = utterance; - GetPlatformImpl()->clear_error(); - bool success = GetPlatformImpl()->Speak( - utterance->id(), - utterance->text(), - utterance->lang(), - voice, - utterance->continuous_parameters()); - if (!success) - current_utterance_ = NULL; - - // If the native voice wasn't able to process this speech, see if - // the browser has built-in TTS that isn't loaded yet. - if (!success && loaded_built_in) { - utterance_queue_.push(utterance); - return; - } - - if (!success) { - utterance->OnTtsEvent(TTS_EVENT_ERROR, kInvalidCharIndex, - GetPlatformImpl()->error()); - delete utterance; - return; - } - } -} - -void TtsControllerImpl::Stop() { - paused_ = false; - if (current_utterance_ && !current_utterance_->extension_id().empty()) { -#if !defined(OS_ANDROID) - if (tts_engine_delegate_) - tts_engine_delegate_->Stop(current_utterance_); -#endif - } else { - GetPlatformImpl()->clear_error(); - GetPlatformImpl()->StopSpeaking(); - } - - if (current_utterance_) - current_utterance_->OnTtsEvent(TTS_EVENT_INTERRUPTED, kInvalidCharIndex, - std::string()); - FinishCurrentUtterance(); - ClearUtteranceQueue(true); // Send events. -} - -void TtsControllerImpl::Pause() { - paused_ = true; - if (current_utterance_ && !current_utterance_->extension_id().empty()) { -#if !defined(OS_ANDROID) - if (tts_engine_delegate_) - tts_engine_delegate_->Pause(current_utterance_); -#endif - } else if (current_utterance_) { - GetPlatformImpl()->clear_error(); - GetPlatformImpl()->Pause(); - } -} - -void TtsControllerImpl::Resume() { - paused_ = false; - if (current_utterance_ && !current_utterance_->extension_id().empty()) { -#if !defined(OS_ANDROID) - if (tts_engine_delegate_) - tts_engine_delegate_->Resume(current_utterance_); -#endif - } else if (current_utterance_) { - GetPlatformImpl()->clear_error(); - GetPlatformImpl()->Resume(); - } else { - SpeakNextUtterance(); - } -} - -void TtsControllerImpl::OnTtsEvent(int utterance_id, - TtsEventType event_type, - int char_index, - const std::string& error_message) { - // We may sometimes receive completion callbacks "late", after we've - // already finished the utterance (for example because another utterance - // interrupted or we got a call to Stop). This is normal and we can - // safely just ignore these events. - if (!current_utterance_ || utterance_id != current_utterance_->id()) { - return; - } - current_utterance_->OnTtsEvent(event_type, char_index, error_message); - if (current_utterance_->finished()) { - FinishCurrentUtterance(); - SpeakNextUtterance(); - } -} - -void TtsControllerImpl::GetVoices(content::BrowserContext* browser_context, - std::vector* out_voices) { -#if !defined(OS_ANDROID) - if (browser_context && tts_engine_delegate_) - tts_engine_delegate_->GetVoices(browser_context, out_voices); -#endif - - TtsPlatformImpl* platform_impl = GetPlatformImpl(); - if (platform_impl) { - // Ensure we have all built-in voices loaded. This is a no-op if already - // loaded. - platform_impl->LoadBuiltInTtsExtension(browser_context); - if (platform_impl->PlatformImplAvailable()) - platform_impl->GetVoices(out_voices); - } -} - -bool TtsControllerImpl::IsSpeaking() { - return current_utterance_ != NULL || GetPlatformImpl()->IsSpeaking(); -} - -void TtsControllerImpl::FinishCurrentUtterance() { - if (current_utterance_) { - if (!current_utterance_->finished()) - current_utterance_->OnTtsEvent(TTS_EVENT_INTERRUPTED, kInvalidCharIndex, - std::string()); - delete current_utterance_; - current_utterance_ = NULL; - } -} - -void TtsControllerImpl::SpeakNextUtterance() { - if (paused_) - return; - - // Start speaking the next utterance in the queue. Keep trying in case - // one fails but there are still more in the queue to try. - while (!utterance_queue_.empty() && !current_utterance_) { - Utterance* utterance = utterance_queue_.front(); - utterance_queue_.pop(); - SpeakNow(utterance); - } -} - -void TtsControllerImpl::ClearUtteranceQueue(bool send_events) { - while (!utterance_queue_.empty()) { - Utterance* utterance = utterance_queue_.front(); - utterance_queue_.pop(); - if (send_events) - utterance->OnTtsEvent(TTS_EVENT_CANCELLED, kInvalidCharIndex, - std::string()); - else - utterance->Finish(); - delete utterance; - } -} - -void TtsControllerImpl::SetPlatformImpl( - TtsPlatformImpl* platform_impl) { - platform_impl_ = platform_impl; -} - -int TtsControllerImpl::QueueSize() { - return static_cast(utterance_queue_.size()); -} - -TtsPlatformImpl* TtsControllerImpl::GetPlatformImpl() { - if (!platform_impl_) - platform_impl_ = TtsPlatformImpl::GetInstance(); - return platform_impl_; -} - -int TtsControllerImpl::GetMatchingVoice( - const Utterance* utterance, std::vector& voices) { - // Make two passes: the first time, do strict language matching - // ('fr-FR' does not match 'fr-CA'). The second time, do prefix - // language matching ('fr-FR' matches 'fr' and 'fr-CA') - for (int pass = 0; pass < 2; ++pass) { - for (size_t i = 0; i < voices.size(); ++i) { - const VoiceData& voice = voices[i]; - - if (!utterance->extension_id().empty() && - utterance->extension_id() != voice.extension_id) { - continue; - } - - if (!voice.name.empty() && - !utterance->voice_name().empty() && - voice.name != utterance->voice_name()) { - continue; - } - if (!voice.lang.empty() && !utterance->lang().empty()) { - std::string voice_lang = voice.lang; - std::string utterance_lang = utterance->lang(); - if (pass == 1) { - voice_lang = TrimLanguageCode(voice_lang); - utterance_lang = TrimLanguageCode(utterance_lang); - } - if (voice_lang != utterance_lang) { - continue; - } - } - if (voice.gender != TTS_GENDER_NONE && - utterance->gender() != TTS_GENDER_NONE && - voice.gender != utterance->gender()) { - continue; - } - - if (utterance->required_event_types().size() > 0) { - bool has_all_required_event_types = true; - for (std::set::const_iterator iter = - utterance->required_event_types().begin(); - iter != utterance->required_event_types().end(); - ++iter) { - if (voice.events.find(*iter) == voice.events.end()) { - has_all_required_event_types = false; - break; - } - } - if (!has_all_required_event_types) - continue; - } - - return static_cast(i); - } - } - - return -1; -} - -void TtsControllerImpl::VoicesChanged() { - for (std::set::iterator iter = - voices_changed_delegates_.begin(); - iter != voices_changed_delegates_.end(); ++iter) { - (*iter)->OnVoicesChanged(); - } -} - -void TtsControllerImpl::AddVoicesChangedDelegate( - VoicesChangedDelegate* delegate) { - voices_changed_delegates_.insert(delegate); -} - -void TtsControllerImpl::RemoveVoicesChangedDelegate( - VoicesChangedDelegate* delegate) { - voices_changed_delegates_.erase(delegate); -} - -void TtsControllerImpl::SetTtsEngineDelegate( - TtsEngineDelegate* delegate) { - tts_engine_delegate_ = delegate; -} - -TtsEngineDelegate* TtsControllerImpl::GetTtsEngineDelegate() { - return tts_engine_delegate_; -} diff --git a/chromium_src/chrome/browser/speech/tts_controller_impl.h b/chromium_src/chrome/browser/speech/tts_controller_impl.h deleted file mode 100644 index 749c60ad6dcf8..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_controller_impl.h +++ /dev/null @@ -1,104 +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. - -#ifndef CHROME_BROWSER_SPEECH_TTS_CONTROLLER_IMPL_H_ -#define CHROME_BROWSER_SPEECH_TTS_CONTROLLER_IMPL_H_ - -#include -#include -#include -#include -#include - -#include "base/memory/singleton.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/speech/tts_controller.h" -#include "url/gurl.h" - -namespace content { -class BrowserContext; -} - -// Singleton class that manages text-to-speech for the TTS and TTS engine -// extension APIs, maintaining a queue of pending utterances and keeping -// track of all state. -class TtsControllerImpl : public TtsController { - public: - // Get the single instance of this class. - static TtsControllerImpl* GetInstance(); - - // TtsController methods - virtual bool IsSpeaking() override; - virtual void SpeakOrEnqueue(Utterance* utterance) override; - virtual void Stop() override; - virtual void Pause() override; - virtual void Resume() override; - virtual void OnTtsEvent(int utterance_id, - TtsEventType event_type, - int char_index, - const std::string& error_message) override; - virtual void GetVoices(content::BrowserContext* browser_context, - std::vector* out_voices) override; - virtual void VoicesChanged() override; - virtual void AddVoicesChangedDelegate( - VoicesChangedDelegate* delegate) override; - virtual void RemoveVoicesChangedDelegate( - VoicesChangedDelegate* delegate) override; - virtual void SetTtsEngineDelegate(TtsEngineDelegate* delegate) override; - virtual TtsEngineDelegate* GetTtsEngineDelegate() override; - virtual void SetPlatformImpl(TtsPlatformImpl* platform_impl) override; - virtual int QueueSize() override; - - protected: - TtsControllerImpl(); - virtual ~TtsControllerImpl(); - - private: - // Get the platform TTS implementation (or injected mock). - TtsPlatformImpl* GetPlatformImpl(); - - // Start speaking the given utterance. Will either take ownership of - // |utterance| or delete it if there's an error. Returns true on success. - void SpeakNow(Utterance* utterance); - - // Clear the utterance queue. If send_events is true, will send - // TTS_EVENT_CANCELLED events on each one. - void ClearUtteranceQueue(bool send_events); - - // Finalize and delete the current utterance. - void FinishCurrentUtterance(); - - // Start speaking the next utterance in the queue. - void SpeakNextUtterance(); - - // Given an utterance and a vector of voices, return the - // index of the voice that best matches the utterance. - int GetMatchingVoice(const Utterance* utterance, - std::vector& voices); - - friend struct base::DefaultSingletonTraits; - - // The current utterance being spoken. - Utterance* current_utterance_; - - // Whether the queue is paused or not. - bool paused_; - - // A queue of utterances to speak after the current one finishes. - std::queue utterance_queue_; - - // A set of delegates that want to be notified when the voices change. - std::set voices_changed_delegates_; - - // A pointer to the platform implementation of text-to-speech, for - // dependency injection. - TtsPlatformImpl* platform_impl_; - - // The delegate that processes TTS requests with user-installed extensions. - TtsEngineDelegate* tts_engine_delegate_; - - DISALLOW_COPY_AND_ASSIGN(TtsControllerImpl); -}; - -#endif // CHROME_BROWSER_SPEECH_TTS_CONTROLLER_IMPL_H_ diff --git a/chromium_src/chrome/browser/speech/tts_linux.cc b/chromium_src/chrome/browser/speech/tts_linux.cc deleted file mode 100644 index d0e0e2ee82375..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_linux.cc +++ /dev/null @@ -1,357 +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 - -#include -#include - -#include "base/command_line.h" -#include "base/debug/leak_annotations.h" -#include "base/memory/singleton.h" -#include "base/synchronization/lock.h" -#include "chrome/browser/speech/tts_platform.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/common/content_switches.h" - -#include "library_loaders/libspeechd.h" - -using content::BrowserThread; - -namespace { - -const char kNotSupportedError[] = - "Native speech synthesis not supported on this platform."; - -struct SPDChromeVoice { - std::string name; - std::string module; -}; - -} // namespace - -class TtsPlatformImplLinux : public TtsPlatformImpl { - public: - bool PlatformImplAvailable() override; - bool Speak(int utterance_id, - const std::string& utterance, - const std::string& lang, - const VoiceData& voice, - const UtteranceContinuousParameters& params) override; - bool StopSpeaking() override; - void Pause() override; - void Resume() override; - bool IsSpeaking() override; - void GetVoices(std::vector* out_voices) override; - - void OnSpeechEvent(SPDNotificationType type); - - // Get the single instance of this class. - static TtsPlatformImplLinux* GetInstance(); - - private: - TtsPlatformImplLinux(); - ~TtsPlatformImplLinux() override; - - // Initiate the connection with the speech dispatcher. - void Initialize(); - - // Resets the connection with speech dispatcher. - void Reset(); - - static void NotificationCallback(size_t msg_id, - size_t client_id, - SPDNotificationType type); - - static void IndexMarkCallback(size_t msg_id, - size_t client_id, - SPDNotificationType state, - char* index_mark); - - static SPDNotificationType current_notification_; - - base::Lock initialization_lock_; - LibSpeechdLoader libspeechd_loader_; - SPDConnection* conn_; - - // These apply to the current utterance only. - std::string utterance_; - int utterance_id_; - - // Map a string composed of a voicename and module to the voicename. Used to - // uniquely identify a voice across all available modules. - std::unique_ptr > all_native_voices_; - - friend struct base::DefaultSingletonTraits; - - DISALLOW_COPY_AND_ASSIGN(TtsPlatformImplLinux); -}; - -// static -SPDNotificationType TtsPlatformImplLinux::current_notification_ = - SPD_EVENT_END; - -TtsPlatformImplLinux::TtsPlatformImplLinux() - : utterance_id_(0) { - const base::CommandLine& command_line = - *base::CommandLine::ForCurrentProcess(); - if (!command_line.HasSwitch(switches::kEnableSpeechDispatcher)) - return; - - BrowserThread::PostTask(BrowserThread::FILE, - FROM_HERE, - base::Bind(&TtsPlatformImplLinux::Initialize, - base::Unretained(this))); -} - -void TtsPlatformImplLinux::Initialize() { - base::AutoLock lock(initialization_lock_); - - if (!libspeechd_loader_.Load("libspeechd.so.2")) - return; - - { - // spd_open has memory leaks which are hard to suppress. - // http://crbug.com/317360 - ANNOTATE_SCOPED_MEMORY_LEAK; - conn_ = libspeechd_loader_.spd_open( - "chrome", "extension_api", NULL, SPD_MODE_THREADED); - } - if (!conn_) - return; - - // Register callbacks for all events. - conn_->callback_begin = - conn_->callback_end = - conn_->callback_cancel = - conn_->callback_pause = - conn_->callback_resume = - &NotificationCallback; - - conn_->callback_im = &IndexMarkCallback; - - libspeechd_loader_.spd_set_notification_on(conn_, SPD_BEGIN); - libspeechd_loader_.spd_set_notification_on(conn_, SPD_END); - libspeechd_loader_.spd_set_notification_on(conn_, SPD_CANCEL); - libspeechd_loader_.spd_set_notification_on(conn_, SPD_PAUSE); - libspeechd_loader_.spd_set_notification_on(conn_, SPD_RESUME); -} - -TtsPlatformImplLinux::~TtsPlatformImplLinux() { - base::AutoLock lock(initialization_lock_); - if (conn_) { - libspeechd_loader_.spd_close(conn_); - conn_ = NULL; - } -} - -void TtsPlatformImplLinux::Reset() { - base::AutoLock lock(initialization_lock_); - if (conn_) - libspeechd_loader_.spd_close(conn_); - conn_ = libspeechd_loader_.spd_open( - "chrome", "extension_api", NULL, SPD_MODE_THREADED); -} - -bool TtsPlatformImplLinux::PlatformImplAvailable() { - if (!initialization_lock_.Try()) - return false; - bool result = libspeechd_loader_.loaded() && (conn_ != NULL); - initialization_lock_.Release(); - return result; -} - -bool TtsPlatformImplLinux::Speak( - int utterance_id, - const std::string& utterance, - const std::string& lang, - const VoiceData& voice, - const UtteranceContinuousParameters& params) { - if (!PlatformImplAvailable()) { - error_ = kNotSupportedError; - return false; - } - - // Speech dispatcher's speech params are around 3x at either limit. - float rate = params.rate > 3 ? 3 : params.rate; - rate = params.rate < 0.334 ? 0.334 : rate; - float pitch = params.pitch > 3 ? 3 : params.pitch; - pitch = params.pitch < 0.334 ? 0.334 : pitch; - - std::map::iterator it = - all_native_voices_->find(voice.name); - if (it != all_native_voices_->end()) { - libspeechd_loader_.spd_set_output_module(conn_, it->second.module.c_str()); - libspeechd_loader_.spd_set_synthesis_voice(conn_, it->second.name.c_str()); - } - - // Map our multiplicative range to Speech Dispatcher's linear range. - // .334 = -100. - // 3 = 100. - libspeechd_loader_.spd_set_voice_rate(conn_, 100 * log10(rate) / log10(3)); - libspeechd_loader_.spd_set_voice_pitch(conn_, 100 * log10(pitch) / log10(3)); - - // Support languages other than the default - if (!lang.empty()) - libspeechd_loader_.spd_set_language(conn_, lang.c_str()); - - utterance_ = utterance; - utterance_id_ = utterance_id; - - if (libspeechd_loader_.spd_say(conn_, SPD_TEXT, utterance.c_str()) == -1) { - Reset(); - return false; - } - return true; -} - -bool TtsPlatformImplLinux::StopSpeaking() { - if (!PlatformImplAvailable()) - return false; - if (libspeechd_loader_.spd_stop(conn_) == -1) { - Reset(); - return false; - } - return true; -} - -void TtsPlatformImplLinux::Pause() { - if (!PlatformImplAvailable()) - return; - libspeechd_loader_.spd_pause(conn_); -} - -void TtsPlatformImplLinux::Resume() { - if (!PlatformImplAvailable()) - return; - libspeechd_loader_.spd_resume(conn_); -} - -bool TtsPlatformImplLinux::IsSpeaking() { - return current_notification_ == SPD_EVENT_BEGIN; -} - -void TtsPlatformImplLinux::GetVoices( - std::vector* out_voices) { - if (!all_native_voices_.get()) { - all_native_voices_.reset(new std::map()); - char** modules = libspeechd_loader_.spd_list_modules(conn_); - if (!modules) - return; - for (int i = 0; modules[i]; i++) { - char* module = modules[i]; - libspeechd_loader_.spd_set_output_module(conn_, module); - SPDVoice** native_voices = - libspeechd_loader_.spd_list_synthesis_voices(conn_); - if (!native_voices) { - free(module); - continue; - } - for (int j = 0; native_voices[j]; j++) { - SPDVoice* native_voice = native_voices[j]; - SPDChromeVoice native_data; - native_data.name = native_voice->name; - native_data.module = module; - std::string key; - key.append(native_data.name); - key.append(" "); - key.append(native_data.module); - all_native_voices_->insert( - std::pair(key, native_data)); - free(native_voices[j]); - } - free(modules[i]); - } - } - - for (std::map::iterator it = - all_native_voices_->begin(); - it != all_native_voices_->end(); - it++) { - out_voices->push_back(VoiceData()); - VoiceData& voice = out_voices->back(); - voice.native = true; - voice.name = it->first; - voice.events.insert(TTS_EVENT_START); - voice.events.insert(TTS_EVENT_END); - voice.events.insert(TTS_EVENT_CANCELLED); - voice.events.insert(TTS_EVENT_MARKER); - voice.events.insert(TTS_EVENT_PAUSE); - voice.events.insert(TTS_EVENT_RESUME); - } -} - -void TtsPlatformImplLinux::OnSpeechEvent(SPDNotificationType type) { - TtsController* controller = TtsController::GetInstance(); - switch (type) { - case SPD_EVENT_BEGIN: - controller->OnTtsEvent(utterance_id_, TTS_EVENT_START, 0, std::string()); - break; - case SPD_EVENT_RESUME: - controller->OnTtsEvent(utterance_id_, TTS_EVENT_RESUME, 0, std::string()); - break; - case SPD_EVENT_END: - controller->OnTtsEvent( - utterance_id_, TTS_EVENT_END, utterance_.size(), std::string()); - break; - case SPD_EVENT_PAUSE: - controller->OnTtsEvent( - utterance_id_, TTS_EVENT_PAUSE, utterance_.size(), std::string()); - break; - case SPD_EVENT_CANCEL: - controller->OnTtsEvent( - utterance_id_, TTS_EVENT_CANCELLED, 0, std::string()); - break; - case SPD_EVENT_INDEX_MARK: - controller->OnTtsEvent(utterance_id_, TTS_EVENT_MARKER, 0, std::string()); - break; - } -} - -// static -void TtsPlatformImplLinux::NotificationCallback( - size_t msg_id, size_t client_id, SPDNotificationType type) { - // We run Speech Dispatcher in threaded mode, so these callbacks should always - // be in a separate thread. - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - current_notification_ = type; - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&TtsPlatformImplLinux::OnSpeechEvent, - base::Unretained(TtsPlatformImplLinux::GetInstance()), - type)); - } -} - -// static -void TtsPlatformImplLinux::IndexMarkCallback(size_t msg_id, - size_t client_id, - SPDNotificationType state, - char* index_mark) { - // TODO(dtseng): index_mark appears to specify an index type supplied by a - // client. Need to explore how this is used before hooking it up with existing - // word, sentence events. - // We run Speech Dispatcher in threaded mode, so these callbacks should always - // be in a separate thread. - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - current_notification_ = state; - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&TtsPlatformImplLinux::OnSpeechEvent, - base::Unretained(TtsPlatformImplLinux::GetInstance()), - state)); - } -} - -// static -TtsPlatformImplLinux* TtsPlatformImplLinux::GetInstance() { - return base::Singleton< - TtsPlatformImplLinux, - base::LeakySingletonTraits>::get(); -} - -// static -TtsPlatformImpl* TtsPlatformImpl::GetInstance() { - return TtsPlatformImplLinux::GetInstance(); -} diff --git a/chromium_src/chrome/browser/speech/tts_mac.mm b/chromium_src/chrome/browser/speech/tts_mac.mm deleted file mode 100644 index aafbd46925159..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_mac.mm +++ /dev/null @@ -1,352 +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 - -#include "base/mac/scoped_nsobject.h" -#include "base/memory/singleton.h" -#include "base/strings/sys_string_conversions.h" -#include "base/values.h" -#include "chrome/browser/speech/tts_controller.h" -#include "chrome/browser/speech/tts_platform.h" - -#import - -class TtsPlatformImplMac; - -@interface ChromeTtsDelegate : NSObject { - @private - TtsPlatformImplMac* ttsImplMac_; // weak. -} - -- (id)initWithPlatformImplMac:(TtsPlatformImplMac*)ttsImplMac; - -@end - -// Subclass of NSSpeechSynthesizer that takes an utterance -// string on initialization, retains it and only allows it -// to be spoken once. -// -// We construct a new NSSpeechSynthesizer for each utterance, for -// two reasons: -// 1. To associate delegate callbacks with a particular utterance, -// without assuming anything undocumented about the protocol. -// 2. To work around http://openradar.appspot.com/radar?id=2854403, -// where Nuance voices don't retain the utterance string and -// crash when trying to call willSpeakWord. -@interface SingleUseSpeechSynthesizer : NSSpeechSynthesizer { - @private - base::scoped_nsobject utterance_; - bool didSpeak_; -} - -- (id)initWithUtterance:(NSString*)utterance; -- (bool)startSpeakingRetainedUtterance; -- (bool)startSpeakingString:(NSString*)utterance; - -@end - -class TtsPlatformImplMac : public TtsPlatformImpl { - public: - virtual bool PlatformImplAvailable() override { - return true; - } - - virtual bool Speak( - int utterance_id, - const std::string& utterance, - const std::string& lang, - const VoiceData& voice, - const UtteranceContinuousParameters& params) override; - - virtual bool StopSpeaking() override; - - virtual void Pause() override; - - virtual void Resume() override; - - virtual bool IsSpeaking() override; - - virtual void GetVoices(std::vector* out_voices) override; - - // Called by ChromeTtsDelegate when we get a callback from the - // native speech engine. - void OnSpeechEvent(NSSpeechSynthesizer* sender, - TtsEventType event_type, - int char_index, - const std::string& error_message); - - // Get the single instance of this class. - static TtsPlatformImplMac* GetInstance(); - - private: - TtsPlatformImplMac(); - virtual ~TtsPlatformImplMac(); - - base::scoped_nsobject speech_synthesizer_; - base::scoped_nsobject delegate_; - int utterance_id_; - std::string utterance_; - int last_char_index_; - bool paused_; - - friend struct base::DefaultSingletonTraits; - - DISALLOW_COPY_AND_ASSIGN(TtsPlatformImplMac); -}; - -// static -TtsPlatformImpl* TtsPlatformImpl::GetInstance() { - return TtsPlatformImplMac::GetInstance(); -} - -bool TtsPlatformImplMac::Speak( - int utterance_id, - const std::string& utterance, - const std::string& lang, - const VoiceData& voice, - const UtteranceContinuousParameters& params) { - // TODO: convert SSML to SAPI xml. http://crbug.com/88072 - utterance_ = utterance; - paused_ = false; - - NSString* utterance_nsstring = - [NSString stringWithUTF8String:utterance_.c_str()]; - - // Deliberately construct a new speech synthesizer every time Speak is - // called, otherwise there's no way to know whether calls to the delegate - // apply to the current utterance or a previous utterance. In - // experimentation, the overhead of constructing and destructing a - // NSSpeechSynthesizer is minimal. - speech_synthesizer_.reset( - [[SingleUseSpeechSynthesizer alloc] - initWithUtterance:utterance_nsstring]); - [speech_synthesizer_ setDelegate:delegate_]; - - if (!voice.native_voice_identifier.empty()) { - NSString* native_voice_identifier = - [NSString stringWithUTF8String:voice.native_voice_identifier.c_str()]; - [speech_synthesizer_ setVoice:native_voice_identifier]; - } - - utterance_id_ = utterance_id; - - // TODO: support languages other than the default: crbug.com/88059 - - if (params.rate >= 0.0) { - // The TTS api defines rate via words per minute. Let 200 be the default. - [speech_synthesizer_ - setObject:[NSNumber numberWithInt:params.rate * 200] - forProperty:NSSpeechRateProperty error:nil]; - } - - if (params.pitch >= 0.0) { - // The input is a float from 0.0 to 2.0, with 1.0 being the default. - // Get the default pitch for this voice and modulate it by 50% - 150%. - NSError* errorCode; - NSNumber* defaultPitchObj = - [speech_synthesizer_ objectForProperty:NSSpeechPitchBaseProperty - error:&errorCode]; - int defaultPitch = defaultPitchObj ? [defaultPitchObj intValue] : 48; - int newPitch = static_cast(defaultPitch * (0.5 * params.pitch + 0.5)); - [speech_synthesizer_ - setObject:[NSNumber numberWithInt:newPitch] - forProperty:NSSpeechPitchBaseProperty error:nil]; - } - - if (params.volume >= 0.0) { - [speech_synthesizer_ - setObject: [NSNumber numberWithFloat:params.volume] - forProperty:NSSpeechVolumeProperty error:nil]; - } - - bool success = [speech_synthesizer_ startSpeakingRetainedUtterance]; - if (success) { - TtsController* controller = TtsController::GetInstance(); - controller->OnTtsEvent(utterance_id_, TTS_EVENT_START, 0, ""); - } - return success; -} - -bool TtsPlatformImplMac::StopSpeaking() { - if (speech_synthesizer_.get()) { - [speech_synthesizer_ stopSpeaking]; - speech_synthesizer_.reset(nil); - } - paused_ = false; - return true; -} - -void TtsPlatformImplMac::Pause() { - if (speech_synthesizer_.get() && utterance_id_ && !paused_) { - [speech_synthesizer_ pauseSpeakingAtBoundary:NSSpeechImmediateBoundary]; - paused_ = true; - TtsController::GetInstance()->OnTtsEvent( - utterance_id_, TTS_EVENT_PAUSE, last_char_index_, ""); - } -} - -void TtsPlatformImplMac::Resume() { - if (speech_synthesizer_.get() && utterance_id_ && paused_) { - [speech_synthesizer_ continueSpeaking]; - paused_ = false; - TtsController::GetInstance()->OnTtsEvent( - utterance_id_, TTS_EVENT_RESUME, last_char_index_, ""); - } -} - -bool TtsPlatformImplMac::IsSpeaking() { - if (speech_synthesizer_) - return [speech_synthesizer_ isSpeaking]; - return false; -} - -void TtsPlatformImplMac::GetVoices(std::vector* outVoices) { - NSArray* voices = [NSSpeechSynthesizer availableVoices]; - - // Create a new temporary array of the available voices with - // the default voice first. - NSMutableArray* orderedVoices = - [NSMutableArray arrayWithCapacity:[voices count]]; - NSString* defaultVoice = [NSSpeechSynthesizer defaultVoice]; - if (defaultVoice) { - [orderedVoices addObject:defaultVoice]; - } - for (NSString* voiceIdentifier in voices) { - if (![voiceIdentifier isEqualToString:defaultVoice]) - [orderedVoices addObject:voiceIdentifier]; - } - - for (NSString* voiceIdentifier in orderedVoices) { - outVoices->push_back(VoiceData()); - VoiceData& data = outVoices->back(); - - NSDictionary* attributes = - [NSSpeechSynthesizer attributesForVoice:voiceIdentifier]; - NSString* name = [attributes objectForKey:NSVoiceName]; - NSString* gender = [attributes objectForKey:NSVoiceGender]; - NSString* localeIdentifier = - [attributes objectForKey:NSVoiceLocaleIdentifier]; - - data.native = true; - data.native_voice_identifier = base::SysNSStringToUTF8(voiceIdentifier); - data.name = base::SysNSStringToUTF8(name); - - NSDictionary* localeComponents = - [NSLocale componentsFromLocaleIdentifier:localeIdentifier]; - NSString* language = [localeComponents objectForKey:NSLocaleLanguageCode]; - NSString* country = [localeComponents objectForKey:NSLocaleCountryCode]; - if (language && country) { - data.lang = - [[NSString stringWithFormat:@"%@-%@", language, country] UTF8String]; - } else { - data.lang = base::SysNSStringToUTF8(language); - } - if ([gender isEqualToString:NSVoiceGenderMale]) - data.gender = TTS_GENDER_MALE; - else if ([gender isEqualToString:NSVoiceGenderFemale]) - data.gender = TTS_GENDER_FEMALE; - else - data.gender = TTS_GENDER_NONE; - data.events.insert(TTS_EVENT_START); - data.events.insert(TTS_EVENT_END); - data.events.insert(TTS_EVENT_WORD); - data.events.insert(TTS_EVENT_ERROR); - data.events.insert(TTS_EVENT_CANCELLED); - data.events.insert(TTS_EVENT_INTERRUPTED); - data.events.insert(TTS_EVENT_PAUSE); - data.events.insert(TTS_EVENT_RESUME); - } -} - -void TtsPlatformImplMac::OnSpeechEvent( - NSSpeechSynthesizer* sender, - TtsEventType event_type, - int char_index, - const std::string& error_message) { - // Don't send events from an utterance that's already completed. - // This depends on the fact that we construct a new NSSpeechSynthesizer - // each time we call Speak. - if (sender != speech_synthesizer_.get()) - return; - - if (event_type == TTS_EVENT_END) - char_index = utterance_.size(); - TtsController* controller = TtsController::GetInstance(); -controller->OnTtsEvent( - utterance_id_, event_type, char_index, error_message); - last_char_index_ = char_index; -} - -TtsPlatformImplMac::TtsPlatformImplMac() { - utterance_id_ = -1; - paused_ = false; - - delegate_.reset([[ChromeTtsDelegate alloc] initWithPlatformImplMac:this]); -} - -TtsPlatformImplMac::~TtsPlatformImplMac() { -} - -// static -TtsPlatformImplMac* TtsPlatformImplMac::GetInstance() { - return base::Singleton::get(); -} - -@implementation ChromeTtsDelegate - -- (id)initWithPlatformImplMac:(TtsPlatformImplMac*)ttsImplMac { - if ((self = [super init])) { - ttsImplMac_ = ttsImplMac; - } - return self; -} - -- (void)speechSynthesizer:(NSSpeechSynthesizer*)sender - didFinishSpeaking:(BOOL)finished_speaking { - ttsImplMac_->OnSpeechEvent(sender, TTS_EVENT_END, 0, ""); -} - -- (void)speechSynthesizer:(NSSpeechSynthesizer*)sender - willSpeakWord:(NSRange)character_range - ofString:(NSString*)string { - ttsImplMac_->OnSpeechEvent(sender, TTS_EVENT_WORD, - character_range.location, ""); -} - -- (void)speechSynthesizer:(NSSpeechSynthesizer*)sender - didEncounterErrorAtIndex:(NSUInteger)character_index - ofString:(NSString*)string - message:(NSString*)message { - std::string message_utf8 = base::SysNSStringToUTF8(message); - ttsImplMac_->OnSpeechEvent(sender, TTS_EVENT_ERROR, character_index, - message_utf8); -} - -@end - -@implementation SingleUseSpeechSynthesizer - -- (id)initWithUtterance:(NSString*)utterance { - self = [super init]; - if (self) { - utterance_.reset([utterance retain]); - didSpeak_ = false; - } - return self; -} - -- (bool)startSpeakingRetainedUtterance { - CHECK(!didSpeak_); - CHECK(utterance_); - didSpeak_ = true; - return [super startSpeakingString:utterance_]; -} - -- (bool)startSpeakingString:(NSString*)utterance { - CHECK(false); - return false; -} - -@end diff --git a/chromium_src/chrome/browser/speech/tts_message_filter.cc b/chromium_src/chrome/browser/speech/tts_message_filter.cc deleted file mode 100644 index 1a198d9e26e1e..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_message_filter.cc +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 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. - -#include "chrome/browser/speech/tts_message_filter.h" - -#include "base/bind.h" -#include "base/logging.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/render_process_host.h" - -using content::BrowserThread; - -TtsMessageFilter::TtsMessageFilter(int render_process_id, - content::BrowserContext* browser_context) - : BrowserMessageFilter(TtsMsgStart), - render_process_id_(render_process_id), - browser_context_(browser_context), - weak_ptr_factory_(this) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - TtsController::GetInstance()->AddVoicesChangedDelegate(this); - - // Balanced in OnChannelClosingInUIThread() to keep the ref-count be non-zero - // until all WeakPtr's are invalidated. - AddRef(); -} - -void TtsMessageFilter::OverrideThreadForMessage( - const IPC::Message& message, BrowserThread::ID* thread) { - switch (message.type()) { - case TtsHostMsg_InitializeVoiceList::ID: - case TtsHostMsg_Speak::ID: - case TtsHostMsg_Pause::ID: - case TtsHostMsg_Resume::ID: - case TtsHostMsg_Cancel::ID: - *thread = BrowserThread::UI; - break; - } -} - -bool TtsMessageFilter::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(TtsMessageFilter, message) - IPC_MESSAGE_HANDLER(TtsHostMsg_InitializeVoiceList, OnInitializeVoiceList) - IPC_MESSAGE_HANDLER(TtsHostMsg_Speak, OnSpeak) - IPC_MESSAGE_HANDLER(TtsHostMsg_Pause, OnPause) - IPC_MESSAGE_HANDLER(TtsHostMsg_Resume, OnResume) - IPC_MESSAGE_HANDLER(TtsHostMsg_Cancel, OnCancel) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void TtsMessageFilter::OnChannelClosing() { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&TtsMessageFilter::OnChannelClosingInUIThread, this)); -} - -void TtsMessageFilter::OnDestruct() const { - BrowserThread::DeleteOnUIThread::Destruct(this); -} - -void TtsMessageFilter::OnInitializeVoiceList() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - TtsController* tts_controller = TtsController::GetInstance(); - std::vector voices; - tts_controller->GetVoices(browser_context_, &voices); - - std::vector out_voices; - out_voices.resize(voices.size()); - for (size_t i = 0; i < voices.size(); ++i) { - TtsVoice& out_voice = out_voices[i]; - out_voice.voice_uri = voices[i].name; - out_voice.name = voices[i].name; - out_voice.lang = voices[i].lang; - out_voice.local_service = !voices[i].remote; - out_voice.is_default = (i == 0); - } - Send(new TtsMsg_SetVoiceList(out_voices)); -} - -void TtsMessageFilter::OnSpeak(const TtsUtteranceRequest& request) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - std::unique_ptr utterance(new Utterance(browser_context_)); - utterance->set_src_id(request.id); - utterance->set_text(request.text); - utterance->set_lang(request.lang); - utterance->set_voice_name(request.voice); - utterance->set_can_enqueue(true); - - UtteranceContinuousParameters params; - params.rate = request.rate; - params.pitch = request.pitch; - params.volume = request.volume; - utterance->set_continuous_parameters(params); - - utterance->set_event_delegate(weak_ptr_factory_.GetWeakPtr()); - - TtsController::GetInstance()->SpeakOrEnqueue(utterance.release()); -} - -void TtsMessageFilter::OnPause() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - TtsController::GetInstance()->Pause(); -} - -void TtsMessageFilter::OnResume() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - TtsController::GetInstance()->Resume(); -} - -void TtsMessageFilter::OnCancel() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - TtsController::GetInstance()->Stop(); -} - -void TtsMessageFilter::OnTtsEvent(Utterance* utterance, - TtsEventType event_type, - int char_index, - const std::string& error_message) { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - switch (event_type) { - case TTS_EVENT_START: - Send(new TtsMsg_DidStartSpeaking(utterance->src_id())); - break; - case TTS_EVENT_END: - Send(new TtsMsg_DidFinishSpeaking(utterance->src_id())); - break; - case TTS_EVENT_WORD: - Send(new TtsMsg_WordBoundary(utterance->src_id(), char_index)); - break; - case TTS_EVENT_SENTENCE: - Send(new TtsMsg_SentenceBoundary(utterance->src_id(), char_index)); - break; - case TTS_EVENT_MARKER: - Send(new TtsMsg_MarkerEvent(utterance->src_id(), char_index)); - break; - case TTS_EVENT_INTERRUPTED: - Send(new TtsMsg_WasInterrupted(utterance->src_id())); - break; - case TTS_EVENT_CANCELLED: - Send(new TtsMsg_WasCancelled(utterance->src_id())); - break; - case TTS_EVENT_ERROR: - Send(new TtsMsg_SpeakingErrorOccurred( - utterance->src_id(), error_message)); - break; - case TTS_EVENT_PAUSE: - Send(new TtsMsg_DidPauseSpeaking(utterance->src_id())); - break; - case TTS_EVENT_RESUME: - Send(new TtsMsg_DidResumeSpeaking(utterance->src_id())); - break; - } -} - -void TtsMessageFilter::OnVoicesChanged() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - OnInitializeVoiceList(); -} - -void TtsMessageFilter::OnChannelClosingInUIThread() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - TtsController::GetInstance()->RemoveVoicesChangedDelegate(this); - - weak_ptr_factory_.InvalidateWeakPtrs(); - Release(); // Balanced in TtsMessageFilter(). -} - -TtsMessageFilter::~TtsMessageFilter() { - CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(!weak_ptr_factory_.HasWeakPtrs()); - TtsController::GetInstance()->RemoveVoicesChangedDelegate(this); -} \ No newline at end of file diff --git a/chromium_src/chrome/browser/speech/tts_message_filter.h b/chromium_src/chrome/browser/speech/tts_message_filter.h deleted file mode 100644 index b095651611908..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_message_filter.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 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_SPEECH_TTS_MESSAGE_FILTER_H_ -#define CHROME_BROWSER_SPEECH_TTS_MESSAGE_FILTER_H_ - -#include "base/memory/weak_ptr.h" -#include "chrome/browser/speech/tts_controller.h" -#include "chrome/common/tts_messages.h" -#include "content/public/browser/browser_message_filter.h" - -namespace content { -class BrowserContext; -} - -class TtsMessageFilter - : public content::BrowserMessageFilter, - public UtteranceEventDelegate, - public VoicesChangedDelegate { - public: - explicit TtsMessageFilter(int render_process_id, - content::BrowserContext* browser_context); - - // content::BrowserMessageFilter implementation. - void OverrideThreadForMessage( - const IPC::Message& message, - content::BrowserThread::ID* thread) override; - bool OnMessageReceived(const IPC::Message& message) override; - void OnChannelClosing() override; - void OnDestruct() const override; - - // UtteranceEventDelegate implementation. - void OnTtsEvent(Utterance* utterance, - TtsEventType event_type, - int char_index, - const std::string& error_message) override; - - // VoicesChangedDelegate implementation. - void OnVoicesChanged() override; - - private: - friend class content::BrowserThread; - friend class base::DeleteHelper; - - virtual ~TtsMessageFilter(); - - void OnInitializeVoiceList(); - void OnSpeak(const TtsUtteranceRequest& utterance); - void OnPause(); - void OnResume(); - void OnCancel(); - - void OnChannelClosingInUIThread(); - - int render_process_id_; - content::BrowserContext* browser_context_; - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(TtsMessageFilter); -}; - -#endif // CHROME_BROWSER_SPEECH_TTS_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/browser/speech/tts_platform.cc b/chromium_src/chrome/browser/speech/tts_platform.cc deleted file mode 100644 index 220e005f1816d..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_platform.cc +++ /dev/null @@ -1,28 +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/speech/tts_platform.h" - -#include - -bool TtsPlatformImpl::LoadBuiltInTtsExtension( - content::BrowserContext* browser_context) { - return false; -} - -std::string TtsPlatformImpl::error() { - return error_; -} - -void TtsPlatformImpl::clear_error() { - error_ = std::string(); -} - -void TtsPlatformImpl::set_error(const std::string& error) { - error_ = error; -} - -void TtsPlatformImpl::WillSpeakUtteranceWithVoice(const Utterance* utterance, - const VoiceData& voice_data) { -} \ No newline at end of file diff --git a/chromium_src/chrome/browser/speech/tts_platform.h b/chromium_src/chrome/browser/speech/tts_platform.h deleted file mode 100644 index f33eab1c18ad6..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_platform.h +++ /dev/null @@ -1,81 +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_SPEECH_TTS_PLATFORM_H_ -#define CHROME_BROWSER_SPEECH_TTS_PLATFORM_H_ - -#include - -#include "chrome/browser/speech/tts_controller.h" - -// Abstract class that defines the native platform TTS interface, -// subclassed by specific implementations on Win, Mac, etc. -class TtsPlatformImpl { - public: - static TtsPlatformImpl* GetInstance(); - - // Returns true if this platform implementation is supported and available. - virtual bool PlatformImplAvailable() = 0; - - // Some platforms may provide a built-in TTS extension. Returns true - // if the extension was not previously loaded and is now loading, and - // false if it's already loaded or if there's no extension to load. - // Will call TtsController::RetrySpeakingQueuedUtterances when - // the extension finishes loading. - virtual bool LoadBuiltInTtsExtension( - content::BrowserContext* browser_context); - - // Speak the given utterance with the given parameters if possible, - // and return true on success. Utterance will always be nonempty. - // If rate, pitch, or volume are -1.0, they will be ignored. - // - // The TtsController will only try to speak one utterance at - // a time. If it wants to interrupt speech, it will always call Stop - // before speaking again. - virtual bool Speak( - int utterance_id, - const std::string& utterance, - const std::string& lang, - const VoiceData& voice, - const UtteranceContinuousParameters& params) = 0; - - // Stop speaking immediately and return true on success. - virtual bool StopSpeaking() = 0; - - // Returns whether any speech is on going. - virtual bool IsSpeaking() = 0; - - // Append information about voices provided by this platform implementation - // to |out_voices|. - virtual void GetVoices(std::vector* out_voices) = 0; - - // Pause the current utterance, if any, until a call to Resume, - // Speak, or StopSpeaking. - virtual void Pause() = 0; - - // Resume speaking the current utterance, if it was paused. - virtual void Resume() = 0; - - // Allows the platform to monitor speech commands and the voices used - // for each one. - virtual void WillSpeakUtteranceWithVoice(const Utterance* utterance, - const VoiceData& voice_data); - - virtual std::string error(); - virtual void clear_error(); - virtual void set_error(const std::string& error); - - protected: - TtsPlatformImpl() {} - - // On some platforms this may be a leaky singleton - do not rely on the - // destructor being called! http://crbug.com/122026 - virtual ~TtsPlatformImpl() {} - - std::string error_; - - DISALLOW_COPY_AND_ASSIGN(TtsPlatformImpl); -}; - -#endif // CHROME_BROWSER_SPEECH_TTS_PLATFORM_H_ \ No newline at end of file diff --git a/chromium_src/chrome/browser/speech/tts_win.cc b/chromium_src/chrome/browser/speech/tts_win.cc deleted file mode 100644 index bc9411a8c1591..0000000000000 --- a/chromium_src/chrome/browser/speech/tts_win.cc +++ /dev/null @@ -1,259 +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 -#include - -#include "base/memory/singleton.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "base/win/scoped_comptr.h" -#include "chrome/browser/speech/tts_controller.h" -#include "chrome/browser/speech/tts_platform.h" - -class TtsPlatformImplWin : public TtsPlatformImpl { - public: - bool PlatformImplAvailable() override { - return true; - } - - bool Speak( - int utterance_id, - const std::string& utterance, - const std::string& lang, - const VoiceData& voice, - const UtteranceContinuousParameters& params) override; - - bool StopSpeaking() override; - - void Pause() override; - - void Resume() override; - - bool IsSpeaking() override; - - void GetVoices(std::vector* out_voices) override; - - // Get the single instance of this class. - static TtsPlatformImplWin* GetInstance(); - - static void __stdcall SpeechEventCallback(WPARAM w_param, LPARAM l_param); - - private: - TtsPlatformImplWin(); - ~TtsPlatformImplWin() override {} - - void OnSpeechEvent(); - - base::win::ScopedComPtr speech_synthesizer_; - - // These apply to the current utterance only. - std::wstring utterance_; - int utterance_id_; - int prefix_len_; - ULONG stream_number_; - int char_position_; - bool paused_; - - friend struct base::DefaultSingletonTraits; - - DISALLOW_COPY_AND_ASSIGN(TtsPlatformImplWin); -}; - -// static -TtsPlatformImpl* TtsPlatformImpl::GetInstance() { - return TtsPlatformImplWin::GetInstance(); -} - -bool TtsPlatformImplWin::Speak( - int utterance_id, - const std::string& src_utterance, - const std::string& lang, - const VoiceData& voice, - const UtteranceContinuousParameters& params) { - std::wstring prefix; - std::wstring suffix; - - if (!speech_synthesizer_.get()) - return false; - - // TODO(dmazzoni): support languages other than the default: crbug.com/88059 - - if (params.rate >= 0.0) { - // Map our multiplicative range of 0.1x to 10.0x onto Microsoft's - // linear range of -10 to 10: - // 0.1 -> -10 - // 1.0 -> 0 - // 10.0 -> 10 - speech_synthesizer_->SetRate(static_cast(10 * log10(params.rate))); - } - - if (params.pitch >= 0.0) { - // The TTS api allows a range of -10 to 10 for speech pitch. - // TODO(dtseng): cleanup if we ever use any other properties that - // require xml. - std::wstring pitch_value = - base::IntToString16(static_cast(params.pitch * 10 - 10)); - prefix = L""; - suffix = L""; - } - - if (params.volume >= 0.0) { - // The TTS api allows a range of 0 to 100 for speech volume. - speech_synthesizer_->SetVolume(static_cast(params.volume * 100)); - } - - // TODO(dmazzoni): convert SSML to SAPI xml. http://crbug.com/88072 - - utterance_ = base::UTF8ToWide(src_utterance); - utterance_id_ = utterance_id; - char_position_ = 0; - std::wstring merged_utterance = prefix + utterance_ + suffix; - prefix_len_ = prefix.size(); - - HRESULT result = speech_synthesizer_->Speak( - merged_utterance.c_str(), - SPF_ASYNC, - &stream_number_); - return (result == S_OK); -} - -bool TtsPlatformImplWin::StopSpeaking() { - if (speech_synthesizer_.get()) { - // Clear the stream number so that any further events relating to this - // utterance are ignored. - stream_number_ = 0; - - if (IsSpeaking()) { - // Stop speech by speaking the empty string with the purge flag. - speech_synthesizer_->Speak(L"", SPF_ASYNC | SPF_PURGEBEFORESPEAK, NULL); - } - if (paused_) { - speech_synthesizer_->Resume(); - paused_ = false; - } - } - return true; -} - -void TtsPlatformImplWin::Pause() { - if (speech_synthesizer_.get() && utterance_id_ && !paused_) { - speech_synthesizer_->Pause(); - paused_ = true; - TtsController::GetInstance()->OnTtsEvent( - utterance_id_, TTS_EVENT_PAUSE, char_position_, ""); - } -} - -void TtsPlatformImplWin::Resume() { - if (speech_synthesizer_.get() && utterance_id_ && paused_) { - speech_synthesizer_->Resume(); - paused_ = false; - TtsController::GetInstance()->OnTtsEvent( - utterance_id_, TTS_EVENT_RESUME, char_position_, ""); - } -} - -bool TtsPlatformImplWin::IsSpeaking() { - if (speech_synthesizer_.get()) { - SPVOICESTATUS status; - HRESULT result = speech_synthesizer_->GetStatus(&status, NULL); - if (result == S_OK) { - if (status.dwRunningState == 0 || // 0 == waiting to speak - status.dwRunningState == SPRS_IS_SPEAKING) { - return true; - } - } - } - return false; -} - -void TtsPlatformImplWin::GetVoices( - std::vector* out_voices) { - // TODO: get all voices, not just default voice. - // http://crbug.com/88059 - out_voices->push_back(VoiceData()); - VoiceData& voice = out_voices->back(); - voice.native = true; - voice.name = "native"; - voice.events.insert(TTS_EVENT_START); - voice.events.insert(TTS_EVENT_END); - voice.events.insert(TTS_EVENT_MARKER); - voice.events.insert(TTS_EVENT_WORD); - voice.events.insert(TTS_EVENT_SENTENCE); - voice.events.insert(TTS_EVENT_PAUSE); - voice.events.insert(TTS_EVENT_RESUME); -} - -void TtsPlatformImplWin::OnSpeechEvent() { - TtsController* controller = TtsController::GetInstance(); - SPEVENT event; - while (S_OK == speech_synthesizer_->GetEvents(1, &event, NULL)) { - if (event.ulStreamNum != stream_number_) - continue; - - switch (event.eEventId) { - case SPEI_START_INPUT_STREAM: - controller->OnTtsEvent( - utterance_id_, TTS_EVENT_START, 0, std::string()); - break; - case SPEI_END_INPUT_STREAM: - char_position_ = utterance_.size(); - controller->OnTtsEvent( - utterance_id_, TTS_EVENT_END, char_position_, std::string()); - break; - case SPEI_TTS_BOOKMARK: - controller->OnTtsEvent( - utterance_id_, TTS_EVENT_MARKER, char_position_, std::string()); - break; - case SPEI_WORD_BOUNDARY: - char_position_ = static_cast(event.lParam) - prefix_len_; - controller->OnTtsEvent( - utterance_id_, TTS_EVENT_WORD, char_position_, - std::string()); - break; - case SPEI_SENTENCE_BOUNDARY: - char_position_ = static_cast(event.lParam) - prefix_len_; - controller->OnTtsEvent( - utterance_id_, TTS_EVENT_SENTENCE, char_position_, - std::string()); - break; - default: - break; - } - } -} - -TtsPlatformImplWin::TtsPlatformImplWin() - : utterance_id_(0), - prefix_len_(0), - stream_number_(0), - char_position_(0), - paused_(false) { - speech_synthesizer_.CreateInstance(CLSID_SpVoice); - if (speech_synthesizer_.get()) { - ULONGLONG event_mask = - SPFEI(SPEI_START_INPUT_STREAM) | - SPFEI(SPEI_TTS_BOOKMARK) | - SPFEI(SPEI_WORD_BOUNDARY) | - SPFEI(SPEI_SENTENCE_BOUNDARY) | - SPFEI(SPEI_END_INPUT_STREAM); - speech_synthesizer_->SetInterest(event_mask, event_mask); - speech_synthesizer_->SetNotifyCallbackFunction( - TtsPlatformImplWin::SpeechEventCallback, 0, 0); - } -} - -// static -TtsPlatformImplWin* TtsPlatformImplWin::GetInstance() { - return base::Singleton>::get(); -} - -// static -void TtsPlatformImplWin::SpeechEventCallback( - WPARAM w_param, LPARAM l_param) { - GetInstance()->OnSpeechEvent(); -} diff --git a/chromium_src/chrome/browser/ui/browser_dialogs.h b/chromium_src/chrome/browser/ui/browser_dialogs.h deleted file mode 100644 index 76d6e00a4fa4f..0000000000000 --- a/chromium_src/chrome/browser/ui/browser_dialogs.h +++ /dev/null @@ -1,26 +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_UI_BROWSER_DIALOGS_H_ -#define CHROME_BROWSER_UI_BROWSER_DIALOGS_H_ - -#include "third_party/skia/include/core/SkColor.h" -#include "ui/gfx/native_widget_types.h" - -class SkBitmap; - -namespace content { -class ColorChooser; -class WebContents; -} - -namespace chrome { - -// Shows a color chooser that reports to the given WebContents. -content::ColorChooser* ShowColorChooser(content::WebContents* web_contents, - SkColor initial_color); - -} // namespace chrome - -#endif // CHROME_BROWSER_UI_BROWSER_DIALOGS_H_ diff --git a/chromium_src/chrome/browser/ui/cocoa/color_chooser_mac.mm b/chromium_src/chrome/browser/ui/cocoa/color_chooser_mac.mm deleted file mode 100644 index 6183dd5d5bd04..0000000000000 --- a/chromium_src/chrome/browser/ui/cocoa/color_chooser_mac.mm +++ /dev/null @@ -1,161 +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. - -#import - -#include "base/logging.h" -#import "base/mac/scoped_nsobject.h" -#include "chrome/browser/ui/browser_dialogs.h" -#include "content/public/browser/color_chooser.h" -#include "content/public/browser/web_contents.h" -#include "skia/ext/skia_utils_mac.h" - -class ColorChooserMac; - -// A Listener class to act as a event target for NSColorPanel and send -// the results to the C++ class, ColorChooserMac. -@interface ColorPanelCocoa : NSObject { - @private - // We don't call DidChooseColor if the change wasn't caused by the user - // interacting with the panel. - BOOL nonUserChange_; - ColorChooserMac* chooser_; // weak, owns this -} - -- (id)initWithChooser:(ColorChooserMac*)chooser; - -// Called from NSColorPanel. -- (void)didChooseColor:(NSColorPanel*)panel; - -// Sets color to the NSColorPanel as a non user change. -- (void)setColor:(NSColor*)color; - -@end - -class ColorChooserMac : public content::ColorChooser { - public: - static ColorChooserMac* Open(content::WebContents* web_contents, - SkColor initial_color); - - ColorChooserMac(content::WebContents* tab, SkColor initial_color); - virtual ~ColorChooserMac(); - - // Called from ColorPanelCocoa. - void DidChooseColorInColorPanel(SkColor color); - void DidCloseColorPabel(); - - virtual void End() override; - virtual void SetSelectedColor(SkColor color) override; - - private: - static ColorChooserMac* current_color_chooser_; - - // The web contents invoking the color chooser. No ownership because it will - // outlive this class. - content::WebContents* web_contents_; - base::scoped_nsobject panel_; -}; - -ColorChooserMac* ColorChooserMac::current_color_chooser_ = NULL; - -// static -ColorChooserMac* ColorChooserMac::Open(content::WebContents* web_contents, - SkColor initial_color) { - if (current_color_chooser_) - current_color_chooser_->End(); - DCHECK(!current_color_chooser_); - current_color_chooser_ = - new ColorChooserMac(web_contents, initial_color); - return current_color_chooser_; -} - -ColorChooserMac::ColorChooserMac(content::WebContents* web_contents, - SkColor initial_color) - : web_contents_(web_contents) { - panel_.reset([[ColorPanelCocoa alloc] initWithChooser:this]); - [panel_ setColor:skia::SkColorToDeviceNSColor(initial_color)]; - [[NSColorPanel sharedColorPanel] makeKeyAndOrderFront:nil]; -} - -ColorChooserMac::~ColorChooserMac() { - // Always call End() before destroying. - DCHECK(!panel_); -} - -void ColorChooserMac::DidChooseColorInColorPanel(SkColor color) { - if (web_contents_) - web_contents_->DidChooseColorInColorChooser(color); -} - -void ColorChooserMac::DidCloseColorPabel() { - End(); -} - -void ColorChooserMac::End() { - panel_.reset(); - DCHECK(current_color_chooser_ == this); - current_color_chooser_ = NULL; - if (web_contents_) - web_contents_->DidEndColorChooser(); -} - -void ColorChooserMac::SetSelectedColor(SkColor color) { - [panel_ setColor:skia::SkColorToDeviceNSColor(color)]; -} - -@implementation ColorPanelCocoa - -- (id)initWithChooser:(ColorChooserMac*)chooser { - if ((self = [super init])) { - chooser_ = chooser; - NSColorPanel* panel = [NSColorPanel sharedColorPanel]; - [panel setShowsAlpha:NO]; - [panel setDelegate:self]; - [panel setTarget:self]; - [panel setAction:@selector(didChooseColor:)]; - } - return self; -} - -- (void)dealloc { - NSColorPanel* panel = [NSColorPanel sharedColorPanel]; - if ([panel delegate] == self) { - [panel setDelegate:nil]; - [panel setTarget:nil]; - [panel setAction:nil]; - } - - [super dealloc]; -} - -- (void)windowWillClose:(NSNotification*)notification { - nonUserChange_ = NO; - chooser_->DidCloseColorPabel(); -} - -- (void)didChooseColor:(NSColorPanel*)panel { - if (nonUserChange_) { - nonUserChange_ = NO; - return; - } - chooser_->DidChooseColorInColorPanel(skia::NSDeviceColorToSkColor( - [[panel color] colorUsingColorSpaceName:NSDeviceRGBColorSpace])); - nonUserChange_ = NO; -} - -- (void)setColor:(NSColor*)color { - nonUserChange_ = YES; - [[NSColorPanel sharedColorPanel] setColor:color]; -} - -namespace chrome { - -content::ColorChooser* ShowColorChooser(content::WebContents* web_contents, - SkColor initial_color) { - return ColorChooserMac::Open(web_contents, initial_color); -} - -} // namepace chrome - -@end diff --git a/chromium_src/chrome/browser/ui/views/color_chooser_aura.cc b/chromium_src/chrome/browser/ui/views/color_chooser_aura.cc deleted file mode 100644 index 95bdb7c46d943..0000000000000 --- a/chromium_src/chrome/browser/ui/views/color_chooser_aura.cc +++ /dev/null @@ -1,69 +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/ui/views/color_chooser_aura.h" - -#include "chrome/browser/ui/browser_dialogs.h" -#include "content/public/browser/web_contents.h" -#include "ui/views/color_chooser/color_chooser_view.h" -#include "ui/views/widget/widget.h" - -ColorChooserAura::ColorChooserAura(content::WebContents* web_contents, - SkColor initial_color) - : web_contents_(web_contents) { - view_ = new views::ColorChooserView(this, initial_color); - widget_ = views::Widget::CreateWindowWithParent( - view_, web_contents->GetTopLevelNativeWindow()); - widget_->Show(); -} - -void ColorChooserAura::OnColorChosen(SkColor color) { - if (web_contents_) - web_contents_->DidChooseColorInColorChooser(color); -} - -void ColorChooserAura::OnColorChooserDialogClosed() { - view_ = NULL; - widget_ = NULL; - DidEndColorChooser(); -} - -void ColorChooserAura::End() { - if (widget_) { - view_->set_listener(NULL); - widget_->Close(); - view_ = NULL; - widget_ = NULL; - // DidEndColorChooser will invoke Browser::DidEndColorChooser, which deletes - // this. Take care of the call order. - DidEndColorChooser(); - } -} - -void ColorChooserAura::DidEndColorChooser() { - if (web_contents_) - web_contents_->DidEndColorChooser(); -} - -void ColorChooserAura::SetSelectedColor(SkColor color) { - if (view_) - view_->OnColorChanged(color); -} - -// static -ColorChooserAura* ColorChooserAura::Open( - content::WebContents* web_contents, SkColor initial_color) { - return new ColorChooserAura(web_contents, initial_color); -} - -#if !defined(OS_WIN) -namespace chrome { - -content::ColorChooser* ShowColorChooser(content::WebContents* web_contents, - SkColor initial_color) { - return ColorChooserAura::Open(web_contents, initial_color); -} - -} // namespace chrome -#endif // OS_WIN diff --git a/chromium_src/chrome/browser/ui/views/color_chooser_aura.h b/chromium_src/chrome/browser/ui/views/color_chooser_aura.h deleted file mode 100644 index 355f540b19d5d..0000000000000 --- a/chromium_src/chrome/browser/ui/views/color_chooser_aura.h +++ /dev/null @@ -1,57 +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_COLOR_CHOOSER_AURA_H_ -#define CHROME_BROWSER_UI_VIEWS_COLOR_CHOOSER_AURA_H_ - -#include "base/macros.h" -#include "content/public/browser/color_chooser.h" -#include "ui/views/color_chooser/color_chooser_listener.h" - -namespace content { -class WebContents; -} - -namespace views { -class ColorChooserView; -class Widget; -} - -// TODO(mukai): rename this as -Ash and move to c/b/ui/ash after Linux-aura -// switches to its native color chooser. -class ColorChooserAura : public content::ColorChooser, - public views::ColorChooserListener { - public: - static ColorChooserAura* Open(content::WebContents* web_contents, - SkColor initial_color); - - private: - ColorChooserAura(content::WebContents* web_contents, SkColor initial_color); - - // content::ColorChooser overrides: - virtual void End() override; - virtual void SetSelectedColor(SkColor color) override; - - // views::ColorChooserListener overrides: - virtual void OnColorChosen(SkColor color) override; - virtual void OnColorChooserDialogClosed() override; - - void DidEndColorChooser(); - - // The actual view of the color chooser. No ownership because its parent - // view will take care of its lifetime. - views::ColorChooserView* view_; - - // The widget for the color chooser. No ownership because it's released - // automatically when closed. - views::Widget* widget_; - - // The web contents invoking the color chooser. No ownership because it will - // outlive this class. - content::WebContents* web_contents_; - - DISALLOW_COPY_AND_ASSIGN(ColorChooserAura); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_COLOR_CHOOSER_AURA_H_ diff --git a/chromium_src/chrome/browser/ui/views/color_chooser_dialog.cc b/chromium_src/chrome/browser/ui/views/color_chooser_dialog.cc deleted file mode 100644 index 347f1043aac1c..0000000000000 --- a/chromium_src/chrome/browser/ui/views/color_chooser_dialog.cc +++ /dev/null @@ -1,85 +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/ui/views/color_chooser_dialog.h" - -#include - -#include "base/bind.h" -#include "base/message_loop/message_loop.h" -#include "base/threading/thread.h" -#include "content/public/browser/browser_thread.h" -#include "skia/ext/skia_utils_win.h" -#include "ui/views/color_chooser/color_chooser_listener.h" -#include "ui/views/win/hwnd_util.h" - -using content::BrowserThread; - -// static -COLORREF ColorChooserDialog::g_custom_colors[16]; - -ColorChooserDialog::ExecuteOpenParams::ExecuteOpenParams(SkColor color, - RunState run_state, - HWND owner) - : color(color), - run_state(run_state), - owner(owner) { -} - -ColorChooserDialog::ColorChooserDialog(views::ColorChooserListener* listener, - SkColor initial_color, - gfx::NativeWindow owning_window) - : listener_(listener) { - DCHECK(listener_); - CopyCustomColors(g_custom_colors, custom_colors_); - HWND owning_hwnd = views::HWNDForNativeWindow(owning_window); - ExecuteOpenParams execute_params(initial_color, BeginRun(owning_hwnd), - owning_hwnd); - execute_params.run_state.dialog_thread->message_loop()->PostTask(FROM_HERE, - base::Bind(&ColorChooserDialog::ExecuteOpen, this, execute_params)); -} - -ColorChooserDialog::~ColorChooserDialog() { -} - -bool ColorChooserDialog::IsRunning(gfx::NativeWindow owning_window) const { - return listener_ && IsRunningDialogForOwner( - views::HWNDForNativeWindow(owning_window)); -} - -void ColorChooserDialog::ListenerDestroyed() { - // Our associated listener has gone away, so we shouldn't call back to it if - // our worker thread returns after the listener is dead. - listener_ = NULL; -} - -void ColorChooserDialog::ExecuteOpen(const ExecuteOpenParams& params) { - CHOOSECOLOR cc; - cc.lStructSize = sizeof(CHOOSECOLOR); - cc.hwndOwner = params.owner; - cc.rgbResult = skia::SkColorToCOLORREF(params.color); - cc.lpCustColors = custom_colors_; - cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT; - bool success = !!ChooseColor(&cc); - DisableOwner(cc.hwndOwner); - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(&ColorChooserDialog::DidCloseDialog, this, success, - skia::COLORREFToSkColor(cc.rgbResult), params.run_state)); -} - -void ColorChooserDialog::DidCloseDialog(bool chose_color, - SkColor color, - RunState run_state) { - EndRun(run_state); - CopyCustomColors(custom_colors_, g_custom_colors); - if (listener_) { - if (chose_color) - listener_->OnColorChosen(color); - listener_->OnColorChooserDialogClosed(); - } -} - -void ColorChooserDialog::CopyCustomColors(COLORREF* src, COLORREF* dst) { - memcpy(dst, src, sizeof(COLORREF) * arraysize(g_custom_colors)); -} diff --git a/chromium_src/chrome/browser/ui/views/color_chooser_dialog.h b/chromium_src/chrome/browser/ui/views/color_chooser_dialog.h deleted file mode 100644 index b23061a386dc0..0000000000000 --- a/chromium_src/chrome/browser/ui/views/color_chooser_dialog.h +++ /dev/null @@ -1,73 +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_UI_VIEWS_COLOR_CHOOSER_DIALOG_H_ -#define CHROME_BROWSER_UI_VIEWS_COLOR_CHOOSER_DIALOG_H_ - -#include "base/memory/ref_counted.h" -#include "chrome/browser/ui/views/color_chooser_dialog.h" -#include "third_party/skia/include/core/SkColor.h" -#include "ui/shell_dialogs/base_shell_dialog.h" -#include "ui/shell_dialogs/base_shell_dialog_win.h" - -namespace views { -class ColorChooserListener; -} - -class ColorChooserDialog - : public base::RefCountedThreadSafe, - public ui::BaseShellDialog, - public ui::BaseShellDialogImpl { - public: - ColorChooserDialog(views::ColorChooserListener* listener, - SkColor initial_color, - gfx::NativeWindow owning_window); - virtual ~ColorChooserDialog(); - - // BaseShellDialog: - virtual bool IsRunning(gfx::NativeWindow owning_window) const override; - virtual void ListenerDestroyed() override; - - private: - struct ExecuteOpenParams { - ExecuteOpenParams(SkColor color, RunState run_state, HWND owner); - SkColor color; - RunState run_state; - HWND owner; - }; - - // Called on the dialog thread to show the actual color chooser. This is - // shown modal to |params.owner|. Once it's closed, calls back to - // DidCloseDialog() on the UI thread. - void ExecuteOpen(const ExecuteOpenParams& params); - - // Called on the UI thread when a color chooser is closed. |chose_color| is - // true if the user actually chose a color, in which case |color| is the - // chosen color. Calls back to the |listener_| (if applicable) to notify it - // of the results, and copies the modified array of |custom_colors_| back to - // |g_custom_colors| so future dialogs will see the changes. - void DidCloseDialog(bool chose_color, SkColor color, RunState run_state); - - // Copies the array of colors in |src| to |dst|. - void CopyCustomColors(COLORREF*, COLORREF*); - - // The user's custom colors. Kept process-wide so that they can be persisted - // from one dialog invocation to the next. - static COLORREF g_custom_colors[16]; - - // A copy of the custom colors for the current dialog to display and modify. - // This allows us to safely access the colors even if multiple windows are - // simultaneously showing color choosers (which would cause thread safety - // problems if we gave them direct handles to |g_custom_colors|). - COLORREF custom_colors_[16]; - - // The listener to notify when the user closes the dialog. This may be set to - // NULL before the color chooser is closed, signalling that the listener no - // longer cares about the outcome. - views::ColorChooserListener* listener_; - - DISALLOW_COPY_AND_ASSIGN(ColorChooserDialog); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_COLOR_CHOOSER_DIALOG_H_ diff --git a/chromium_src/chrome/browser/ui/views/color_chooser_win.cc b/chromium_src/chrome/browser/ui/views/color_chooser_win.cc deleted file mode 100644 index 7a4f757333399..0000000000000 --- a/chromium_src/chrome/browser/ui/views/color_chooser_win.cc +++ /dev/null @@ -1,108 +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 - -#include "chrome/browser/ui/browser_dialogs.h" -#include "chrome/browser/ui/views/color_chooser_aura.h" -#include "chrome/browser/ui/views/color_chooser_dialog.h" -#include "content/public/browser/color_chooser.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host.h" -#include "content/public/browser/render_widget_host_view.h" -#include "content/public/browser/web_contents.h" -#include "ui/aura/window.h" -#include "ui/views/color_chooser/color_chooser_listener.h" - -class ColorChooserWin : public content::ColorChooser, - public views::ColorChooserListener { - public: - static ColorChooserWin* Open(content::WebContents* web_contents, - SkColor initial_color); - - ColorChooserWin(content::WebContents* web_contents, - SkColor initial_color); - ~ColorChooserWin(); - - // content::ColorChooser overrides: - virtual void End() override; - virtual void SetSelectedColor(SkColor color) override {} - - // views::ColorChooserListener overrides: - virtual void OnColorChosen(SkColor color); - virtual void OnColorChooserDialogClosed(); - - private: - static ColorChooserWin* current_color_chooser_; - - // The web contents invoking the color chooser. No ownership. because it will - // outlive this class. - content::WebContents* web_contents_; - - // The color chooser dialog which maintains the native color chooser UI. - scoped_refptr color_chooser_dialog_; -}; - -ColorChooserWin* ColorChooserWin::current_color_chooser_ = NULL; - -ColorChooserWin* ColorChooserWin::Open(content::WebContents* web_contents, - SkColor initial_color) { - if (current_color_chooser_) - return NULL; - current_color_chooser_ = new ColorChooserWin(web_contents, initial_color); - return current_color_chooser_; -} - -ColorChooserWin::ColorChooserWin(content::WebContents* web_contents, - SkColor initial_color) - : web_contents_(web_contents) { - gfx::NativeWindow owning_window = web_contents->GetRenderViewHost() - ->GetWidget() - ->GetView() - ->GetNativeView() - ->GetToplevelWindow(); - color_chooser_dialog_ = new ColorChooserDialog(this, - initial_color, - owning_window); -} - -ColorChooserWin::~ColorChooserWin() { - // Always call End() before destroying. - DCHECK(!color_chooser_dialog_); -} - -void ColorChooserWin::End() { - // The ColorChooserDialog's listener is going away. Ideally we'd - // programmatically close the dialog at this point. Since that's impossible, - // we instead tell the dialog its listener is going away, so that the dialog - // doesn't try to communicate with a destroyed listener later. (We also tell - // the renderer the dialog is closed, since from the renderer's perspective - // it effectively is.) - OnColorChooserDialogClosed(); -} - -void ColorChooserWin::OnColorChosen(SkColor color) { - if (web_contents_) - web_contents_->DidChooseColorInColorChooser(color); -} - -void ColorChooserWin::OnColorChooserDialogClosed() { - if (color_chooser_dialog_.get()) { - color_chooser_dialog_->ListenerDestroyed(); - color_chooser_dialog_ = NULL; - } - DCHECK(current_color_chooser_ == this); - current_color_chooser_ = NULL; - if (web_contents_) - web_contents_->DidEndColorChooser(); -} - -namespace chrome { - -content::ColorChooser* ShowColorChooser(content::WebContents* web_contents, - SkColor initial_color) { - return ColorChooserWin::Open(web_contents, initial_color); -} - -} // namespace chrome diff --git a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc b/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc deleted file mode 100644 index cead675a74d33..0000000000000 --- a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc +++ /dev/null @@ -1,142 +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. - -#include "chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h" - -#include "atom/browser/ui/views/global_menu_bar_x11.h" -#include "base/bind.h" -#include "base/debug/leak_annotations.h" -#include "base/logging.h" -#include "content/public/browser/browser_thread.h" - -using content::BrowserThread; - -namespace { - -const char kAppMenuRegistrarName[] = "com.canonical.AppMenu.Registrar"; -const char kAppMenuRegistrarPath[] = "/com/canonical/AppMenu/Registrar"; - -} // namespace - -// static -GlobalMenuBarRegistrarX11* GlobalMenuBarRegistrarX11::GetInstance() { - return base::Singleton::get(); -} - -void GlobalMenuBarRegistrarX11::OnWindowMapped(unsigned long xid) { - live_xids_.insert(xid); - - if (registrar_proxy_) - RegisterXID(xid); -} - -void GlobalMenuBarRegistrarX11::OnWindowUnmapped(unsigned long xid) { - if (registrar_proxy_) - UnregisterXID(xid); - - live_xids_.erase(xid); -} - -GlobalMenuBarRegistrarX11::GlobalMenuBarRegistrarX11() - : registrar_proxy_(nullptr) { - // libdbusmenu uses the gio version of dbus; I tried using the code in dbus/, - // but it looks like that's isn't sharing the bus name with the gio version, - // even when |connection_type| is set to SHARED. - g_dbus_proxy_new_for_bus( - G_BUS_TYPE_SESSION, - static_cast( - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), - nullptr, - kAppMenuRegistrarName, - kAppMenuRegistrarPath, - kAppMenuRegistrarName, - nullptr, // TODO: Probalby want a real cancelable. - static_cast(OnProxyCreatedThunk), - this); -} - -GlobalMenuBarRegistrarX11::~GlobalMenuBarRegistrarX11() { - if (registrar_proxy_) { - g_signal_handlers_disconnect_by_func( - registrar_proxy_, - reinterpret_cast(OnNameOwnerChangedThunk), - this); - g_object_unref(registrar_proxy_); - } -} - -void GlobalMenuBarRegistrarX11::RegisterXID(unsigned long xid) { - DCHECK(registrar_proxy_); - std::string path = atom::GlobalMenuBarX11::GetPathForWindow(xid); - - ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087 - // TODO(erg): The mozilla implementation goes to a lot of callback trouble - // just to make sure that they react to make sure there's some sort of - // cancelable object; including making a whole callback just to handle the - // cancelable. - // - // I don't see any reason why we should care if "RegisterWindow" completes or - // not. - g_dbus_proxy_call(registrar_proxy_, - "RegisterWindow", - g_variant_new("(uo)", xid, path.c_str()), - G_DBUS_CALL_FLAGS_NONE, -1, - nullptr, - nullptr, - nullptr); -} - -void GlobalMenuBarRegistrarX11::UnregisterXID(unsigned long xid) { - DCHECK(registrar_proxy_); - std::string path = atom::GlobalMenuBarX11::GetPathForWindow(xid); - - ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/314087 - // TODO(erg): The mozilla implementation goes to a lot of callback trouble - // just to make sure that they react to make sure there's some sort of - // cancelable object; including making a whole callback just to handle the - // cancelable. - // - // I don't see any reason why we should care if "UnregisterWindow" completes - // or not. - g_dbus_proxy_call(registrar_proxy_, - "UnregisterWindow", - g_variant_new("(u)", xid), - G_DBUS_CALL_FLAGS_NONE, -1, - nullptr, - nullptr, - nullptr); -} - -void GlobalMenuBarRegistrarX11::OnProxyCreated(GObject* source, - GAsyncResult* result) { - GError* error = nullptr; - GDBusProxy* proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (error) { - g_error_free(error); - return; - } - - // TODO(erg): Mozilla's implementation has a workaround for GDBus - // cancellation here. However, it's marked as fixed. If there's weird - // problems with cancelation, look at how they fixed their issues. - - registrar_proxy_ = proxy; - - g_signal_connect(registrar_proxy_, "notify::g-name-owner", - G_CALLBACK(OnNameOwnerChangedThunk), this); - - OnNameOwnerChanged(nullptr, nullptr); -} - -void GlobalMenuBarRegistrarX11::OnNameOwnerChanged(GObject* /* ignored */, - GParamSpec* /* ignored */) { - // If the name owner changed, we need to reregister all the live xids with - // the system. - for (std::set::const_iterator it = live_xids_.begin(); - it != live_xids_.end(); ++it) { - RegisterXID(*it); - } -} 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 95a08b229f478..0000000000000 --- a/chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h +++ /dev/null @@ -1,53 +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" - -// Advertises our menu bars to Unity. -// -// GlobalMenuBarX11 is responsible for managing the DbusmenuServer for each -// XID. We need a separate object to own the dbus channel to -// com.canonical.AppMenu.Registrar and to register/unregister the mapping -// between a XID and the DbusmenuServer instance we are offering. -class GlobalMenuBarRegistrarX11 { - public: - static GlobalMenuBarRegistrarX11* GetInstance(); - - void OnWindowMapped(unsigned long xid); - void OnWindowUnmapped(unsigned long xid); - - private: - friend struct base::DefaultSingletonTraits; - - GlobalMenuBarRegistrarX11(); - ~GlobalMenuBarRegistrarX11(); - - // Sends the actual message. - void RegisterXID(unsigned long xid); - void UnregisterXID(unsigned long xid); - - CHROMEG_CALLBACK_1(GlobalMenuBarRegistrarX11, void, OnProxyCreated, - GObject*, GAsyncResult*); - CHROMEG_CALLBACK_1(GlobalMenuBarRegistrarX11, void, OnNameOwnerChanged, - GObject*, GParamSpec*); - - GDBusProxy* registrar_proxy_; - - // Window XIDs which want to be registered, but haven't yet been because - // we're waiting for the proxy to become available. - std::set live_xids_; - - DISALLOW_COPY_AND_ASSIGN(GlobalMenuBarRegistrarX11); -}; - -#endif // CHROME_BROWSER_UI_VIEWS_FRAME_GLOBAL_MENU_BAR_REGISTRAR_X11_H_ diff --git a/chromium_src/chrome/common/chrome_constants.cc b/chromium_src/chrome/common/chrome_constants.cc deleted file mode 100644 index 43a6ccdc7cb4a..0000000000000 --- a/chromium_src/chrome/common/chrome_constants.cc +++ /dev/null @@ -1,74 +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/common/chrome_constants.h" - -#define FPL FILE_PATH_LITERAL - -namespace chrome { - -#if defined(OS_MACOSX) -const base::FilePath::CharType kFrameworkName[] = - FPL(ATOM_PRODUCT_NAME " Framework.framework"); -#endif // OS_MACOSX - -// filenames -const base::FilePath::CharType kCacheDirname[] = FPL("Cache"); -const base::FilePath::CharType kChannelIDFilename[] = FPL("Origin Bound Certs"); -const base::FilePath::CharType kCookieFilename[] = FPL("Cookies"); -const base::FilePath::CharType kCRLSetFilename[] = - FPL("Certificate Revocation Lists"); -const base::FilePath::CharType kCustomDictionaryFileName[] = - FPL("Custom Dictionary.txt"); -const base::FilePath::CharType kExtensionActivityLogFilename[] = - FPL("Extension Activity"); -const base::FilePath::CharType kExtensionsCookieFilename[] = - FPL("Extension Cookies"); -const base::FilePath::CharType kFirstRunSentinel[] = FPL("First Run"); -const base::FilePath::CharType kGCMStoreDirname[] = FPL("GCM Store"); -const base::FilePath::CharType kLocalStateFilename[] = FPL("Local State"); -const base::FilePath::CharType kLocalStorePoolName[] = FPL("LocalStorePool"); -const base::FilePath::CharType kMediaCacheDirname[] = FPL("Media Cache"); -const base::FilePath::CharType kNetworkPersistentStateFilename[] = - FPL("Network Persistent State"); -const base::FilePath::CharType kOfflinePageArchviesDirname[] = - FPL("Offline Pages/archives"); -const base::FilePath::CharType kOfflinePageMetadataDirname[] = - FPL("Offline Pages/metadata"); -const base::FilePath::CharType kPreferencesFilename[] = FPL("Preferences"); -const base::FilePath::CharType kProtectedPreferencesFilenameDeprecated[] = - FPL("Protected Preferences"); -const base::FilePath::CharType kReadmeFilename[] = FPL("README"); -const base::FilePath::CharType kResetPromptMementoFilename[] = - FPL("Reset Prompt Memento"); -const base::FilePath::CharType kSafeBrowsingBaseFilename[] = - FPL("Safe Browsing"); -const base::FilePath::CharType kSecurePreferencesFilename[] = - FPL("Secure Preferences"); -const base::FilePath::CharType kServiceStateFileName[] = FPL("Service State"); -const base::FilePath::CharType kSingletonCookieFilename[] = - FPL("SingletonCookie"); -const base::FilePath::CharType kSingletonLockFilename[] = FPL("SingletonLock"); -const base::FilePath::CharType kSingletonSocketFilename[] = - FPL("SingletonSocket"); -const base::FilePath::CharType kSupervisedUserSettingsFilename[] = - FPL("Managed Mode Settings"); -const base::FilePath::CharType kThemePackFilename[] = FPL("Cached Theme.pak"); -const base::FilePath::CharType kThemePackMaterialDesignFilename[] = - FPL("Cached Theme Material Design.pak"); -const base::FilePath::CharType kWebAppDirname[] = FPL("Web Applications"); - -// File name of the Pepper Flash plugin on different platforms. -const base::FilePath::CharType kPepperFlashPluginFilename[] = -#if defined(OS_MACOSX) - FPL("PepperFlashPlayer.plugin"); -#elif defined(OS_WIN) - FPL("pepflashplayer.dll"); -#else // OS_LINUX, etc. - FPL("libpepflashplayer.so"); -#endif - -} // namespace chrome - -#undef FPL diff --git a/chromium_src/chrome/common/chrome_constants.h b/chromium_src/chrome/common/chrome_constants.h deleted file mode 100644 index 2df506ac5d59a..0000000000000 --- a/chromium_src/chrome/common/chrome_constants.h +++ /dev/null @@ -1,58 +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. - -// A handful of resource-like constants related to the Chrome application. - -#ifndef CHROME_COMMON_CHROME_CONSTANTS_H_ -#define CHROME_COMMON_CHROME_CONSTANTS_H_ - -#include "base/files/file_path.h" - -namespace chrome { - -#if defined(OS_MACOSX) -// NOTE: if you change the value of kFrameworkName, please don't forget to -// update components/test/run_all_unittests.cc as well. -// TODO(tfarina): Remove the comment above, when you fix components to use plist -// on Mac. -extern const base::FilePath::CharType kFrameworkName[]; -#endif // OS_MACOSX - -// filenames -extern const base::FilePath::CharType kCacheDirname[]; -extern const base::FilePath::CharType kChannelIDFilename[]; -extern const base::FilePath::CharType kCookieFilename[]; -extern const base::FilePath::CharType kCRLSetFilename[]; -extern const base::FilePath::CharType kCustomDictionaryFileName[]; -extern const base::FilePath::CharType kExtensionActivityLogFilename[]; -extern const base::FilePath::CharType kExtensionsCookieFilename[]; -extern const base::FilePath::CharType kFirstRunSentinel[]; -extern const base::FilePath::CharType kGCMStoreDirname[]; -extern const base::FilePath::CharType kLocalStateFilename[]; -extern const base::FilePath::CharType kLocalStorePoolName[]; -extern const base::FilePath::CharType kMediaCacheDirname[]; -extern const base::FilePath::CharType kNetworkPersistentStateFilename[]; -extern const base::FilePath::CharType kOfflinePageArchviesDirname[]; -extern const base::FilePath::CharType kOfflinePageMetadataDirname[]; -extern const base::FilePath::CharType kPreferencesFilename[]; -extern const base::FilePath::CharType kProtectedPreferencesFilenameDeprecated[]; -extern const base::FilePath::CharType kReadmeFilename[]; -extern const base::FilePath::CharType kResetPromptMementoFilename[]; -extern const base::FilePath::CharType kSafeBrowsingBaseFilename[]; -extern const base::FilePath::CharType kSecurePreferencesFilename[]; -extern const base::FilePath::CharType kServiceStateFileName[]; -extern const base::FilePath::CharType kSingletonCookieFilename[]; -extern const base::FilePath::CharType kSingletonLockFilename[]; -extern const base::FilePath::CharType kSingletonSocketFilename[]; -extern const base::FilePath::CharType kSupervisedUserSettingsFilename[]; -extern const base::FilePath::CharType kThemePackFilename[]; -extern const base::FilePath::CharType kThemePackMaterialDesignFilename[]; -extern const base::FilePath::CharType kWebAppDirname[]; - -// File name of the Pepper Flash plugin on different platforms. -extern const base::FilePath::CharType kPepperFlashPluginFilename[]; - -} // namespace chrome - -#endif // CHROME_COMMON_CHROME_CONSTANTS_H_ diff --git a/chromium_src/chrome/common/chrome_paths.cc b/chromium_src/chrome/common/chrome_paths.cc deleted file mode 100644 index 293ea2638aef8..0000000000000 --- a/chromium_src/chrome/common/chrome_paths.cc +++ /dev/null @@ -1,612 +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/common/chrome_paths.h" - -#include "base/files/file_util.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/mac/bundle_locations.h" -#include "base/path_service.h" -#include "base/strings/string_util.h" -#include "base/sys_info.h" -#include "base/threading/thread_restrictions.h" -#include "base/version.h" -#include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_paths_internal.h" -#include "chrome/common/widevine_cdm_constants.h" -#include "third_party/widevine/cdm/stub/widevine_cdm_version.h" - -#if defined(OS_ANDROID) -#include "base/android/path_utils.h" -#include "base/base_paths_android.h" -// ui/base must only be used on Android. See BUILD.gn for dependency info. -#include "ui/base/ui_base_paths.h" // nogncheck -#endif - -#if defined(OS_MACOSX) -#include "base/mac/foundation_util.h" -#endif - -#if defined(OS_WIN) -#include "base/win/registry.h" -#endif - -namespace { - -// The Pepper Flash plugins are in a directory with this name. -const base::FilePath::CharType kPepperFlashBaseDirectory[] = - FILE_PATH_LITERAL("PepperFlash"); - -#if defined(OS_MACOSX) && !defined(OS_IOS) -const base::FilePath::CharType kPepperFlashSystemBaseDirectory[] = - FILE_PATH_LITERAL("Internet Plug-Ins/PepperFlashPlayer"); -const base::FilePath::CharType kFlashSystemBaseDirectory[] = - FILE_PATH_LITERAL("Internet Plug-Ins"); -const base::FilePath::CharType kFlashSystemPluginName[] = - FILE_PATH_LITERAL("Flash Player.plugin"); -#endif - -const base::FilePath::CharType kInternalNaClPluginFileName[] = - FILE_PATH_LITERAL("internal-nacl-plugin"); - -#if defined(OS_LINUX) -// The path to the external extension .json files. -// /usr/share seems like a good choice, see: http://www.pathname.com/fhs/ -const base::FilePath::CharType kFilepathSinglePrefExtensions[] = -#if defined(GOOGLE_CHROME_BUILD) - FILE_PATH_LITERAL("/usr/share/google-chrome/extensions"); -#else - FILE_PATH_LITERAL("/usr/share/chromium/extensions"); -#endif // defined(GOOGLE_CHROME_BUILD) - -// The path to the hint file that tells the pepper plugin loader -// where it can find the latest component updated flash. -const base::FilePath::CharType kComponentUpdatedFlashHint[] = - FILE_PATH_LITERAL("latest-component-updated-flash"); -#endif // defined(OS_LINUX) - -static base::LazyInstance - g_invalid_specified_user_data_dir = LAZY_INSTANCE_INITIALIZER; - -// Gets the path for internal plugins. -bool GetInternalPluginsDirectory(base::FilePath* result) { -#if defined(OS_MACOSX) && !defined(OS_IOS) - // If called from Chrome, get internal plugins from a subdirectory of the - // framework. - if (base::mac::AmIBundled()) { - *result = chrome::GetFrameworkBundlePath(); - DCHECK(!result->empty()); - *result = result->Append("Internet Plug-Ins"); - return true; - } - // In tests, just look in the module directory (below). -#endif - - // The rest of the world expects plugins in the module directory. - return PathService::Get(base::DIR_MODULE, result); -} - -#if defined(OS_WIN) -// Gets the Flash path if installed on the system. |is_npapi| determines whether -// to return the NPAPI of the PPAPI version of the system plugin. -bool GetSystemFlashFilename(base::FilePath* out_path, bool is_npapi) { - const wchar_t kNpapiFlashRegistryRoot[] = - L"SOFTWARE\\Macromedia\\FlashPlayerPlugin"; - const wchar_t kPepperFlashRegistryRoot[] = - L"SOFTWARE\\Macromedia\\FlashPlayerPepper"; - const wchar_t kFlashPlayerPathValueName[] = L"PlayerPath"; - - base::win::RegKey path_key( - HKEY_LOCAL_MACHINE, - is_npapi ? kNpapiFlashRegistryRoot : kPepperFlashRegistryRoot, KEY_READ); - base::string16 path_str; - if (FAILED(path_key.ReadValue(kFlashPlayerPathValueName, &path_str))) - return false; - - *out_path = base::FilePath(path_str); - return true; -} -#endif - -} // namespace - -namespace chrome { - -bool PathProvider(int key, base::FilePath* result) { - // Some keys are just aliases... - switch (key) { - case chrome::DIR_APP: - return PathService::Get(base::DIR_MODULE, result); - case chrome::DIR_LOGS: -#ifdef NDEBUG - // Release builds write to the data dir - return PathService::Get(chrome::DIR_USER_DATA, result); -#else - // Debug builds write next to the binary (in the build tree) -#if defined(OS_MACOSX) - if (!PathService::Get(base::DIR_EXE, result)) - return false; - if (base::mac::AmIBundled()) { - // If we're called from chrome, dump it beside the app (outside the - // app bundle), if we're called from a unittest, we'll already - // outside the bundle so use the exe dir. - // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium. - *result = result->DirName(); - *result = result->DirName(); - *result = result->DirName(); - } - return true; -#else - return PathService::Get(base::DIR_EXE, result); -#endif // defined(OS_MACOSX) -#endif // NDEBUG - case chrome::FILE_RESOURCE_MODULE: - return PathService::Get(base::FILE_MODULE, result); - } - - // Assume that we will not need to create the directory if it does not exist. - // This flag can be set to true for the cases where we want to create it. - bool create_dir = false; - - base::FilePath cur; - switch (key) { - case chrome::DIR_USER_DATA: - if (!GetDefaultUserDataDirectory(&cur)) { - NOTREACHED(); - return false; - } - create_dir = true; - break; - case chrome::DIR_USER_DOCUMENTS: - if (!GetUserDocumentsDirectory(&cur)) - return false; - create_dir = true; - break; - case chrome::DIR_USER_MUSIC: - if (!GetUserMusicDirectory(&cur)) - return false; - break; - case chrome::DIR_USER_PICTURES: - if (!GetUserPicturesDirectory(&cur)) - return false; - break; - case chrome::DIR_USER_VIDEOS: - if (!GetUserVideosDirectory(&cur)) - return false; - break; - case chrome::DIR_DEFAULT_DOWNLOADS_SAFE: -#if defined(OS_WIN) || defined(OS_LINUX) - if (!GetUserDownloadsDirectorySafe(&cur)) - return false; - break; -#else - // Fall through for all other platforms. -#endif - case chrome::DIR_DEFAULT_DOWNLOADS: -#if defined(OS_ANDROID) - if (!base::android::GetDownloadsDirectory(&cur)) - return false; -#else - if (!GetUserDownloadsDirectory(&cur)) - return false; - // Do not create the download directory here, we have done it twice now - // and annoyed a lot of users. -#endif - break; - case chrome::DIR_CRASH_DUMPS: -#if defined(OS_CHROMEOS) - // ChromeOS uses a separate directory. See http://crosbug.com/25089 - cur = base::FilePath("/var/log/chrome"); -#elif defined(OS_ANDROID) - if (!base::android::GetCacheDirectory(&cur)) - return false; -#else - // The crash reports are always stored relative to the default user data - // directory. This avoids the problem of having to re-initialize the - // exception handler after parsing command line options, which may - // override the location of the app's profile directory. - if (!GetDefaultUserDataDirectory(&cur)) - return false; -#endif -#if defined(OS_MACOSX) - cur = cur.Append(FILE_PATH_LITERAL("Crashpad")); -#else - cur = cur.Append(FILE_PATH_LITERAL("Crash Reports")); -#endif - create_dir = true; - break; -#if defined(OS_WIN) - case chrome::DIR_WATCHER_DATA: - // The watcher data is always stored relative to the default user data - // directory. This allows the watcher to be initialized before - // command-line options have been parsed. - if (!GetDefaultUserDataDirectory(&cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("Diagnostics")); - break; -#endif - case chrome::DIR_RESOURCES: -#if defined(OS_MACOSX) - cur = base::mac::FrameworkBundlePath(); - cur = cur.Append(FILE_PATH_LITERAL("Resources")); -#else - if (!PathService::Get(chrome::DIR_APP, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("resources")); -#endif - break; - case chrome::DIR_INSPECTOR: - if (!PathService::Get(chrome::DIR_RESOURCES, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("inspector")); - break; - case chrome::DIR_APP_DICTIONARIES: -#if defined(OS_POSIX) - // We can't write into the EXE dir on Linux, so keep dictionaries - // alongside the safe browsing database in the user data dir. - // And we don't want to write into the bundle on the Mac, so push - // it to the user data dir there also. - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; -#else - if (!PathService::Get(base::DIR_EXE, &cur)) - return false; -#endif - cur = cur.Append(FILE_PATH_LITERAL("Dictionaries")); - create_dir = true; - break; - case chrome::DIR_INTERNAL_PLUGINS: - if (!GetInternalPluginsDirectory(&cur)) - return false; - break; - case chrome::DIR_PEPPER_FLASH_PLUGIN: - if (!GetInternalPluginsDirectory(&cur)) - return false; - cur = cur.Append(kPepperFlashBaseDirectory); - break; - case chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(kPepperFlashBaseDirectory); - break; - case chrome::FILE_PEPPER_FLASH_SYSTEM_PLUGIN: -#if defined(OS_WIN) - if (!GetSystemFlashFilename(&cur, false)) - return false; -#elif defined(OS_MACOSX) && !defined(OS_IOS) - if (!GetLocalLibraryDirectory(&cur)) - return false; - cur = cur.Append(kPepperFlashSystemBaseDirectory); - cur = cur.Append(chrome::kPepperFlashPluginFilename); -#else - // Chrome on iOS does not supports PPAPI binaries, return false. - // TODO(wfh): If Adobe release PPAPI binaries for Linux, add support here. - return false; -#endif - break; - case chrome::FILE_FLASH_SYSTEM_PLUGIN: -#if defined(OS_WIN) - if (!GetSystemFlashFilename(&cur, true)) - return false; -#elif defined(OS_MACOSX) && !defined(OS_IOS) - if (!GetLocalLibraryDirectory(&cur)) - return false; - cur = cur.Append(kFlashSystemBaseDirectory); - cur = cur.Append(kFlashSystemPluginName); -#else - // Chrome on other platforms does not supports system NPAPI binaries. - return false; -#endif - break; - case chrome::FILE_LOCAL_STATE: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(chrome::kLocalStateFilename); - break; - case chrome::FILE_RECORDED_SCRIPT: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("script.log")); - break; - case chrome::FILE_PEPPER_FLASH_PLUGIN: - if (!PathService::Get(chrome::DIR_PEPPER_FLASH_PLUGIN, &cur)) - return false; - cur = cur.Append(chrome::kPepperFlashPluginFilename); - break; - // TODO(teravest): Remove this case once the internal NaCl plugin is gone. - // We currently need a path here to look up whether the plugin is disabled - // and what its permissions are. - case chrome::FILE_NACL_PLUGIN: - if (!GetInternalPluginsDirectory(&cur)) - return false; - cur = cur.Append(kInternalNaClPluginFileName); - break; - // PNaCl is currenly installable via the component updater or by being - // simply built-in. DIR_PNACL_BASE is used as the base directory for - // installation via component updater. DIR_PNACL_COMPONENT will be - // the final location of pnacl, which is a subdir of DIR_PNACL_BASE. - case chrome::DIR_PNACL_BASE: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("pnacl")); - break; - // Where PNaCl files are ultimately located. The default finds the files - // inside the InternalPluginsDirectory / build directory, as if it - // was shipped along with chrome. The value can be overridden - // if it is installed via component updater. - case chrome::DIR_PNACL_COMPONENT: -#if defined(OS_MACOSX) - // PNaCl really belongs in the InternalPluginsDirectory but actually - // copying it there would result in the files also being shipped, which - // we don't want yet. So for now, just find them in the directory where - // they get built. - if (!PathService::Get(base::DIR_EXE, &cur)) - return false; - if (base::mac::AmIBundled()) { - // If we're called from chrome, it's beside the app (outside the - // app bundle), if we're called from a unittest, we'll already be - // outside the bundle so use the exe dir. - // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium. - cur = cur.DirName(); - cur = cur.DirName(); - cur = cur.DirName(); - } -#else - if (!GetInternalPluginsDirectory(&cur)) - return false; -#endif - cur = cur.Append(FILE_PATH_LITERAL("pnacl")); - break; -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) -#if defined(WIDEVINE_CDM_IS_COMPONENT) - case chrome::DIR_COMPONENT_WIDEVINE_CDM: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(kWidevineCdmBaseDirectory); - break; -#endif // defined(WIDEVINE_CDM_IS_COMPONENT) - // TODO(xhwang): FILE_WIDEVINE_CDM_ADAPTER has different meanings. - // In the component case, this is the source adapter. Otherwise, it is the - // actual Pepper module that gets loaded. - case chrome::FILE_WIDEVINE_CDM_ADAPTER: - if (!GetInternalPluginsDirectory(&cur)) - return false; - cur = cur.AppendASCII(kWidevineCdmAdapterFileName); - break; -#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) - case chrome::FILE_RESOURCES_PACK: -#if defined(OS_MACOSX) && !defined(OS_IOS) - if (base::mac::AmIBundled()) { - cur = base::mac::FrameworkBundlePath(); - cur = cur.Append(FILE_PATH_LITERAL("Resources")) - .Append(FILE_PATH_LITERAL("resources.pak")); - break; - } -#elif defined(OS_ANDROID) - if (!PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &cur)) - return false; -#else - // If we're not bundled on mac or Android, resources.pak should be next - // to the binary (e.g., for unit tests). - if (!PathService::Get(base::DIR_MODULE, &cur)) - return false; -#endif - cur = cur.Append(FILE_PATH_LITERAL("resources.pak")); - break; - case chrome::DIR_RESOURCES_EXTENSION: - if (!PathService::Get(base::DIR_MODULE, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("resources")) - .Append(FILE_PATH_LITERAL("extension")); - break; -#if defined(OS_CHROMEOS) - case chrome::DIR_CHROMEOS_WALLPAPERS: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("wallpapers")); - break; - case chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("wallpaper_thumbnails")); - break; - case chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("custom_wallpapers")); - break; -#endif -#if defined(ENABLE_SUPERVISED_USERS) -#if defined(OS_LINUX) - case chrome::DIR_SUPERVISED_USERS_DEFAULT_APPS: - if (!PathService::Get(chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("managed_users")); - break; -#endif - case chrome::DIR_SUPERVISED_USER_INSTALLED_WHITELISTS: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("SupervisedUserInstalledWhitelists")); - break; -#endif - // The following are only valid in the development environment, and - // will fail if executed from an installed executable (because the - // generated path won't exist). - case chrome::DIR_GEN_TEST_DATA: -#if defined(OS_ANDROID) - // On Android, our tests don't have permission to write to DIR_MODULE. - // gtest/test_runner.py pushes data to external storage. - if (!PathService::Get(base::DIR_ANDROID_EXTERNAL_STORAGE, &cur)) - return false; -#else - if (!PathService::Get(base::DIR_MODULE, &cur)) - return false; -#endif - cur = cur.Append(FILE_PATH_LITERAL("test_data")); - if (!base::PathExists(cur)) // We don't want to create this. - return false; - break; - case chrome::DIR_TEST_DATA: - if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("chrome")); - cur = cur.Append(FILE_PATH_LITERAL("test")); - cur = cur.Append(FILE_PATH_LITERAL("data")); - if (!base::PathExists(cur)) // We don't want to create this. - return false; - break; - case chrome::DIR_TEST_TOOLS: - if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("chrome")); - cur = cur.Append(FILE_PATH_LITERAL("tools")); - cur = cur.Append(FILE_PATH_LITERAL("test")); - if (!base::PathExists(cur)) // We don't want to create this - return false; - break; -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) - case chrome::DIR_POLICY_FILES: { -#if defined(GOOGLE_CHROME_BUILD) - cur = base::FilePath(FILE_PATH_LITERAL("/etc/opt/chrome/policies")); -#else - cur = base::FilePath(FILE_PATH_LITERAL("/etc/chromium/policies")); -#endif - break; - } -#endif -#if defined(OS_MACOSX) && !defined(OS_IOS) - case chrome::DIR_USER_LIBRARY: { - if (!GetUserLibraryDirectory(&cur)) - return false; - if (!base::PathExists(cur)) // We don't want to create this. - return false; - break; - } - case chrome::DIR_USER_APPLICATIONS: { - if (!GetUserApplicationsDirectory(&cur)) - return false; - if (!base::PathExists(cur)) // We don't want to create this. - return false; - break; - } -#endif -#if defined(OS_CHROMEOS) || (defined(OS_LINUX) && defined(CHROMIUM_BUILD)) || \ - (defined(OS_MACOSX) && !defined(OS_IOS)) - case chrome::DIR_USER_EXTERNAL_EXTENSIONS: { - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("External Extensions")); - break; - } -#endif -#if defined(OS_LINUX) - case chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS: { - cur = base::FilePath(kFilepathSinglePrefExtensions); - break; - } -#endif - case chrome::DIR_EXTERNAL_EXTENSIONS: -#if defined(OS_MACOSX) && !defined(OS_IOS) - if (!chrome::GetGlobalApplicationSupportDirectory(&cur)) - return false; - - cur = cur.Append(FILE_PATH_LITERAL("Google")) - .Append(FILE_PATH_LITERAL("Chrome")) - .Append(FILE_PATH_LITERAL("External Extensions")); - create_dir = false; -#else - if (!PathService::Get(base::DIR_MODULE, &cur)) - return false; - - cur = cur.Append(FILE_PATH_LITERAL("extensions")); - create_dir = true; -#endif - break; - - case chrome::DIR_DEFAULT_APPS: -#if defined(OS_MACOSX) - cur = base::mac::FrameworkBundlePath(); - cur = cur.Append(FILE_PATH_LITERAL("Default Apps")); -#else - if (!PathService::Get(chrome::DIR_APP, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("default_apps")); -#endif - break; - -#if defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS)) - case chrome::DIR_NATIVE_MESSAGING: -#if defined(OS_MACOSX) -#if defined(GOOGLE_CHROME_BUILD) - cur = base::FilePath(FILE_PATH_LITERAL( - "/Library/Google/Chrome/NativeMessagingHosts")); -#else - cur = base::FilePath(FILE_PATH_LITERAL( - "/Library/Application Support/Chromium/NativeMessagingHosts")); -#endif -#else // defined(OS_MACOSX) -#if defined(GOOGLE_CHROME_BUILD) - cur = base::FilePath(FILE_PATH_LITERAL( - "/etc/opt/chrome/native-messaging-hosts")); -#else - cur = base::FilePath(FILE_PATH_LITERAL( - "/etc/chromium/native-messaging-hosts")); -#endif -#endif // !defined(OS_MACOSX) - break; - - case chrome::DIR_USER_NATIVE_MESSAGING: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(FILE_PATH_LITERAL("NativeMessagingHosts")); - break; -#endif // defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS)) -#if !defined(OS_ANDROID) - case chrome::DIR_GLOBAL_GCM_STORE: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.Append(kGCMStoreDirname); - break; -#endif // !defined(OS_ANDROID) -#if defined(OS_LINUX) - case chrome::FILE_COMPONENT_FLASH_HINT: - if (!PathService::Get(chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN, - &cur)) { - return false; - } - cur = cur.Append(kComponentUpdatedFlashHint); - break; -#endif // defined(OS_LINUX) - - default: - return false; - } - - // TODO(bauerb): http://crbug.com/259796 - base::ThreadRestrictions::ScopedAllowIO allow_io; - if (create_dir && !base::PathExists(cur) && - !base::CreateDirectory(cur)) - return false; - - *result = cur; - return true; -} - -// This cannot be done as a static initializer sadly since Visual Studio will -// eliminate this object file if there is no direct entry point into it. -void RegisterPathProvider() { - PathService::RegisterProvider(PathProvider, PATH_START, PATH_END); -} - -void SetInvalidSpecifiedUserDataDir(const base::FilePath& user_data_dir) { - g_invalid_specified_user_data_dir.Get() = user_data_dir; -} - -const base::FilePath& GetInvalidSpecifiedUserDataDir() { - return g_invalid_specified_user_data_dir.Get(); -} - -} // namespace chrome diff --git a/chromium_src/chrome/common/chrome_paths.h b/chromium_src/chrome/common/chrome_paths.h deleted file mode 100644 index 581fdc06f7c12..0000000000000 --- a/chromium_src/chrome/common/chrome_paths.h +++ /dev/null @@ -1,152 +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_COMMON_CHROME_PATHS_H__ -#define CHROME_COMMON_CHROME_PATHS_H__ - -#include "build/build_config.h" - -namespace base { -class FilePath; -} - -// This file declares path keys for the chrome module. These can be used with -// the PathService to access various special directories and files. - -namespace chrome { - -enum { - PATH_START = 1000, - - DIR_APP = PATH_START, // Directory where dlls and data reside. - DIR_LOGS, // Directory where logs should be written. - DIR_USER_DATA, // Directory where user data can be written. - DIR_CRASH_DUMPS, // Directory where crash dumps are written. -#if defined(OS_WIN) - DIR_WATCHER_DATA, // Directory where the Chrome watcher stores - // data. -#endif - DIR_RESOURCES, // Directory containing separate file resources - // used by Chrome at runtime. - DIR_INSPECTOR, // Directory where web inspector is located. - DIR_APP_DICTIONARIES, // Directory where the global dictionaries are. - DIR_USER_DOCUMENTS, // Directory for a user's "My Documents". - DIR_USER_MUSIC, // Directory for a user's music. - DIR_USER_PICTURES, // Directory for a user's pictures. - DIR_USER_VIDEOS, // Directory for a user's videos. - DIR_DEFAULT_DOWNLOADS_SAFE, // Directory for a user's - // "My Documents/Downloads", (Windows) or - // "Downloads". (Linux) - DIR_DEFAULT_DOWNLOADS, // Directory for a user's downloads. - DIR_INTERNAL_PLUGINS, // Directory where internal plugins reside. -#if defined(OS_POSIX) && !defined(OS_MACOSX) - DIR_POLICY_FILES, // Directory for system-wide read-only - // policy files that allow sys-admins - // to set policies for chrome. This directory - // contains subdirectories. -#endif -#if defined(OS_MACOSX) && !defined(OS_IOS) - DIR_USER_APPLICATIONS, // ~/Applications - DIR_USER_LIBRARY, // ~/Library -#endif -#if defined(OS_CHROMEOS) || (defined(OS_LINUX) && defined(CHROMIUM_BUILD)) || \ - (defined(OS_MACOSX) && !defined(OS_IOS)) - DIR_USER_EXTERNAL_EXTENSIONS, // Directory for per-user external extensions - // on Chrome Mac and Chromium Linux. - // On Chrome OS, this path is used for OEM - // customization. Getting this path does not - // create it. -#endif - -#if defined(OS_LINUX) - DIR_STANDALONE_EXTERNAL_EXTENSIONS, // Directory for 'per-extension' - // definition manifest files that - // describe extensions which are to be - // installed when chrome is run. -#endif - DIR_EXTERNAL_EXTENSIONS, // Directory where installer places .crx files. - - DIR_DEFAULT_APPS, // Directory where installer places .crx files - // to be installed when chrome is first run. - DIR_PEPPER_FLASH_PLUGIN, // Directory to the bundled Pepper Flash plugin, - // containing the plugin and the manifest. - DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN, // Base directory of the Pepper - // Flash plugins downloaded by the - // component updater. - FILE_RESOURCE_MODULE, // Full path and filename of the module that - // contains embedded resources (version, - // strings, images, etc.). - FILE_LOCAL_STATE, // Path and filename to the file in which - // machine/installation-specific state is saved. - FILE_RECORDED_SCRIPT, // Full path to the script.log file that - // contains recorded browser events for - // playback. - FILE_PEPPER_FLASH_PLUGIN, // Full path to the bundled Pepper Flash plugin - // file. - FILE_PEPPER_FLASH_SYSTEM_PLUGIN, // Full path to the system version of the - // Pepper Flash plugin, downloadable from - // Adobe website. Querying this path might - // succeed no matter the file exists or not. - FILE_FLASH_SYSTEM_PLUGIN, // Full path to the system version of NPAPI - // Flash plugin, downloadable from Adobe - // website. Querying this path might succeed no - // matter the file exists or not. - FILE_NACL_PLUGIN, // Full path to the internal NaCl plugin file. - DIR_PNACL_BASE, // Full path to the base dir for PNaCl. - DIR_PNACL_COMPONENT, // Full path to the latest PNaCl version - // (subdir of DIR_PNACL_BASE). - DIR_COMPONENT_WIDEVINE_CDM, // Directory that contains component-updated - // Widevine CDM files. - FILE_WIDEVINE_CDM_ADAPTER, // Full path to the Widevine CDM adapter file. - FILE_RESOURCES_PACK, // Full path to the .pak file containing - // binary data (e.g., html files and images - // used by internal pages). - DIR_RESOURCES_EXTENSION, // Full path to extension resources. -#if defined(OS_CHROMEOS) - DIR_CHROMEOS_WALLPAPERS, // Directory where downloaded chromeos - // wallpapers reside. - DIR_CHROMEOS_WALLPAPER_THUMBNAILS, // Directory where downloaded chromeos - // wallpaper thumbnails reside. - DIR_CHROMEOS_CUSTOM_WALLPAPERS, // Directory where custom wallpapers - // reside. -#endif - DIR_SUPERVISED_USERS_DEFAULT_APPS, // Directory where installer places .crx - // files to be installed when managed user - // session starts. - DIR_SUPERVISED_USER_INSTALLED_WHITELISTS, // Directory where sanitized - // supervised user whitelists are - // installed. -#if defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS)) - DIR_NATIVE_MESSAGING, // System directory where native messaging host - // manifest files are stored. - DIR_USER_NATIVE_MESSAGING, // Directory with Native Messaging Hosts - // installed per-user. -#endif -#if !defined(OS_ANDROID) - DIR_GLOBAL_GCM_STORE, // Directory where the global GCM instance - // stores its data. -#endif - - // Valid only in development environment; TODO(darin): move these - DIR_GEN_TEST_DATA, // Directory where generated test data resides. - DIR_TEST_DATA, // Directory where unit test data resides. - DIR_TEST_TOOLS, // Directory where unit test tools reside. -#if defined(OS_LINUX) - FILE_COMPONENT_FLASH_HINT, // A file in a known location that points to - // the component updated flash plugin. -#endif // defined(OS_LINUX) - - PATH_END -}; - -// Call once to register the provider for the path keys defined above. -void RegisterPathProvider(); - -// Get or set the invalid user data dir that was originally specified. -void SetInvalidSpecifiedUserDataDir(const base::FilePath& user_data_dir); -const base::FilePath& GetInvalidSpecifiedUserDataDir(); - -} // namespace chrome - -#endif // CHROME_COMMON_CHROME_PATHS_H__ diff --git a/chromium_src/chrome/common/chrome_paths_internal.h b/chromium_src/chrome/common/chrome_paths_internal.h deleted file mode 100644 index ae1cd623d773a..0000000000000 --- a/chromium_src/chrome/common/chrome_paths_internal.h +++ /dev/null @@ -1,112 +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_COMMON_CHROME_PATHS_INTERNAL_H_ -#define CHROME_COMMON_CHROME_PATHS_INTERNAL_H_ - -#include - -#include "build/build_config.h" - -#if defined(OS_MACOSX) -#if defined(__OBJC__) -@class NSBundle; -#else -class NSBundle; -#endif -#endif - -namespace base { -class FilePath; -} - -namespace chrome { - -// Get the path to the user's data directory, regardless of whether -// DIR_USER_DATA has been overridden by a command-line option. -bool GetDefaultUserDataDirectory(base::FilePath* result); - -// Get the path to the user's cache directory. This is normally the -// same as the profile directory, but on Linux it can also be -// $XDG_CACHE_HOME and on Mac it can be under ~/Library/Caches. -// Note that the Chrome cache directories are actually subdirectories -// of this directory, with names like "Cache" and "Media Cache". -// This will always fill in |result| with a directory, sometimes -// just |profile_dir|. -void GetUserCacheDirectory(const base::FilePath& profile_dir, base::FilePath* result); - -// Get the path to the user's documents directory. -bool GetUserDocumentsDirectory(base::FilePath* result); - -#if defined(OS_WIN) || defined(OS_LINUX) -// Gets the path to a safe default download directory for a user. -bool GetUserDownloadsDirectorySafe(base::FilePath* result); -#endif - -// Get the path to the user's downloads directory. -bool GetUserDownloadsDirectory(base::FilePath* result); - -// Gets the path to the user's music directory. -bool GetUserMusicDirectory(base::FilePath* result); - -// Gets the path to the user's pictures directory. -bool GetUserPicturesDirectory(base::FilePath* result); - -// Gets the path to the user's videos directory. -bool GetUserVideosDirectory(base::FilePath* result); - -#if defined(OS_MACOSX) && !defined(OS_IOS) -// The "versioned directory" is a directory in the browser .app bundle. It -// contains the bulk of the application, except for the things that the system -// requires be located at spepcific locations. The versioned directory is -// in the .app at Contents/Versions/w.x.y.z. -base::FilePath GetVersionedDirectory(); - -// This overrides the directory returned by |GetVersionedDirectory()|, to be -// used when |GetVersionedDirectory()| can't automatically determine the proper -// location. This is the case when the browser didn't load itself but by, e.g., -// the app mode loader. This should be called before |ChromeMain()|. This takes -// ownership of the object |path| and the caller must not delete it. -void SetOverrideVersionedDirectory(const base::FilePath* path); - -// Most of the application is further contained within the framework. The -// framework bundle is located within the versioned directory at a specific -// path. The only components in the versioned directory not included in the -// framework are things that also depend on the framework, such as the helper -// app bundle. -base::FilePath GetFrameworkBundlePath(); - -// Get the local library directory. -bool GetLocalLibraryDirectory(base::FilePath* result); - -// Get the user library directory. -bool GetUserLibraryDirectory(base::FilePath* result); - -// Get the user applications directory. -bool GetUserApplicationsDirectory(base::FilePath* result); - -// Get the global Application Support directory (under /Library/). -bool GetGlobalApplicationSupportDirectory(base::FilePath* result); - -// Returns the NSBundle for the outer browser application, even when running -// inside the helper. In unbundled applications, such as tests, returns nil. -NSBundle* OuterAppBundle(); - -// Get the user data directory for the Chrome browser bundle at |bundle|. -// |bundle| should be the same value that would be returned from +[NSBundle -// mainBundle] if Chrome were launched normaly. This is used by app shims, -// which run from a bundle which isn't Chrome itself, but which need access to -// the user data directory to connect to a UNIX-domain socket therein. -// Returns false if there was a problem fetching the app data directory. -bool GetUserDataDirectoryForBrowserBundle(NSBundle* bundle, - base::FilePath* result); - -#endif // OS_MACOSX && !OS_IOS - -// Checks if the |process_type| has the rights to access the profile. -bool ProcessNeedsProfileDir(const std::string& process_type); - -} // namespace chrome - -#endif // CHROME_COMMON_CHROME_PATHS_INTERNAL_H_ diff --git a/chromium_src/chrome/common/chrome_paths_linux.cc b/chromium_src/chrome/common/chrome_paths_linux.cc deleted file mode 100644 index 745bc03adbe15..0000000000000 --- a/chromium_src/chrome/common/chrome_paths_linux.cc +++ /dev/null @@ -1,146 +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/common/chrome_paths_internal.h" - -#include - -#include "base/base_paths.h" -#include "base/environment.h" -#include "base/files/file_util.h" -#include "base/nix/xdg_util.h" -#include "base/path_service.h" -#include "chrome/common/chrome_paths.h" - -namespace chrome { - -using base::nix::GetXDGDirectory; -using base::nix::GetXDGUserDirectory; -using base::nix::kDotConfigDir; -using base::nix::kXdgConfigHomeEnvVar; - -namespace { - -const char kDownloadsDir[] = "Downloads"; -const char kMusicDir[] = "Music"; -const char kPicturesDir[] = "Pictures"; -const char kVideosDir[] = "Videos"; - -// Generic function for GetUser{Music,Pictures,Video}Directory. -bool GetUserMediaDirectory(const std::string& xdg_name, - const std::string& fallback_name, - base::FilePath* result) { -#if defined(OS_CHROMEOS) - // No local media directories on CrOS. - return false; -#else - *result = GetXDGUserDirectory(xdg_name.c_str(), fallback_name.c_str()); - - base::FilePath home; - PathService::Get(base::DIR_HOME, &home); - if (*result != home) { - base::FilePath desktop; - if (!PathService::Get(base::DIR_USER_DESKTOP, &desktop)) - return false; - if (*result != desktop) { - return true; - } - } - - *result = home.Append(fallback_name); - return true; -#endif -} - -} // namespace - -// See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html -// for a spec on where config files go. The net effect for most -// systems is we use ~/.config/chromium/ for Chromium and -// ~/.config/google-chrome/ for official builds. -// (This also helps us sidestep issues with other apps grabbing ~/.chromium .) -bool GetDefaultUserDataDirectory(base::FilePath* result) { - std::unique_ptr env(base::Environment::Create()); - base::FilePath config_dir(GetXDGDirectory(env.get(), - kXdgConfigHomeEnvVar, - kDotConfigDir)); -#if defined(GOOGLE_CHROME_BUILD) - *result = config_dir.Append("google-chrome"); -#else - *result = config_dir.Append("chromium"); -#endif - return true; -} - -void GetUserCacheDirectory(const base::FilePath& profile_dir, - base::FilePath* result) { - // See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html - // for a spec on where cache files go. Our rule is: - // - if the user-data-dir in the standard place, - // use same subdirectory of the cache directory. - // (this maps ~/.config/google-chrome to ~/.cache/google-chrome as well - // as the same thing for ~/.config/chromium) - // - otherwise, use the profile dir directly. - - // Default value in cases where any of the following fails. - *result = profile_dir; - - std::unique_ptr env(base::Environment::Create()); - - base::FilePath cache_dir; - if (!PathService::Get(base::DIR_CACHE, &cache_dir)) - return; - base::FilePath config_dir(GetXDGDirectory(env.get(), - kXdgConfigHomeEnvVar, - kDotConfigDir)); - - if (!config_dir.AppendRelativePath(profile_dir, &cache_dir)) - return; - - *result = cache_dir; -} - -bool GetUserDocumentsDirectory(base::FilePath* result) { - *result = GetXDGUserDirectory("DOCUMENTS", "Documents"); - return true; -} - -bool GetUserDownloadsDirectorySafe(base::FilePath* result) { - base::FilePath home; - PathService::Get(base::DIR_HOME, &home); - *result = home.Append(kDownloadsDir); - return true; -} - -bool GetUserDownloadsDirectory(base::FilePath* result) { - *result = GetXDGUserDirectory("DOWNLOAD", kDownloadsDir); - return true; -} - -// We respect the user's preferred pictures location, unless it is -// ~ or their desktop directory, in which case we default to ~/Music. -bool GetUserMusicDirectory(base::FilePath* result) { - return GetUserMediaDirectory("MUSIC", kMusicDir, result); -} - -// We respect the user's preferred pictures location, unless it is -// ~ or their desktop directory, in which case we default to ~/Pictures. -bool GetUserPicturesDirectory(base::FilePath* result) { - return GetUserMediaDirectory("PICTURES", kPicturesDir, result); -} - -// We respect the user's preferred pictures location, unless it is -// ~ or their desktop directory, in which case we default to ~/Videos. -bool GetUserVideosDirectory(base::FilePath* result) { - return GetUserMediaDirectory("VIDEOS", kVideosDir, result); -} - -bool ProcessNeedsProfileDir(const std::string& process_type) { - // For now we have no reason to forbid this on Linux as we don't - // have the roaming profile troubles there. Moreover the Linux breakpad needs - // profile dir access in all process if enabled on Linux. - return true; -} - -} // namespace chrome diff --git a/chromium_src/chrome/common/chrome_paths_mac.mm b/chromium_src/chrome/common/chrome_paths_mac.mm deleted file mode 100644 index bbfd6c9b23b02..0000000000000 --- a/chromium_src/chrome/common/chrome_paths_mac.mm +++ /dev/null @@ -1,251 +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/common/chrome_paths_internal.h" - -#import -#include - -#include - -#include "base/base_paths.h" -#include "base/logging.h" -#import "base/mac/foundation_util.h" -#import "base/mac/scoped_nsautorelease_pool.h" -#include "base/memory/free_deleter.h" -#include "base/path_service.h" -#include "chrome/common/chrome_constants.h" - -namespace { - -#if !defined(OS_IOS) -const base::FilePath* g_override_versioned_directory = NULL; - -// Return a retained (NOT autoreleased) NSBundle* as the internal -// implementation of chrome::OuterAppBundle(), which should be the only -// caller. -NSBundle* OuterAppBundleInternal() { - base::mac::ScopedNSAutoreleasePool pool; - - if (!base::mac::AmIBundled()) { - // If unbundled (as in a test), there's no app bundle. - return nil; - } - - if (!base::mac::IsBackgroundOnlyProcess()) { - // Shortcut: in the browser process, just return the main app bundle. - return [[NSBundle mainBundle] retain]; - } - - // From C.app/Contents/Versions/1.2.3.4, go up three steps to get to C.app. - base::FilePath versioned_dir = chrome::GetVersionedDirectory(); - base::FilePath outer_app_dir = versioned_dir.DirName().DirName().DirName(); - const char* outer_app_dir_c = outer_app_dir.value().c_str(); - NSString* outer_app_dir_ns = [NSString stringWithUTF8String:outer_app_dir_c]; - - return [[NSBundle bundleWithPath:outer_app_dir_ns] retain]; -} -#endif // !defined(OS_IOS) - -char* ProductDirNameForBundle(NSBundle* chrome_bundle) { - const char* product_dir_name = NULL; -#if !defined(OS_IOS) - base::mac::ScopedNSAutoreleasePool pool; - - NSString* product_dir_name_ns = - [chrome_bundle objectForInfoDictionaryKey:@"CrProductDirName"]; - product_dir_name = [product_dir_name_ns fileSystemRepresentation]; -#else - DCHECK(!chrome_bundle); -#endif - - if (!product_dir_name) { -#if defined(GOOGLE_CHROME_BUILD) - product_dir_name = "Google/Chrome"; -#else - product_dir_name = "Chromium"; -#endif - } - - // Leaked, but the only caller initializes a static with this result, so it - // only happens once, and that's OK. - return strdup(product_dir_name); -} - -// ProductDirName returns the name of the directory inside -// ~/Library/Application Support that should hold the product application -// data. This can be overridden by setting the CrProductDirName key in the -// outer browser .app's Info.plist. The default is "Google/Chrome" for -// officially-branded builds, and "Chromium" for unbranded builds. For the -// official canary channel, the Info.plist will have CrProductDirName set -// to "Google/Chrome Canary". -std::string ProductDirName() { -#if defined(OS_IOS) - static const char* product_dir_name = ProductDirNameForBundle(nil); -#else - // Use OuterAppBundle() to get the main app's bundle. This key needs to live - // in the main app's bundle because it will be set differently on the canary - // channel, and the autoupdate system dictates that there can be no - // differences between channels within the versioned directory. This would - // normally use base::mac::FrameworkBundle(), but that references the - // framework bundle within the versioned directory. Ordinarily, the profile - // should not be accessed from non-browser processes, but those processes do - // attempt to get the profile directory, so direct them to look in the outer - // browser .app's Info.plist for the CrProductDirName key. - static const char* product_dir_name = - ProductDirNameForBundle(chrome::OuterAppBundle()); -#endif - return std::string(product_dir_name); -} - -bool GetDefaultUserDataDirectoryForProduct(const std::string& product_dir, - base::FilePath* result) { - bool success = false; - if (result && PathService::Get(base::DIR_APP_DATA, result)) { - *result = result->Append(product_dir); - success = true; - } - return success; -} - -} // namespace - -namespace chrome { - -bool GetDefaultUserDataDirectory(base::FilePath* result) { - return GetDefaultUserDataDirectoryForProduct(ProductDirName(), result); -} - -bool GetUserDocumentsDirectory(base::FilePath* result) { - return base::mac::GetUserDirectory(NSDocumentDirectory, result); -} - -void GetUserCacheDirectory(const base::FilePath& profile_dir, - base::FilePath* result) { - // If the profile directory is under ~/Library/Application Support, - // use a suitable cache directory under ~/Library/Caches. For - // example, a profile directory of ~/Library/Application - // Support/Google/Chrome/MyProfileName would use the cache directory - // ~/Library/Caches/Google/Chrome/MyProfileName. - - // Default value in cases where any of the following fails. - *result = profile_dir; - - base::FilePath app_data_dir; - if (!PathService::Get(base::DIR_APP_DATA, &app_data_dir)) - return; - base::FilePath cache_dir; - if (!PathService::Get(base::DIR_CACHE, &cache_dir)) - return; - if (!app_data_dir.AppendRelativePath(profile_dir, &cache_dir)) - return; - - *result = cache_dir; -} - -bool GetUserDownloadsDirectory(base::FilePath* result) { - return base::mac::GetUserDirectory(NSDownloadsDirectory, result); -} - -bool GetUserMusicDirectory(base::FilePath* result) { - return base::mac::GetUserDirectory(NSMusicDirectory, result); -} - -bool GetUserPicturesDirectory(base::FilePath* result) { - return base::mac::GetUserDirectory(NSPicturesDirectory, result); -} - -bool GetUserVideosDirectory(base::FilePath* result) { - return base::mac::GetUserDirectory(NSMoviesDirectory, result); -} - -#if !defined(OS_IOS) - -base::FilePath GetVersionedDirectory() { - if (g_override_versioned_directory) - return *g_override_versioned_directory; - - // Start out with the path to the running executable. - base::FilePath path; - PathService::Get(base::FILE_EXE, &path); - - // One step up to MacOS, another to Contents. - path = path.DirName().DirName(); - DCHECK_EQ(path.BaseName().value(), "Contents"); - - if (base::mac::IsBackgroundOnlyProcess()) { - // path identifies the helper .app's Contents directory in the browser - // .app's versioned directory. Go up two steps to get to the browser - // .app's versioned directory. - path = path.DirName().DirName(); - } else { - // Go into the versioned directory. - path = path.Append("Frameworks"); - } - - return path; -} - -void SetOverrideVersionedDirectory(const base::FilePath* path) { - if (path != g_override_versioned_directory) { - delete g_override_versioned_directory; - g_override_versioned_directory = path; - } -} - -base::FilePath GetFrameworkBundlePath() { - // It's tempting to use +[NSBundle bundleWithIdentifier:], but it's really - // slow (about 30ms on 10.5 and 10.6), despite Apple's documentation stating - // that it may be more efficient than +bundleForClass:. +bundleForClass: - // itself takes 1-2ms. Getting an NSBundle from a path, on the other hand, - // essentially takes no time at all, at least when the bundle has already - // been loaded as it will have been in this case. The FilePath operations - // needed to compute the framework's path are also effectively free, so that - // is the approach that is used here. NSBundle is also documented as being - // not thread-safe, and thread safety may be a concern here. - - // The framework bundle is at a known path and name from the browser .app's - // versioned directory. - return GetVersionedDirectory().Append(kFrameworkName); -} - -bool GetLocalLibraryDirectory(base::FilePath* result) { - return base::mac::GetLocalDirectory(NSLibraryDirectory, result); -} - -bool GetUserLibraryDirectory(base::FilePath* result) { - return base::mac::GetUserDirectory(NSLibraryDirectory, result); -} - -bool GetUserApplicationsDirectory(base::FilePath* result) { - return base::mac::GetUserDirectory(NSApplicationDirectory, result); -} - -bool GetGlobalApplicationSupportDirectory(base::FilePath* result) { - return base::mac::GetLocalDirectory(NSApplicationSupportDirectory, result); -} - -NSBundle* OuterAppBundle() { - // Cache this. Foundation leaks it anyway, and this should be the only call - // to OuterAppBundleInternal(). - static NSBundle* bundle = OuterAppBundleInternal(); - return bundle; -} - -bool GetUserDataDirectoryForBrowserBundle(NSBundle* bundle, - base::FilePath* result) { - std::unique_ptr - product_dir_name(ProductDirNameForBundle(bundle)); - return GetDefaultUserDataDirectoryForProduct(product_dir_name.get(), result); -} - -#endif // !defined(OS_IOS) - -bool ProcessNeedsProfileDir(const std::string& process_type) { - // For now we have no reason to forbid this on other MacOS as we don't - // have the roaming profile troubles there. - return true; -} - -} // namespace chrome diff --git a/chromium_src/chrome/common/chrome_paths_win.cc b/chromium_src/chrome/common/chrome_paths_win.cc deleted file mode 100644 index 89c2ae48eaa2e..0000000000000 --- a/chromium_src/chrome/common/chrome_paths_win.cc +++ /dev/null @@ -1,106 +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/common/chrome_paths_internal.h" - -#include -#include -#include -#include -#include - -#include "base/files/file_path.h" -#include "base/path_service.h" -#include "base/win/scoped_co_mem.h" -#include "chrome/common/chrome_constants.h" - -namespace chrome { - -namespace { - -// Generic function to call SHGetFolderPath(). -bool GetUserDirectory(int csidl_folder, base::FilePath* result) { - // We need to go compute the value. It would be nice to support paths - // with names longer than MAX_PATH, but the system functions don't seem - // to be designed for it either, with the exception of GetTempPath - // (but other things will surely break if the temp path is too long, - // so we don't bother handling it. - wchar_t path_buf[MAX_PATH]; - path_buf[0] = 0; - if (FAILED(SHGetFolderPath(NULL, csidl_folder, NULL, - SHGFP_TYPE_CURRENT, path_buf))) { - return false; - } - *result = base::FilePath(path_buf); - return true; -} - -} // namespace - -bool GetDefaultUserDataDirectory(base::FilePath* result) { - return PathService::Get(base::DIR_LOCAL_APP_DATA, result); -} - -void GetUserCacheDirectory(const base::FilePath& profile_dir, - base::FilePath* result) { - // This function does more complicated things on Mac/Linux. - *result = profile_dir; -} - -bool GetUserDocumentsDirectory(base::FilePath* result) { - return GetUserDirectory(CSIDL_MYDOCUMENTS, result); -} - -// Return a default path for downloads that is safe. -// We just use 'Downloads' under DIR_USER_DOCUMENTS. Localizing -// 'downloads' is not a good idea because Chrome's UI language -// can be changed. -bool GetUserDownloadsDirectorySafe(base::FilePath* result) { - if (!GetUserDocumentsDirectory(result)) - return false; - - *result = result->Append(L"Downloads"); - return true; -} - -// On Vista and higher, use the downloads known folder. Since it can be -// relocated to point to a "dangerous" folder, callers should validate that the -// returned path is not dangerous before using it. -bool GetUserDownloadsDirectory(base::FilePath* result) { - typedef HRESULT (WINAPI *GetKnownFolderPath)( - REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR*); - GetKnownFolderPath f = reinterpret_cast( - GetProcAddress(GetModuleHandle(L"shell32.dll"), "SHGetKnownFolderPath")); - base::win::ScopedCoMem path_buf; - if (f && SUCCEEDED(f(FOLDERID_Downloads, 0, NULL, &path_buf))) { - *result = base::FilePath(std::wstring(path_buf)); - return true; - } - return GetUserDownloadsDirectorySafe(result); -} - -bool GetUserMusicDirectory(base::FilePath* result) { - return GetUserDirectory(CSIDL_MYMUSIC, result); -} - -bool GetUserPicturesDirectory(base::FilePath* result) { - return GetUserDirectory(CSIDL_MYPICTURES, result); -} - -bool GetUserVideosDirectory(base::FilePath* result) { - return GetUserDirectory(CSIDL_MYVIDEO, result); -} - -bool ProcessNeedsProfileDir(const std::string& process_type) { - // On windows we don't want subprocesses other than the browser process and - // service processes to be able to use the profile directory because if it - // lies on a network share the sandbox will prevent us from accessing it. - - if (process_type.empty()) - return true; - - return false; -} - -} // namespace chrome diff --git a/chromium_src/chrome/common/chrome_utility_messages.h b/chromium_src/chrome/common/chrome_utility_messages.h deleted file mode 100644 index f146e1823e81c..0000000000000 --- a/chromium_src/chrome/common/chrome_utility_messages.h +++ /dev/null @@ -1,169 +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. - -// Multiply-included message file, so no include guard. - -#if defined(OS_WIN) -#include -#endif // defined(OS_WIN) - -#include -#include - -#include "base/files/file_path.h" -#include "base/strings/string16.h" -#include "base/tuple.h" -#include "base/values.h" -#include "ipc/ipc_message_macros.h" -#include "ipc/ipc_platform_file.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/ipc/gfx_param_traits.h" - -// Singly-included section for typedefs. -#ifndef CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ -#define CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ - -#if defined(OS_WIN) -// A vector of filters, each being a Tuple containing a display string (i.e. -// "Text Files") and a filter pattern (i.e. "*.txt"). -typedef std::vector> - GetOpenFileNameFilter; -#endif // OS_WIN - -#endif // CHROME_COMMON_CHROME_UTILITY_MESSAGES_H_ - -#define IPC_MESSAGE_START ChromeUtilityMsgStart - - -#if defined(OS_WIN) -IPC_STRUCT_BEGIN(ChromeUtilityMsg_GetSaveFileName_Params) - IPC_STRUCT_MEMBER(HWND, owner) - IPC_STRUCT_MEMBER(DWORD, flags) - IPC_STRUCT_MEMBER(GetOpenFileNameFilter, filters) - IPC_STRUCT_MEMBER(int, one_based_filter_index) - IPC_STRUCT_MEMBER(base::FilePath, suggested_filename) - IPC_STRUCT_MEMBER(base::FilePath, initial_directory) - IPC_STRUCT_MEMBER(base::string16, default_extension) -IPC_STRUCT_END() -#endif // OS_WIN - -//------------------------------------------------------------------------------ -// Utility process messages: -// These are messages from the browser to the utility process. - -// Tell the utility process to parse a JSON string into a Value object. -IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_ParseJSON, - std::string /* JSON to parse */) - -// Tell the utility process to decode the given image data. -IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_DecodeImage, - std::vector /* encoded image contents */, - bool /* shrink image if needed for IPC msg limit */) - -// Tell the utility process to decode the given JPEG image data with a robust -// libjpeg codec. -IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_RobustJPEGDecodeImage, - std::vector) // encoded image contents - -// Tell the utility process to patch the given |input_file| using |patch_file| -// and place the output in |output_file|. The patch should use the bsdiff -// algorithm (Courgette's version). -IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileBsdiff, - base::FilePath /* input_file */, - base::FilePath /* patch_file */, - base::FilePath /* output_file */) - -// Tell the utility process to patch the given |input_file| using |patch_file| -// and place the output in |output_file|. The patch should use the Courgette -// algorithm. -IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileCourgette, - base::FilePath /* input_file */, - base::FilePath /* patch_file */, - base::FilePath /* output_file */) - - -// Requests the utility process to respond with a -// ChromeUtilityHostMsg_ProcessStarted message once it has started. This may -// be used if the host process needs a handle to the running utility process. -IPC_MESSAGE_CONTROL0(ChromeUtilityMsg_StartupPing) - - -#if defined(OS_WIN) -// Invokes ui::base::win::OpenFileViaShell from the utility process. -IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_OpenFileViaShell, - base::FilePath /* full_path */) - -// Invokes ui::base::win::OpenFolderViaShell from the utility process. -IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_OpenFolderViaShell, - base::FilePath /* full_path */) - -// Instructs the utility process to invoke GetOpenFileName. |owner| is the -// parent of the modal dialog, |flags| are OFN_* flags. |filter| constrains the -// user's file choices. |initial_directory| and |filename| select the directory -// to be displayed and the file to be initially selected. -// -// Either ChromeUtilityHostMsg_GetOpenFileName_Failed or -// ChromeUtilityHostMsg_GetOpenFileName_Result will be returned when the -// operation completes whether due to error or user action. -IPC_MESSAGE_CONTROL5(ChromeUtilityMsg_GetOpenFileName, - HWND /* owner */, - DWORD /* flags */, - GetOpenFileNameFilter /* filter */, - base::FilePath /* initial_directory */, - base::FilePath /* filename */) -IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_GetSaveFileName, - ChromeUtilityMsg_GetSaveFileName_Params /* params */) -#endif // defined(OS_WIN) - - -//------------------------------------------------------------------------------ -// Utility process host messages: -// These are messages from the utility process to the browser. - -// Reply when the utility process successfully parsed a JSON string. -// -// WARNING: The result can be of any Value subclass type, but we can't easily -// pass indeterminate value types by const object reference with our IPC macros, -// so we put the result Value into a ListValue. Handlers should examine the -// first (and only) element of the ListValue for the actual result. -IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_ParseJSON_Succeeded, - base::ListValue) - -// Reply when the utility process failed in parsing a JSON string. -IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_ParseJSON_Failed, - std::string /* error message, if any*/) - -// Reply when the utility process has failed while unpacking and parsing a -// web resource. |error_message| is a user-readable explanation of what -// went wrong. -IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_UnpackWebResource_Failed, - std::string /* error_message, if any */) - -// Reply when the utility process has succeeded in decoding the image. -IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_DecodeImage_Succeeded, - SkBitmap) // decoded image - -// Reply when an error occurred decoding the image. -IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_DecodeImage_Failed) - -// Reply when a file has been patched. -IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_PatchFile_Finished, int /* result */) - - -// Reply when the utility process has started. -IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_ProcessStarted) - - -#if defined(OS_WIN) -IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_GetOpenFileName_Failed) -IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetOpenFileName_Result, - base::FilePath /* directory */, - std::vector /* filenames */) -IPC_MESSAGE_CONTROL0(ChromeUtilityHostMsg_GetSaveFileName_Failed) -IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetSaveFileName_Result, - base::FilePath /* path */, - int /* one_based_filter_index */) -IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_BuildDirectWriteFontCache, - base::FilePath /* cache file path */) -#endif // defined(OS_WIN) diff --git a/chromium_src/chrome/common/pref_names.cc b/chromium_src/chrome/common/pref_names.cc deleted file mode 100644 index 23235cd1f4b0c..0000000000000 --- a/chromium_src/chrome/common/pref_names.cc +++ /dev/null @@ -1,13 +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/common/pref_names.h" - -namespace prefs { - -const char kSelectFileLastDirectory[] = "selectfile.last_directory"; -const char kDownloadDefaultDirectory[] = "download.default_directory"; -const char kDevToolsFileSystemPaths[] = "devtools.file_system_paths"; - -} // namespace prefs diff --git a/chromium_src/chrome/common/pref_names.h b/chromium_src/chrome/common/pref_names.h deleted file mode 100644 index 5101c720133d7..0000000000000 --- a/chromium_src/chrome/common/pref_names.h +++ /dev/null @@ -1,13 +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. - -// Constants for the names of various preferences, for easier changing. - -namespace prefs { - -extern const char kSelectFileLastDirectory[]; -extern const char kDownloadDefaultDirectory[]; -extern const char kDevToolsFileSystemPaths[]; - -} // namespace prefs diff --git a/chromium_src/chrome/common/print_messages.cc b/chromium_src/chrome/common/print_messages.cc deleted file mode 100644 index b0ec282382d67..0000000000000 --- a/chromium_src/chrome/common/print_messages.cc +++ /dev/null @@ -1,59 +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/common/print_messages.h" - -#include "base/strings/string16.h" -#include "ui/gfx/geometry/size.h" - -PrintMsg_Print_Params::PrintMsg_Print_Params() - : page_size(), - content_size(), - printable_area(), - margin_top(0), - margin_left(0), - dpi(0), - min_shrink(0), - max_shrink(0), - desired_dpi(0), - document_cookie(0), - selection_only(false), - supports_alpha_blend(false), - print_scaling_option(blink::WebPrintScalingOptionSourceSize), - title(), - url(), - should_print_backgrounds(false) { -} - -PrintMsg_Print_Params::~PrintMsg_Print_Params() {} - -void PrintMsg_Print_Params::Reset() { - page_size = gfx::Size(); - content_size = gfx::Size(); - printable_area = gfx::Rect(); - margin_top = 0; - margin_left = 0; - dpi = 0; - min_shrink = 0; - max_shrink = 0; - desired_dpi = 0; - document_cookie = 0; - selection_only = false; - supports_alpha_blend = false; - print_scaling_option = blink::WebPrintScalingOptionSourceSize; - title.clear(); - url.clear(); - should_print_backgrounds = false; -} - -PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params() - : pages() { -} - -PrintMsg_PrintPages_Params::~PrintMsg_PrintPages_Params() {} - -void PrintMsg_PrintPages_Params::Reset() { - params.Reset(); - pages = std::vector(); -} diff --git a/chromium_src/chrome/common/print_messages.h b/chromium_src/chrome/common/print_messages.h deleted file mode 100644 index 034691b5b9584..0000000000000 --- a/chromium_src/chrome/common/print_messages.h +++ /dev/null @@ -1,322 +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. - -// IPC messages for printing. -// Multiply-included message file, hence no include guard. - -#include -#include - -#include "base/memory/shared_memory.h" -#include "base/values.h" -#include "ipc/ipc_message_macros.h" -#include "printing/page_size_margins.h" -#include "printing/print_job_constants.h" -#include "third_party/WebKit/public/web/WebPrintScalingOption.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/geometry/rect.h" - -#if defined(OS_WIN) -#include "ipc/ipc_platform_file.h" -#include "printing/backend/print_backend.h" -#include "printing/page_range.h" -#include "printing/pdf_render_settings.h" -#endif - -#ifndef CHROME_COMMON_PRINT_MESSAGES_H_ -#define CHROME_COMMON_PRINT_MESSAGES_H_ - -struct PrintMsg_Print_Params { - PrintMsg_Print_Params(); - ~PrintMsg_Print_Params(); - - // Resets the members of the struct to 0. - void Reset(); - - gfx::Size page_size; - gfx::Size content_size; - gfx::Rect printable_area; - int margin_top; - int margin_left; - double dpi; - double min_shrink; - double max_shrink; - int desired_dpi; - int document_cookie; - bool selection_only; - bool supports_alpha_blend; - int preview_request_id; - blink::WebPrintScalingOption print_scaling_option; - bool print_to_pdf; - base::string16 title; - base::string16 url; - bool should_print_backgrounds; -}; - -struct PrintMsg_PrintPages_Params { - PrintMsg_PrintPages_Params(); - ~PrintMsg_PrintPages_Params(); - - // Resets the members of the struct to 0. - void Reset(); - - PrintMsg_Print_Params params; - std::vector pages; -}; - -#endif // CHROME_COMMON_PRINT_MESSAGES_H_ - -#define IPC_MESSAGE_START PrintMsgStart - -IPC_ENUM_TRAITS_MAX_VALUE(printing::MarginType, - printing::MARGIN_TYPE_LAST) -IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPrintScalingOption, - blink::WebPrintScalingOptionLast) - -// Parameters for a render request. -IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params) - // Physical size of the page, including non-printable margins, - // in pixels according to dpi. - IPC_STRUCT_TRAITS_MEMBER(page_size) - - // In pixels according to dpi_x and dpi_y. - IPC_STRUCT_TRAITS_MEMBER(content_size) - - // Physical printable area of the page in pixels according to dpi. - IPC_STRUCT_TRAITS_MEMBER(printable_area) - - // The y-offset of the printable area, in pixels according to dpi. - IPC_STRUCT_TRAITS_MEMBER(margin_top) - - // The x-offset of the printable area, in pixels according to dpi. - IPC_STRUCT_TRAITS_MEMBER(margin_left) - - // Specifies dots per inch. - IPC_STRUCT_TRAITS_MEMBER(dpi) - - // Minimum shrink factor. See PrintSettings::min_shrink for more information. - IPC_STRUCT_TRAITS_MEMBER(min_shrink) - - // Maximum shrink factor. See PrintSettings::max_shrink for more information. - IPC_STRUCT_TRAITS_MEMBER(max_shrink) - - // Desired apparent dpi on paper. - IPC_STRUCT_TRAITS_MEMBER(desired_dpi) - - // Cookie for the document to ensure correctness. - IPC_STRUCT_TRAITS_MEMBER(document_cookie) - - // Should only print currently selected text. - IPC_STRUCT_TRAITS_MEMBER(selection_only) - - // Does the printer support alpha blending? - IPC_STRUCT_TRAITS_MEMBER(supports_alpha_blend) - - // Specifies the page scaling option for preview printing. - IPC_STRUCT_TRAITS_MEMBER(print_scaling_option) - - // Title string to be printed as header if requested by the user. - IPC_STRUCT_TRAITS_MEMBER(title) - - // URL string to be printed as footer if requested by the user. - IPC_STRUCT_TRAITS_MEMBER(url) - - // True if print backgrounds is requested by the user. - IPC_STRUCT_TRAITS_MEMBER(should_print_backgrounds) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_BEGIN(PrintMsg_PrintPage_Params) - // Parameters to render the page as a printed page. It must always be the same - // value for all the document. - IPC_STRUCT_MEMBER(PrintMsg_Print_Params, params) - - // The page number is the indicator of the square that should be rendered - // according to the layout specified in PrintMsg_Print_Params. - IPC_STRUCT_MEMBER(int, page_number) -IPC_STRUCT_END() - -IPC_STRUCT_TRAITS_BEGIN(printing::PageSizeMargins) - IPC_STRUCT_TRAITS_MEMBER(content_width) - IPC_STRUCT_TRAITS_MEMBER(content_height) - IPC_STRUCT_TRAITS_MEMBER(margin_left) - IPC_STRUCT_TRAITS_MEMBER(margin_right) - IPC_STRUCT_TRAITS_MEMBER(margin_top) - IPC_STRUCT_TRAITS_MEMBER(margin_bottom) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(PrintMsg_PrintPages_Params) - // Parameters to render the page as a printed page. It must always be the same - // value for all the document. - IPC_STRUCT_TRAITS_MEMBER(params) - - // If empty, this means a request to render all the printed pages. - IPC_STRUCT_TRAITS_MEMBER(pages) -IPC_STRUCT_TRAITS_END() - -// Parameters to describe a rendered page. -IPC_STRUCT_BEGIN(PrintHostMsg_DidPrintPage_Params) - // A shared memory handle to the EMF data. This data can be quite large so a - // memory map needs to be used. - IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle) - - // Size of the metafile data. - IPC_STRUCT_MEMBER(uint32_t, data_size) - - // Cookie for the document to ensure correctness. - IPC_STRUCT_MEMBER(int, document_cookie) - - // Page number. - IPC_STRUCT_MEMBER(int, page_number) - - // Shrink factor used to render this page. - IPC_STRUCT_MEMBER(double, actual_shrink) - - // The size of the page the page author specified. - IPC_STRUCT_MEMBER(gfx::Size, page_size) - - // The printable area the page author specified. - IPC_STRUCT_MEMBER(gfx::Rect, content_area) -IPC_STRUCT_END() - -// Parameters for the IPC message ViewHostMsg_ScriptedPrint -IPC_STRUCT_BEGIN(PrintHostMsg_ScriptedPrint_Params) - IPC_STRUCT_MEMBER(int, cookie) - IPC_STRUCT_MEMBER(int, expected_pages_count) - IPC_STRUCT_MEMBER(bool, has_selection) - IPC_STRUCT_MEMBER(printing::MarginType, margin_type) -IPC_STRUCT_END() - -// Parameters to describe a rendered document. -IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewDocument_Params) - // A shared memory handle to metafile data. - IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle) - - // Size of metafile data. - IPC_STRUCT_MEMBER(uint32_t, data_size) - - // Cookie for the document to ensure correctness. - IPC_STRUCT_MEMBER(int, document_cookie) - - // Store the expected pages count. - IPC_STRUCT_MEMBER(int, expected_pages_count) - - // Whether the preview can be modified. - IPC_STRUCT_MEMBER(bool, modifiable) - - // The id of the preview request. - IPC_STRUCT_MEMBER(int, preview_request_id) -IPC_STRUCT_END() - - -// Messages sent from the browser to the renderer. - -// Tells the render view to switch the CSS to print media type, renders every -// requested pages and switch back the CSS to display media type. -IPC_MESSAGE_ROUTED2(PrintMsg_PrintPages, - bool /* silent print */, - bool /* print page's background */) - -// Tells the render view that printing is done so it can clean up. -IPC_MESSAGE_ROUTED1(PrintMsg_PrintingDone, - bool /* success */) - -// Tells the render view to switch the CSS to print media type, renders every -// requested pages for print preview using the given |settings|. This gets -// called multiple times as the user updates settings. -IPC_MESSAGE_ROUTED1(PrintMsg_PrintPreview, - base::DictionaryValue /* settings */) - -// Messages sent from the renderer to the browser. - -#if defined(OS_WIN) -// Duplicates a shared memory handle from the renderer to the browser. Then -// the renderer can flush the handle. -IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_DuplicateSection, - base::SharedMemoryHandle /* renderer handle */, - base::SharedMemoryHandle /* browser handle */) -#endif - -// Tells the browser that the renderer is done calculating the number of -// rendered pages according to the specified settings. -IPC_MESSAGE_ROUTED2(PrintHostMsg_DidGetPrintedPagesCount, - int /* rendered document cookie */, - int /* number of rendered pages */) - -// Sends the document cookie of the current printer query to the browser. -IPC_MESSAGE_ROUTED1(PrintHostMsg_DidGetDocumentCookie, - int /* rendered document cookie */) - -// Tells the browser that the print dialog has been shown. -IPC_MESSAGE_ROUTED0(PrintHostMsg_DidShowPrintDialog) - -// Sends back to the browser the rendered "printed page" that was requested by -// a ViewMsg_PrintPage message or from scripted printing. The memory handle in -// this message is already valid in the browser process. -IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPrintPage, - PrintHostMsg_DidPrintPage_Params /* page content */) - -// The renderer wants to know the default print settings. -IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_GetDefaultPrintSettings, - PrintMsg_Print_Params /* default_settings */) - -// The renderer wants to update the current print settings with new -// |job_settings|. -IPC_SYNC_MESSAGE_ROUTED2_2(PrintHostMsg_UpdatePrintSettings, - int /* document_cookie */, - base::DictionaryValue /* job_settings */, - PrintMsg_PrintPages_Params /* current_settings */, - bool /* canceled */) - -// It's the renderer that controls the printing process when it is generated -// by javascript. This step is about showing UI to the user to select the -// final print settings. The output parameter is the same as -// ViewMsg_PrintPages which is executed implicitly. -IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_ScriptedPrint, - PrintHostMsg_ScriptedPrint_Params, - PrintMsg_PrintPages_Params - /* settings chosen by the user*/) - -// This is sent when there are invalid printer settings. -IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError) - -// Tell the browser printing failed. -IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintingFailed, - int /* document cookie */) - -// Sends back to the browser the complete rendered document (non-draft mode, -// used for printing) that was requested by a PrintMsg_PrintPreview message. -// The memory handle in this message is already valid in the browser process. -IPC_MESSAGE_ROUTED1(PrintHostMsg_MetafileReadyForPrinting, - PrintHostMsg_DidPreviewDocument_Params /* params */) - -IPC_MESSAGE_ROUTED2(PrintHostMsg_PrintPreviewFailed, - int /* document cookie */, - int /* request_id */); - -#if defined(OS_WIN) -// Tell the utility process to start rendering the given PDF into a metafile. -// Utility process would be alive until -// ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop message. -IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles, - IPC::PlatformFileForTransit, /* input_file */ - printing::PdfRenderSettings /* settings */) - -// Requests conversion of the next page. -IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage, - int /* page_number */, - IPC::PlatformFileForTransit /* output_file */) - -// Requests utility process to stop conversion and exit. -IPC_MESSAGE_CONTROL0(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop) - -// Reply when the utility process loaded PDF. |page_count| is 0, if loading -// failed. -IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, - int /* page_count */) - -// Reply when the utility process rendered the PDF page. -IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, - bool /* success */, - float /* scale_factor */) -#endif diff --git a/chromium_src/chrome/common/tts_messages.h b/chromium_src/chrome/common/tts_messages.h deleted file mode 100644 index 2132d80a0775a..0000000000000 --- a/chromium_src/chrome/common/tts_messages.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 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. - -// Multiply-included message file, hence no include guard. - -#include - -#include "chrome/common/tts_utterance_request.h" -#include "ipc/ipc_message_macros.h" -#include "ipc/ipc_param_traits.h" - -#define IPC_MESSAGE_START TtsMsgStart - -IPC_STRUCT_TRAITS_BEGIN(TtsUtteranceRequest) -IPC_STRUCT_TRAITS_MEMBER(id) -IPC_STRUCT_TRAITS_MEMBER(text) -IPC_STRUCT_TRAITS_MEMBER(lang) -IPC_STRUCT_TRAITS_MEMBER(voice) -IPC_STRUCT_TRAITS_MEMBER(volume) -IPC_STRUCT_TRAITS_MEMBER(rate) -IPC_STRUCT_TRAITS_MEMBER(pitch) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(TtsVoice) -IPC_STRUCT_TRAITS_MEMBER(voice_uri) -IPC_STRUCT_TRAITS_MEMBER(name) -IPC_STRUCT_TRAITS_MEMBER(lang) -IPC_STRUCT_TRAITS_MEMBER(local_service) -IPC_STRUCT_TRAITS_MEMBER(is_default) -IPC_STRUCT_TRAITS_END() - -// Renderer -> Browser messages. - -IPC_MESSAGE_CONTROL0(TtsHostMsg_InitializeVoiceList) -IPC_MESSAGE_CONTROL1(TtsHostMsg_Speak, - TtsUtteranceRequest) -IPC_MESSAGE_CONTROL0(TtsHostMsg_Pause) -IPC_MESSAGE_CONTROL0(TtsHostMsg_Resume) -IPC_MESSAGE_CONTROL0(TtsHostMsg_Cancel) - -// Browser -> Renderer messages. - -IPC_MESSAGE_CONTROL1(TtsMsg_SetVoiceList, - std::vector) -IPC_MESSAGE_CONTROL1(TtsMsg_DidStartSpeaking, - int /* utterance id */) -IPC_MESSAGE_CONTROL1(TtsMsg_DidFinishSpeaking, - int /* utterance id */) -IPC_MESSAGE_CONTROL1(TtsMsg_DidPauseSpeaking, - int /* utterance id */) -IPC_MESSAGE_CONTROL1(TtsMsg_DidResumeSpeaking, - int /* utterance id */) -IPC_MESSAGE_CONTROL2(TtsMsg_WordBoundary, - int /* utterance id */, - int /* char index */) -IPC_MESSAGE_CONTROL2(TtsMsg_SentenceBoundary, - int /* utterance id */, - int /* char index */) -IPC_MESSAGE_CONTROL2(TtsMsg_MarkerEvent, - int /* utterance id */, - int /* char index */) -IPC_MESSAGE_CONTROL1(TtsMsg_WasInterrupted, - int /* utterance id */) -IPC_MESSAGE_CONTROL1(TtsMsg_WasCancelled, - int /* utterance id */) -IPC_MESSAGE_CONTROL2(TtsMsg_SpeakingErrorOccurred, - int /* utterance id */, - std::string /* error message */) \ No newline at end of file diff --git a/chromium_src/chrome/common/tts_utterance_request.cc b/chromium_src/chrome/common/tts_utterance_request.cc deleted file mode 100644 index a2e3e7fcea433..0000000000000 --- a/chromium_src/chrome/common/tts_utterance_request.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 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. - -#include "chrome/common/tts_utterance_request.h" - -TtsUtteranceRequest::TtsUtteranceRequest() - : id(0), - volume(1.0), - rate(1.0), - pitch(1.0) { -} - -TtsUtteranceRequest::~TtsUtteranceRequest() { -} - -TtsVoice::TtsVoice() - : local_service(true), - is_default(false) { -} - -TtsVoice::~TtsVoice() { -} - -TtsUtteranceResponse::TtsUtteranceResponse() - : id(0) { -} - -TtsUtteranceResponse::~TtsUtteranceResponse() { -} \ No newline at end of file diff --git a/chromium_src/chrome/common/tts_utterance_request.h b/chromium_src/chrome/common/tts_utterance_request.h deleted file mode 100644 index a4b4cab68ca36..0000000000000 --- a/chromium_src/chrome/common/tts_utterance_request.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) 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_COMMON_TTS_UTTERANCE_REQUEST_H_ -#define CHROME_COMMON_TTS_UTTERANCE_REQUEST_H_ - -#include - -#include "base/macros.h" -#include "base/strings/string16.h" - -struct TtsUtteranceRequest { - TtsUtteranceRequest(); - ~TtsUtteranceRequest(); - - int id; - std::string text; - std::string lang; - std::string voice; - float volume; - float rate; - float pitch; -}; - -struct TtsVoice { - TtsVoice(); - ~TtsVoice(); - - std::string voice_uri; - std::string name; - std::string lang; - bool local_service; - bool is_default; -}; - -struct TtsUtteranceResponse { - TtsUtteranceResponse(); - ~TtsUtteranceResponse(); - - int id; -}; - -#endif // CHROME_COMMON_TTS_UTTERANCE_REQUEST_H_ diff --git a/chromium_src/chrome/common/widevine_cdm_constants.cc b/chromium_src/chrome/common/widevine_cdm_constants.cc deleted file mode 100644 index 587966a9c3681..0000000000000 --- a/chromium_src/chrome/common/widevine_cdm_constants.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 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. - -#include "chrome/common/widevine_cdm_constants.h" - -#include "build/build_config.h" -#include "ppapi/shared_impl/ppapi_permissions.h" - -const base::FilePath::CharType kWidevineCdmBaseDirectory[] = - FILE_PATH_LITERAL("WidevineCDM"); - -const char kWidevineCdmPluginExtension[] = ""; - -const int32_t kWidevineCdmPluginPermissions = ppapi::PERMISSION_DEV | - ppapi::PERMISSION_PRIVATE; diff --git a/chromium_src/chrome/common/widevine_cdm_constants.h b/chromium_src/chrome/common/widevine_cdm_constants.h deleted file mode 100644 index 9597b1cb41fe0..0000000000000 --- a/chromium_src/chrome/common/widevine_cdm_constants.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 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_COMMON_WIDEVINE_CDM_CONSTANTS_H_ -#define CHROME_COMMON_WIDEVINE_CDM_CONSTANTS_H_ - -#include "base/macros.h" -#include "base/files/file_path.h" - -// The Widevine CDM adapter and Widevine CDM are in this directory. -extern const base::FilePath::CharType kWidevineCdmBaseDirectory[]; - -extern const char kWidevineCdmPluginExtension[]; - -// Permission bits for Widevine CDM plugin. -extern const int32_t kWidevineCdmPluginPermissions; - -#endif // CHROME_COMMON_WIDEVINE_CDM_CONSTANTS_H_ diff --git a/chromium_src/chrome/common/widevine_cdm_messages.h b/chromium_src/chrome/common/widevine_cdm_messages.h deleted file mode 100644 index 17c908776b26e..0000000000000 --- a/chromium_src/chrome/common/widevine_cdm_messages.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 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. - -// Multiply-included message file, hence no include guard. - -#include - -#include "ipc/ipc_message_macros.h" -// #include "ipc/ipc_param_traits.h" - -#define IPC_MESSAGE_START ChromeMsgStart - -// Renderer -> Browser messages. - -#if defined(ENABLE_PEPPER_CDMS) -// Returns whether any internal plugin supporting |mime_type| is registered and -// enabled. Does not determine whether the plugin can actually be instantiated -// (e.g. whether it has all its dependencies). -// When the returned *|is_available| is true, |additional_param_names| and -// |additional_param_values| contain the name-value pairs, if any, specified -// for the *first* non-disabled plugin found that is registered for |mime_type|. -IPC_SYNC_MESSAGE_CONTROL1_3( - ChromeViewHostMsg_IsInternalPluginAvailableForMimeType, - std::string /* mime_type */, - bool /* is_available */, - std::vector /* additional_param_names */, - std::vector /* additional_param_values */) -#endif - -// Browser -> Renderer messages. diff --git a/chromium_src/chrome/renderer/media/chrome_key_systems.cc b/chromium_src/chrome/renderer/media/chrome_key_systems.cc deleted file mode 100644 index 79e1333a74697..0000000000000 --- a/chromium_src/chrome/renderer/media/chrome_key_systems.cc +++ /dev/null @@ -1,277 +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. - -#include "chrome/renderer/media/chrome_key_systems.h" - -#include - -#include -#include - -#include "base/logging.h" -#include "base/strings/string16.h" -#include "base/strings/string_split.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/common/widevine_cdm_messages.h" -#include "components/cdm/renderer/widevine_key_system_properties.h" -#include "content/public/renderer/render_thread.h" -#include "media/base/eme_constants.h" -#include "media/base/key_system_properties.h" - -// #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. -#include "third_party/widevine/cdm/stub/widevine_cdm_version.h" - -// The following must be after widevine_cdm_version.h. - -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) -#include -#include "base/version.h" -#endif - -using media::KeySystemProperties; -using media::SupportedCodecs; - -#if defined(ENABLE_PEPPER_CDMS) -static const char kExternalClearKeyPepperType[] = - "application/x-ppapi-clearkey-cdm"; - -static bool IsPepperCdmAvailable( - const std::string& pepper_type, - std::vector* additional_param_names, - std::vector* additional_param_values) { - bool is_available = false; - content::RenderThread::Get()->Send( - new ChromeViewHostMsg_IsInternalPluginAvailableForMimeType( - pepper_type, - &is_available, - additional_param_names, - additional_param_values)); - - return is_available; -} - -// KeySystemProperties implementation for external Clear Key systems. -class ExternalClearKeyProperties : public KeySystemProperties { - public: - explicit ExternalClearKeyProperties(const std::string& key_system_name) - : key_system_name_(key_system_name) {} - - std::string GetKeySystemName() const override { return key_system_name_; } - bool IsSupportedInitDataType( - media::EmeInitDataType init_data_type) const override { - switch (init_data_type) { - case media::EmeInitDataType::WEBM: - case media::EmeInitDataType::KEYIDS: - return true; - - case media::EmeInitDataType::CENC: -#if defined(USE_PROPRIETARY_CODECS) - return true; -#else - return false; -#endif // defined(USE_PROPRIETARY_CODECS) - - case media::EmeInitDataType::UNKNOWN: - return false; - } - NOTREACHED(); - return false; - } - - SupportedCodecs GetSupportedCodecs() const override { -#if defined(USE_PROPRIETARY_CODECS) - return media::EME_CODEC_MP4_ALL | media::EME_CODEC_WEBM_ALL; -#else - return media::EME_CODEC_WEBM_ALL; -#endif - } - - media::EmeConfigRule GetRobustnessConfigRule( - media::EmeMediaType media_type, - const std::string& requested_robustness) const override { - return requested_robustness.empty() ? media::EmeConfigRule::SUPPORTED - : media::EmeConfigRule::NOT_SUPPORTED; - } - - // Persistent license sessions are faked. - media::EmeSessionTypeSupport GetPersistentLicenseSessionSupport() - const override { - return media::EmeSessionTypeSupport::SUPPORTED; - } - - media::EmeSessionTypeSupport GetPersistentReleaseMessageSessionSupport() - const override { - return media::EmeSessionTypeSupport::NOT_SUPPORTED; - } - - media::EmeFeatureSupport GetPersistentStateSupport() const override { - return media::EmeFeatureSupport::REQUESTABLE; - } - - media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override { - return media::EmeFeatureSupport::NOT_SUPPORTED; - } - - std::string GetPepperType() const override { - return kExternalClearKeyPepperType; - } - - private: - const std::string key_system_name_; -}; - -// External Clear Key (used for testing). -static void AddExternalClearKey( - std::vector>* concrete_key_systems) { - static const char kExternalClearKeyKeySystem[] = - "org.chromium.externalclearkey"; - static const char kExternalClearKeyDecryptOnlyKeySystem[] = - "org.chromium.externalclearkey.decryptonly"; - static const char kExternalClearKeyFileIOTestKeySystem[] = - "org.chromium.externalclearkey.fileiotest"; - static const char kExternalClearKeyInitializeFailKeySystem[] = - "org.chromium.externalclearkey.initializefail"; - static const char kExternalClearKeyCrashKeySystem[] = - "org.chromium.externalclearkey.crash"; - - std::vector additional_param_names; - std::vector additional_param_values; - if (!IsPepperCdmAvailable(kExternalClearKeyPepperType, - &additional_param_names, - &additional_param_values)) { - return; - } - - concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyKeySystem)); - - // Add support of decrypt-only mode in ClearKeyCdm. - concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyDecryptOnlyKeySystem)); - - // A key system that triggers FileIO test in ClearKeyCdm. - concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyFileIOTestKeySystem)); - - // A key system that Chrome thinks is supported by ClearKeyCdm, but actually - // will be refused by ClearKeyCdm. This is to test the CDM initialization - // failure case. - concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyInitializeFailKeySystem)); - - // A key system that triggers a crash in ClearKeyCdm. - concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyCrashKeySystem)); -} - -#if defined(WIDEVINE_CDM_AVAILABLE) -// This function finds "codecs" and parses the value into the vector |codecs|. -// Converts the codec strings to UTF-8 since we only expect ASCII strings and -// this simplifies the rest of the code in this file. -void GetSupportedCodecsForPepperCdm( - const std::vector& additional_param_names, - const std::vector& additional_param_values, - std::vector* codecs) { - DCHECK(codecs->empty()); - DCHECK_EQ(additional_param_names.size(), additional_param_values.size()); - for (size_t i = 0; i < additional_param_names.size(); ++i) { - if (additional_param_names[i] == - base::ASCIIToUTF16(kCdmSupportedCodecsParamName)) { - const base::string16& codecs_string16 = additional_param_values[i]; - std::string codecs_string; - if (!base::UTF16ToUTF8(codecs_string16.c_str(), - codecs_string16.length(), - &codecs_string)) { - DLOG(WARNING) << "Non-UTF-8 codecs string."; - // Continue using the best effort conversion. - } - *codecs = base::SplitString( - codecs_string, std::string(1, kCdmSupportedCodecsValueDelimiter), - base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - break; - } - } -} - -static void AddPepperBasedWidevine( - std::vector>* concrete_key_systems) { -#if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) - Version glibc_version(gnu_get_libc_version()); - DCHECK(glibc_version.IsValid()); - if (glibc_version < base::Version(WIDEVINE_CDM_MIN_GLIBC_VERSION)) - return; -#endif // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) - - std::vector additional_param_names; - std::vector additional_param_values; - if (!IsPepperCdmAvailable(kWidevineCdmPluginMimeType, - &additional_param_names, - &additional_param_values)) { - DVLOG(1) << "Widevine CDM is not currently available."; - return; - } - - std::vector codecs; - GetSupportedCodecsForPepperCdm(additional_param_names, - additional_param_values, - &codecs); - - SupportedCodecs supported_codecs = media::EME_CODEC_NONE; - - // Audio codecs are always supported. - // TODO(sandersd): Distinguish these from those that are directly supported, - // as those may offer a higher level of protection. - supported_codecs |= media::EME_CODEC_WEBM_OPUS; - supported_codecs |= media::EME_CODEC_WEBM_VORBIS; -#if defined(USE_PROPRIETARY_CODECS) - supported_codecs |= media::EME_CODEC_MP4_AAC; -#endif // defined(USE_PROPRIETARY_CODECS) - - for (size_t i = 0; i < codecs.size(); ++i) { - if (codecs[i] == kCdmSupportedCodecVp8) - supported_codecs |= media::EME_CODEC_WEBM_VP8; - if (codecs[i] == kCdmSupportedCodecVp9) - supported_codecs |= media::EME_CODEC_WEBM_VP9; -#if defined(USE_PROPRIETARY_CODECS) - if (codecs[i] == kCdmSupportedCodecAvc1) - supported_codecs |= media::EME_CODEC_MP4_AVC1; - if (codecs[i] == kCdmSupportedCodecVp9) - supported_codecs |= media::EME_CODEC_MP4_VP9; -#endif // defined(USE_PROPRIETARY_CODECS) - } - - concrete_key_systems->emplace_back(new cdm::WidevineKeySystemProperties( - supported_codecs, -#if defined(OS_CHROMEOS) - media::EmeRobustness::HW_SECURE_ALL, // Maximum audio robustness. - media::EmeRobustness::HW_SECURE_ALL, // Maximim video robustness. - media::EmeSessionTypeSupport:: - SUPPORTED_WITH_IDENTIFIER, // Persistent-license. - media::EmeSessionTypeSupport:: - NOT_SUPPORTED, // Persistent-release-message. - media::EmeFeatureSupport::REQUESTABLE, // Persistent state. - media::EmeFeatureSupport::REQUESTABLE)); // Distinctive identifier. -#else // (Desktop) - media::EmeRobustness::SW_SECURE_CRYPTO, // Maximum audio robustness. - media::EmeRobustness::SW_SECURE_DECODE, // Maximum video robustness. - media::EmeSessionTypeSupport::NOT_SUPPORTED, // persistent-license. - media::EmeSessionTypeSupport:: - NOT_SUPPORTED, // persistent-release-message. - media::EmeFeatureSupport::REQUESTABLE, // Persistent state. - media::EmeFeatureSupport::NOT_SUPPORTED)); // Distinctive identifier. -#endif // defined(OS_CHROMEOS) -} -#endif // defined(WIDEVINE_CDM_AVAILABLE) -#endif // defined(ENABLE_PEPPER_CDMS) - -void AddChromeKeySystems( - std::vector>* key_systems_properties) { -#if defined(ENABLE_PEPPER_CDMS) - AddExternalClearKey(key_systems_properties); - -#if defined(WIDEVINE_CDM_AVAILABLE) - AddPepperBasedWidevine(key_systems_properties); -#endif // defined(WIDEVINE_CDM_AVAILABLE) -#endif // defined(ENABLE_PEPPER_CDMS) -} diff --git a/chromium_src/chrome/renderer/media/chrome_key_systems.h b/chromium_src/chrome/renderer/media/chrome_key_systems.h deleted file mode 100644 index 3e82ee70e2b78..0000000000000 --- a/chromium_src/chrome/renderer/media/chrome_key_systems.h +++ /dev/null @@ -1,20 +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_RENDERER_MEDIA_CHROME_KEY_SYSTEMS_H_ -#define CHROME_RENDERER_MEDIA_CHROME_KEY_SYSTEMS_H_ - -#include -#include - -namespace media { -class KeySystemProperties; -} - -// Register the key systems supported by populating |key_systems_properties|. -void AddChromeKeySystems( - std::vector>* - key_systems_properties); - -#endif // CHROME_RENDERER_MEDIA_CHROME_KEY_SYSTEMS_H_ diff --git a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc deleted file mode 100644 index bcf6debc4cf5f..0000000000000 --- a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc +++ /dev/null @@ -1,83 +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/renderer/pepper/chrome_renderer_pepper_host_factory.h" - -#include "base/logging.h" -#include "chrome/renderer/pepper/pepper_flash_font_file_host.h" -#include "chrome/renderer/pepper/pepper_flash_fullscreen_host.h" -#include "chrome/renderer/pepper/pepper_flash_menu_host.h" -#include "chrome/renderer/pepper/pepper_flash_renderer_host.h" -#include "content/public/renderer/renderer_ppapi_host.h" -#include "ppapi/host/ppapi_host.h" -#include "ppapi/host/resource_host.h" -#include "ppapi/proxy/ppapi_message_utils.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/shared_impl/ppapi_permissions.h" - -using ppapi::host::ResourceHost; - -ChromeRendererPepperHostFactory::ChromeRendererPepperHostFactory( - content::RendererPpapiHost* host) - : host_(host) {} - -ChromeRendererPepperHostFactory::~ChromeRendererPepperHostFactory() {} - -std::unique_ptr ChromeRendererPepperHostFactory::CreateResourceHost( - ppapi::host::PpapiHost* host, - PP_Resource resource, - PP_Instance instance, - const IPC::Message& message) { - DCHECK_EQ(host_->GetPpapiHost(), host); - - // Make sure the plugin is giving us a valid instance for this resource. - if (!host_->IsValidInstance(instance)) - return std::unique_ptr(); - - if (host_->GetPpapiHost()->permissions().HasPermission( - ppapi::PERMISSION_FLASH)) { - switch (message.type()) { - case PpapiHostMsg_Flash_Create::ID: { - return std::unique_ptr( - new PepperFlashRendererHost(host_, instance, resource)); - } - case PpapiHostMsg_FlashFullscreen_Create::ID: { - return std::unique_ptr( - new PepperFlashFullscreenHost(host_, instance, resource)); - } - case PpapiHostMsg_FlashMenu_Create::ID: { - ppapi::proxy::SerializedFlashMenu serialized_menu; - if (ppapi::UnpackMessage( - message, &serialized_menu)) { - return std::unique_ptr(new PepperFlashMenuHost( - host_, instance, resource, serialized_menu)); - } - break; - } - } - } - - // TODO(raymes): PDF also needs access to the FlashFontFileHost currently. - // We should either rename PPB_FlashFont_File to PPB_FontFile_Private or get - // rid of its use in PDF if possible. - if (host_->GetPpapiHost()->permissions().HasPermission( - ppapi::PERMISSION_FLASH) || - host_->GetPpapiHost()->permissions().HasPermission( - ppapi::PERMISSION_PRIVATE)) { - switch (message.type()) { - case PpapiHostMsg_FlashFontFile_Create::ID: { - ppapi::proxy::SerializedFontDescription description; - PP_PrivateFontCharset charset; - if (ppapi::UnpackMessage( - message, &description, &charset)) { - return std::unique_ptr(new PepperFlashFontFileHost( - host_, instance, resource, description, charset)); - } - break; - } - } - } - - return std::unique_ptr(); -} diff --git a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h b/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h deleted file mode 100644 index c52c73b56f048..0000000000000 --- a/chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h +++ /dev/null @@ -1,34 +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_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_ -#define CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_ - -#include "base/macros.h" -#include "ppapi/host/host_factory.h" - -namespace content { -class RendererPpapiHost; -} - -class ChromeRendererPepperHostFactory : public ppapi::host::HostFactory { - public: - explicit ChromeRendererPepperHostFactory(content::RendererPpapiHost* host); - ~ChromeRendererPepperHostFactory() override; - - // HostFactory. - std::unique_ptr CreateResourceHost( - ppapi::host::PpapiHost* host, - PP_Resource resource, - PP_Instance instance, - const IPC::Message& message) override; - - private: - // Not owned by this object. - content::RendererPpapiHost* host_; - - DISALLOW_COPY_AND_ASSIGN(ChromeRendererPepperHostFactory); -}; - -#endif // CHROME_RENDERER_PEPPER_CHROME_RENDERER_PEPPER_HOST_FACTORY_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.cc deleted file mode 100644 index 305b6ec56c071..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.cc +++ /dev/null @@ -1,74 +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/renderer/pepper/pepper_flash_font_file_host.h" - -#include "build/build_config.h" -#include "content/public/renderer/renderer_ppapi_host.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/host/dispatch_host_message.h" -#include "ppapi/host/host_message_context.h" -#include "ppapi/host/ppapi_host.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/proxy/serialized_structs.h" - -#if defined(OS_LINUX) || defined(OS_OPENBSD) -#include "content/public/common/child_process_sandbox_support_linux.h" -#endif - -PepperFlashFontFileHost::PepperFlashFontFileHost( - content::RendererPpapiHost* host, - PP_Instance instance, - PP_Resource resource, - const ppapi::proxy::SerializedFontDescription& description, - PP_PrivateFontCharset charset) - : ResourceHost(host->GetPpapiHost(), instance, resource) { -#if defined(OS_LINUX) || defined(OS_OPENBSD) - fd_.reset(content::MatchFontWithFallback( - description.face.c_str(), - description.weight >= PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD, - description.italic, - charset, - PP_BROWSERFONT_TRUSTED_FAMILY_DEFAULT)); -#endif // defined(OS_LINUX) || defined(OS_OPENBSD) -} - -PepperFlashFontFileHost::~PepperFlashFontFileHost() {} - -int32_t PepperFlashFontFileHost::OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) { - PPAPI_BEGIN_MESSAGE_MAP(PepperFlashFontFileHost, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFontFile_GetFontTable, - OnGetFontTable) - PPAPI_END_MESSAGE_MAP() - return PP_ERROR_FAILED; -} - -int32_t PepperFlashFontFileHost::OnGetFontTable( - ppapi::host::HostMessageContext* context, - uint32_t table) { - std::string contents; - int32_t result = PP_ERROR_FAILED; -#if defined(OS_LINUX) || defined(OS_OPENBSD) - int fd = fd_.get(); - if (fd != -1) { - size_t length = 0; - if (content::GetFontTable(fd, table, 0 /* offset */, NULL, &length)) { - contents.resize(length); - uint8_t* contents_ptr = - reinterpret_cast(const_cast(contents.c_str())); - if (content::GetFontTable( - fd, table, 0 /* offset */, contents_ptr, &length)) { - result = PP_OK; - } else { - contents.clear(); - } - } - } -#endif // defined(OS_LINUX) || defined(OS_OPENBSD) - - context->reply_msg = PpapiPluginMsg_FlashFontFile_GetFontTableReply(contents); - return result; -} diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.h b/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.h deleted file mode 100644 index eeaa7209b5f04..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.h +++ /dev/null @@ -1,50 +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_RENDERER_PEPPER_PEPPER_FLASH_FONT_FILE_HOST_H_ -#define CHROME_RENDERER_PEPPER_PEPPER_FLASH_FONT_FILE_HOST_H_ - -#include "ppapi/c/private/pp_private_font_charset.h" -#include "ppapi/host/resource_host.h" - -#if defined(OS_LINUX) || defined(OS_OPENBSD) -#include "base/files/scoped_file.h" -#endif - -namespace content { -class RendererPpapiHost; -} - -namespace ppapi { -namespace proxy { -struct SerializedFontDescription; -} -} - -class PepperFlashFontFileHost : public ppapi::host::ResourceHost { - public: - PepperFlashFontFileHost( - content::RendererPpapiHost* host, - PP_Instance instance, - PP_Resource resource, - const ppapi::proxy::SerializedFontDescription& description, - PP_PrivateFontCharset charset); - ~PepperFlashFontFileHost() override; - - int32_t OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) override; - - private: - int32_t OnGetFontTable(ppapi::host::HostMessageContext* context, - uint32_t table); - -#if defined(OS_LINUX) || defined(OS_OPENBSD) - base::ScopedFD fd_; -#endif - - DISALLOW_COPY_AND_ASSIGN(PepperFlashFontFileHost); -}; - -#endif // CHROME_RENDERER_PEPPER_PEPPER_FLASH_FONT_FILE_HOST_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc deleted file mode 100644 index d590cde3a4a5b..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.cc +++ /dev/null @@ -1,43 +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/renderer/pepper/pepper_flash_fullscreen_host.h" - -#include "content/public/renderer/pepper_plugin_instance.h" -#include "content/public/renderer/renderer_ppapi_host.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/host/dispatch_host_message.h" -#include "ppapi/host/host_message_context.h" -#include "ppapi/host/ppapi_host.h" -#include "ppapi/proxy/ppapi_messages.h" - -PepperFlashFullscreenHost::PepperFlashFullscreenHost( - content::RendererPpapiHost* host, - PP_Instance instance, - PP_Resource resource) - : ResourceHost(host->GetPpapiHost(), instance, resource), - renderer_ppapi_host_(host) {} - -PepperFlashFullscreenHost::~PepperFlashFullscreenHost() {} - -int32_t PepperFlashFullscreenHost::OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) { - PPAPI_BEGIN_MESSAGE_MAP(PepperFlashFullscreenHost, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL( - PpapiHostMsg_FlashFullscreen_SetFullscreen, - OnSetFullscreen) - PPAPI_END_MESSAGE_MAP() - return PP_ERROR_FAILED; -} - -int32_t PepperFlashFullscreenHost::OnSetFullscreen( - ppapi::host::HostMessageContext* context, - bool fullscreen) { - content::PepperPluginInstance* plugin_instance = - renderer_ppapi_host_->GetPluginInstance(pp_instance()); - if (plugin_instance && plugin_instance->FlashSetFullscreen(fullscreen, true)) - return PP_OK; - return PP_ERROR_FAILED; -} diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.h b/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.h deleted file mode 100644 index 86d0af73aee54..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_fullscreen_host.h +++ /dev/null @@ -1,35 +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_RENDERER_PEPPER_PEPPER_FLASH_FULLSCREEN_HOST_H_ -#define CHROME_RENDERER_PEPPER_PEPPER_FLASH_FULLSCREEN_HOST_H_ - -#include "ppapi/host/resource_host.h" - -namespace content { -class RendererPpapiHost; -} - -class PepperFlashFullscreenHost : public ppapi::host::ResourceHost { - public: - PepperFlashFullscreenHost(content::RendererPpapiHost* host, - PP_Instance instance, - PP_Resource resource); - ~PepperFlashFullscreenHost() override; - - int32_t OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) override; - - private: - int32_t OnSetFullscreen(ppapi::host::HostMessageContext* context, - bool fullscreen); - - // Non-owning pointer. - content::RendererPpapiHost* renderer_ppapi_host_; - - DISALLOW_COPY_AND_ASSIGN(PepperFlashFullscreenHost); -}; - -#endif // CHROME_RENDERER_PEPPER_PEPPER_FLASH_FULLSCREEN_HOST_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.cc deleted file mode 100644 index 3b7a438f7220b..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.cc +++ /dev/null @@ -1,202 +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/renderer/pepper/pepper_flash_menu_host.h" - -#include "base/strings/utf_string_conversions.h" -#include "content/public/common/context_menu_params.h" -#include "content/public/renderer/render_frame.h" -#include "content/public/renderer/renderer_ppapi_host.h" -#include "ipc/ipc_message.h" -#include "ppapi/c/private/ppb_flash_menu.h" -#include "ppapi/host/dispatch_host_message.h" -#include "ppapi/host/ppapi_host.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/proxy/serialized_flash_menu.h" -#include "ui/gfx/geometry/point.h" - -namespace { - -// Maximum depth of submenus allowed (e.g., 1 indicates that submenus are -// allowed, but not sub-submenus). -const size_t kMaxMenuDepth = 2; - -// Maximum number of entries in any single menu (including separators). -const size_t kMaxMenuEntries = 50; - -// Maximum total number of entries in the |menu_id_map| (see below). -// (Limit to 500 real entries; reserve the 0 action as an invalid entry.) -const size_t kMaxMenuIdMapEntries = 501; - -// Converts menu data from one form to another. -// - |depth| is the current nested depth (call it starting with 0). -// - |menu_id_map| is such that |menu_id_map[output_item.action] == -// input_item.id| (where |action| is what a |MenuItem| has, |id| is what a -// |PP_Flash_MenuItem| has). -bool ConvertMenuData(const PP_Flash_Menu* in_menu, - size_t depth, - std::vector* out_menu, - std::vector* menu_id_map) { - if (depth > kMaxMenuDepth || !in_menu) - return false; - - // Clear the output, just in case. - out_menu->clear(); - - if (!in_menu->count) - return true; // Nothing else to do. - - if (!in_menu->items || in_menu->count > kMaxMenuEntries) - return false; - for (uint32_t i = 0; i < in_menu->count; i++) { - content::MenuItem item; - - PP_Flash_MenuItem_Type type = in_menu->items[i].type; - switch (type) { - case PP_FLASH_MENUITEM_TYPE_NORMAL: - item.type = content::MenuItem::OPTION; - break; - case PP_FLASH_MENUITEM_TYPE_CHECKBOX: - item.type = content::MenuItem::CHECKABLE_OPTION; - break; - case PP_FLASH_MENUITEM_TYPE_SEPARATOR: - item.type = content::MenuItem::SEPARATOR; - break; - case PP_FLASH_MENUITEM_TYPE_SUBMENU: - item.type = content::MenuItem::SUBMENU; - break; - default: - return false; - } - if (in_menu->items[i].name) - item.label = base::UTF8ToUTF16(in_menu->items[i].name); - if (menu_id_map->size() >= kMaxMenuIdMapEntries) - return false; - item.action = static_cast(menu_id_map->size()); - // This sets |(*menu_id_map)[item.action] = in_menu->items[i].id|. - menu_id_map->push_back(in_menu->items[i].id); - item.enabled = PP_ToBool(in_menu->items[i].enabled); - item.checked = PP_ToBool(in_menu->items[i].checked); - if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) { - if (!ConvertMenuData( - in_menu->items[i].submenu, depth + 1, &item.submenu, menu_id_map)) - return false; - } - - out_menu->push_back(item); - } - - return true; -} - -} // namespace - -PepperFlashMenuHost::PepperFlashMenuHost( - content::RendererPpapiHost* host, - PP_Instance instance, - PP_Resource resource, - const ppapi::proxy::SerializedFlashMenu& serial_menu) - : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource), - renderer_ppapi_host_(host), - showing_context_menu_(false), - context_menu_request_id_(0), - has_saved_context_menu_action_(false), - saved_context_menu_action_(0) { - menu_id_map_.push_back(0); // Reserve |menu_id_map_[0]|. - if (!ConvertMenuData(serial_menu.pp_menu(), 0, &menu_data_, &menu_id_map_)) { - menu_data_.clear(); - menu_id_map_.clear(); - } -} - -PepperFlashMenuHost::~PepperFlashMenuHost() { - if (showing_context_menu_) { - content::RenderFrame* render_frame = - renderer_ppapi_host_->GetRenderFrameForInstance(pp_instance()); - if (render_frame) - render_frame->CancelContextMenu(context_menu_request_id_); - } -} - -int32_t PepperFlashMenuHost::OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) { - PPAPI_BEGIN_MESSAGE_MAP(PepperFlashMenuHost, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashMenu_Show, - OnHostMsgShow) - PPAPI_END_MESSAGE_MAP() - return PP_ERROR_FAILED; -} - -int32_t PepperFlashMenuHost::OnHostMsgShow( - ppapi::host::HostMessageContext* context, - const PP_Point& location) { - // Note that all early returns must do a SendMenuReply. The sync result for - // this message isn't used, so to forward the error to the plugin, we need to - // additionally call SendMenuReply explicitly. - if (menu_data_.empty()) { - SendMenuReply(PP_ERROR_FAILED, -1); - return PP_ERROR_FAILED; - } - if (showing_context_menu_) { - SendMenuReply(PP_ERROR_INPROGRESS, -1); - return PP_ERROR_INPROGRESS; - } - - content::RenderFrame* render_frame = - renderer_ppapi_host_->GetRenderFrameForInstance(pp_instance()); - - content::ContextMenuParams params; - params.x = location.x; - params.y = location.y; - params.custom_context.is_pepper_menu = true; - params.custom_context.render_widget_id = - renderer_ppapi_host_->GetRoutingIDForWidget(pp_instance()); - params.custom_items = menu_data_; - - // Transform the position to be in render frame's coordinates. - gfx::Point render_frame_pt = renderer_ppapi_host_->PluginPointToRenderFrame( - pp_instance(), gfx::Point(location.x, location.y)); - params.x = render_frame_pt.x(); - params.y = render_frame_pt.y(); - - showing_context_menu_ = true; - context_menu_request_id_ = render_frame->ShowContextMenu(this, params); - - // Note: the show message is sync so this OK is for the sync reply which we - // don't actually use (see the comment in the resource file for this). The - // async message containing the context menu action will be sent in the - // future. - return PP_OK; -} - -void PepperFlashMenuHost::OnMenuAction(int request_id, unsigned action) { - // Just save the action. - DCHECK(!has_saved_context_menu_action_); - has_saved_context_menu_action_ = true; - saved_context_menu_action_ = action; -} - -void PepperFlashMenuHost::OnMenuClosed(int request_id) { - if (has_saved_context_menu_action_ && - saved_context_menu_action_ < menu_id_map_.size()) { - SendMenuReply(PP_OK, menu_id_map_[saved_context_menu_action_]); - has_saved_context_menu_action_ = false; - saved_context_menu_action_ = 0; - } else { - SendMenuReply(PP_ERROR_USERCANCEL, -1); - } - - showing_context_menu_ = false; - context_menu_request_id_ = 0; -} - -void PepperFlashMenuHost::SendMenuReply(int32_t result, int action) { - ppapi::host::ReplyMessageContext reply_context( - ppapi::proxy::ResourceMessageReplyParams(pp_resource(), 0), - NULL, - MSG_ROUTING_NONE); - reply_context.params.set_result(result); - host()->SendReply(reply_context, PpapiPluginMsg_FlashMenu_ShowReply(action)); -} diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.h b/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.h deleted file mode 100644 index 3aa730a6afc39..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_menu_host.h +++ /dev/null @@ -1,69 +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_RENDERER_PEPPER_PEPPER_FLASH_MENU_HOST_H_ -#define CHROME_RENDERER_PEPPER_PEPPER_FLASH_MENU_HOST_H_ - -#include - -#include "base/compiler_specific.h" -#include "content/public/renderer/context_menu_client.h" -#include "ppapi/c/pp_point.h" -#include "ppapi/host/host_message_context.h" -#include "ppapi/host/resource_host.h" - -namespace content { -class RendererPpapiHost; -struct MenuItem; -} - -namespace ppapi { -namespace proxy { -class SerializedFlashMenu; -} -} - -class PepperFlashMenuHost : public ppapi::host::ResourceHost, - public content::ContextMenuClient { - public: - PepperFlashMenuHost(content::RendererPpapiHost* host, - PP_Instance instance, - PP_Resource resource, - const ppapi::proxy::SerializedFlashMenu& serial_menu); - ~PepperFlashMenuHost() override; - - int32_t OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) override; - - private: - int32_t OnHostMsgShow(ppapi::host::HostMessageContext* context, - const PP_Point& location); - - // ContextMenuClient implementation. - void OnMenuAction(int request_id, unsigned action) override; - void OnMenuClosed(int request_id) override; - - void SendMenuReply(int32_t result, int action); - - content::RendererPpapiHost* renderer_ppapi_host_; - - bool showing_context_menu_; - int context_menu_request_id_; - - std::vector menu_data_; - - // We send |MenuItem|s, which have an |unsigned| "action" field instead of - // an |int32_t| ID. (CONTENT also limits the range of valid values for - // actions.) This maps actions to IDs. - std::vector menu_id_map_; - - // Used to send a single context menu "completion" upon menu close. - bool has_saved_context_menu_action_; - unsigned saved_context_menu_action_; - - DISALLOW_COPY_AND_ASSIGN(PepperFlashMenuHost); -}; - -#endif // CHROME_RENDERER_PEPPER_PEPPER_FLASH_MENU_HOST_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc deleted file mode 100644 index 59046b328bfea..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.cc +++ /dev/null @@ -1,372 +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/renderer/pepper/pepper_flash_renderer_host.h" - -#include -#include - -#include "base/lazy_instance.h" -#include "base/metrics/histogram.h" -#include "base/strings/string_util.h" -#include "content/public/renderer/pepper_plugin_instance.h" -#include "content/public/renderer/render_thread.h" -#include "content/public/renderer/renderer_ppapi_host.h" -#include "ipc/ipc_message_macros.h" -#include "net/http/http_util.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/c/trusted/ppb_browser_font_trusted.h" -#include "ppapi/host/dispatch_host_message.h" -#include "ppapi/proxy/host_dispatcher.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/proxy/resource_message_params.h" -#include "ppapi/proxy/serialized_structs.h" -#include "ppapi/thunk/enter.h" -#include "ppapi/thunk/ppb_image_data_api.h" -#include "skia/ext/platform_canvas.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkMatrix.h" -#include "third_party/skia/include/core/SkPaint.h" -#include "third_party/skia/include/core/SkPoint.h" -#include "third_party/skia/include/core/SkTypeface.h" -#include "ui/gfx/geometry/rect.h" -#include "url/gurl.h" - -using ppapi::thunk::EnterResourceNoLock; -using ppapi::thunk::PPB_ImageData_API; - -namespace { - -// Some non-simple HTTP request headers that Flash may set. -// (Please see http://www.w3.org/TR/cors/#simple-header for the definition of -// simple headers.) -// -// The list and the enum defined below are used to collect data about request -// headers used in PPB_Flash.Navigate() calls, in order to understand the impact -// of rejecting PPB_Flash.Navigate() requests with non-simple headers. -// -// TODO(yzshen): We should be able to remove the histogram recording code once -// we get the answer. -const char* const kRejectedHttpRequestHeaders[] = { - "authorization", // - "cache-control", // - "content-encoding", // - "content-md5", // - "content-type", // If the media type is not one of those covered by the - // simple header definition. - "expires", // - "from", // - "if-match", // - "if-none-match", // - "if-range", // - "if-unmodified-since", // - "pragma", // - "referer" // -}; - -// Please note that new entries should be added right above -// FLASH_NAVIGATE_USAGE_ENUM_COUNT, and existing entries shouldn't be re-ordered -// or removed, since this ordering is used in a histogram. -enum FlashNavigateUsage { - // This section must be in the same order as kRejectedHttpRequestHeaders. - REJECT_AUTHORIZATION = 0, - REJECT_CACHE_CONTROL, - REJECT_CONTENT_ENCODING, - REJECT_CONTENT_MD5, - REJECT_CONTENT_TYPE, - REJECT_EXPIRES, - REJECT_FROM, - REJECT_IF_MATCH, - REJECT_IF_NONE_MATCH, - REJECT_IF_RANGE, - REJECT_IF_UNMODIFIED_SINCE, - REJECT_PRAGMA, - REJECT_REFERER, - - // The navigate request is rejected because of headers not listed above - // (e.g., custom headers). - REJECT_OTHER_HEADERS, - - // Total number of rejected navigate requests. - TOTAL_REJECTED_NAVIGATE_REQUESTS, - - // Total number of navigate requests. - TOTAL_NAVIGATE_REQUESTS, - FLASH_NAVIGATE_USAGE_ENUM_COUNT -}; - -static base::LazyInstance > - g_rejected_headers = LAZY_INSTANCE_INITIALIZER; - -bool IsSimpleHeader(const std::string& lower_case_header_name, - const std::string& header_value) { - if (lower_case_header_name == "accept" || - lower_case_header_name == "accept-language" || - lower_case_header_name == "content-language") { - return true; - } - - if (lower_case_header_name == "content-type") { - std::string lower_case_mime_type; - std::string lower_case_charset; - bool had_charset = false; - net::HttpUtil::ParseContentType(header_value, - &lower_case_mime_type, - &lower_case_charset, - &had_charset, - NULL); - return lower_case_mime_type == "application/x-www-form-urlencoded" || - lower_case_mime_type == "multipart/form-data" || - lower_case_mime_type == "text/plain"; - } - - return false; -} - -void RecordFlashNavigateUsage(FlashNavigateUsage usage) { - DCHECK_NE(FLASH_NAVIGATE_USAGE_ENUM_COUNT, usage); - UMA_HISTOGRAM_ENUMERATION( - "Plugin.FlashNavigateUsage", usage, FLASH_NAVIGATE_USAGE_ENUM_COUNT); -} - -} // namespace - -PepperFlashRendererHost::PepperFlashRendererHost( - content::RendererPpapiHost* host, - PP_Instance instance, - PP_Resource resource) - : ResourceHost(host->GetPpapiHost(), instance, resource), - host_(host), - weak_factory_(this) {} - -PepperFlashRendererHost::~PepperFlashRendererHost() { - // This object may be destroyed in the middle of a sync message. If that is - // the case, make sure we respond to all the pending navigate calls. - std::vector::reverse_iterator it; - for (it = navigate_replies_.rbegin(); it != navigate_replies_.rend(); ++it) - SendReply(*it, IPC::Message()); -} - -int32_t PepperFlashRendererHost::OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) { - PPAPI_BEGIN_MESSAGE_MAP(PepperFlashRendererHost, msg) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_GetProxyForURL, - OnGetProxyForURL) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_SetInstanceAlwaysOnTop, - OnSetInstanceAlwaysOnTop) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_DrawGlyphs, - OnDrawGlyphs) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_Navigate, OnNavigate) - PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_IsRectTopmost, - OnIsRectTopmost) - PPAPI_END_MESSAGE_MAP() - return PP_ERROR_FAILED; -} - -int32_t PepperFlashRendererHost::OnGetProxyForURL( - ppapi::host::HostMessageContext* host_context, - const std::string& url) { - GURL gurl(url); - if (!gurl.is_valid()) - return PP_ERROR_FAILED; - std::string proxy; - bool result = content::RenderThread::Get()->ResolveProxy(gurl, &proxy); - if (!result) - return PP_ERROR_FAILED; - host_context->reply_msg = PpapiPluginMsg_Flash_GetProxyForURLReply(proxy); - return PP_OK; -} - -int32_t PepperFlashRendererHost::OnSetInstanceAlwaysOnTop( - ppapi::host::HostMessageContext* host_context, - bool on_top) { - content::PepperPluginInstance* plugin_instance = - host_->GetPluginInstance(pp_instance()); - if (plugin_instance) - plugin_instance->SetAlwaysOnTop(on_top); - // Since no reply is sent for this message, it doesn't make sense to return an - // error. - return PP_OK; -} - -int32_t PepperFlashRendererHost::OnDrawGlyphs( - ppapi::host::HostMessageContext* host_context, - ppapi::proxy::PPBFlash_DrawGlyphs_Params params) { - if (params.glyph_indices.size() != params.glyph_advances.size() || - params.glyph_indices.empty()) - return PP_ERROR_FAILED; - - // Set up the typeface. - int style = SkTypeface::kNormal; - if (static_cast(params.font_desc.weight) >= - PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD) - style |= SkTypeface::kBold; - if (params.font_desc.italic) - style |= SkTypeface::kItalic; - sk_sp typeface(SkTypeface::CreateFromName( - params.font_desc.face.c_str(), static_cast(style))); - if (!typeface) - return PP_ERROR_FAILED; - - EnterResourceNoLock enter( - params.image_data.host_resource(), true); - if (enter.failed()) - return PP_ERROR_FAILED; - - // Set up the canvas. - PPB_ImageData_API* image = static_cast(enter.object()); - SkCanvas* canvas = image->GetCanvas(); - bool needs_unmapping = false; - if (!canvas) { - needs_unmapping = true; - image->Map(); - canvas = image->GetCanvas(); - if (!canvas) - return PP_ERROR_FAILED; // Failure mapping. - } - - SkAutoCanvasRestore acr(canvas, true); - - // Clip is applied in pixels before the transform. - SkRect clip_rect = { - SkIntToScalar(params.clip.point.x), SkIntToScalar(params.clip.point.y), - SkIntToScalar(params.clip.point.x + params.clip.size.width), - SkIntToScalar(params.clip.point.y + params.clip.size.height)}; - canvas->clipRect(clip_rect); - - // Convert & set the matrix. - SkMatrix matrix; - matrix.set(SkMatrix::kMScaleX, SkFloatToScalar(params.transformation[0][0])); - matrix.set(SkMatrix::kMSkewX, SkFloatToScalar(params.transformation[0][1])); - matrix.set(SkMatrix::kMTransX, SkFloatToScalar(params.transformation[0][2])); - matrix.set(SkMatrix::kMSkewY, SkFloatToScalar(params.transformation[1][0])); - matrix.set(SkMatrix::kMScaleY, SkFloatToScalar(params.transformation[1][1])); - matrix.set(SkMatrix::kMTransY, SkFloatToScalar(params.transformation[1][2])); - matrix.set(SkMatrix::kMPersp0, SkFloatToScalar(params.transformation[2][0])); - matrix.set(SkMatrix::kMPersp1, SkFloatToScalar(params.transformation[2][1])); - matrix.set(SkMatrix::kMPersp2, SkFloatToScalar(params.transformation[2][2])); - canvas->concat(matrix); - - SkPaint paint; - paint.setColor(params.color); - paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - paint.setAntiAlias(true); - paint.setHinting(SkPaint::kFull_Hinting); - paint.setTextSize(SkIntToScalar(params.font_desc.size)); - paint.setTypeface(std::move(typeface)); - if (params.allow_subpixel_aa) { - paint.setSubpixelText(true); - paint.setLCDRenderText(true); - } - - SkScalar x = SkIntToScalar(params.position.x); - SkScalar y = SkIntToScalar(params.position.y); - - // Build up the skia advances. - size_t glyph_count = params.glyph_indices.size(); - if (glyph_count) { - std::vector storage; - storage.resize(glyph_count); - SkPoint* sk_positions = &storage[0]; - for (uint32_t i = 0; i < glyph_count; i++) { - sk_positions[i].set(x, y); - x += SkFloatToScalar(params.glyph_advances[i].x); - y += SkFloatToScalar(params.glyph_advances[i].y); - } - - canvas->drawPosText( - ¶ms.glyph_indices[0], glyph_count * 2, sk_positions, paint); - } - - if (needs_unmapping) - image->Unmap(); - - return PP_OK; -} - -// CAUTION: This code is subtle because Navigate is a sync call which may -// cause re-entrancy or cause the instance to be destroyed. If the instance -// is destroyed we need to ensure that we respond to all outstanding sync -// messages so that the plugin process does not remain blocked. -int32_t PepperFlashRendererHost::OnNavigate( - ppapi::host::HostMessageContext* host_context, - const ppapi::URLRequestInfoData& data, - const std::string& target, - bool from_user_action) { - // If our PepperPluginInstance is already destroyed, just return a failure. - content::PepperPluginInstance* plugin_instance = - host_->GetPluginInstance(pp_instance()); - if (!plugin_instance) - return PP_ERROR_FAILED; - - std::map& rejected_headers = - g_rejected_headers.Get(); - if (rejected_headers.empty()) { - for (size_t i = 0; i < arraysize(kRejectedHttpRequestHeaders); ++i) - rejected_headers[kRejectedHttpRequestHeaders[i]] = - static_cast(i); - } - - net::HttpUtil::HeadersIterator header_iter( - data.headers.begin(), data.headers.end(), "\n\r"); - bool rejected = false; - while (header_iter.GetNext()) { - std::string lower_case_header_name = - base::ToLowerASCII(header_iter.name()); - if (!IsSimpleHeader(lower_case_header_name, header_iter.values())) { - rejected = true; - - std::map::const_iterator iter = - rejected_headers.find(lower_case_header_name); - FlashNavigateUsage usage = - iter != rejected_headers.end() ? iter->second : REJECT_OTHER_HEADERS; - RecordFlashNavigateUsage(usage); - } - } - - RecordFlashNavigateUsage(TOTAL_NAVIGATE_REQUESTS); - if (rejected) { - RecordFlashNavigateUsage(TOTAL_REJECTED_NAVIGATE_REQUESTS); - return PP_ERROR_NOACCESS; - } - - // Navigate may call into Javascript (e.g. with a "javascript:" URL), - // or do things like navigate away from the page, either one of which will - // need to re-enter into the plugin. It is safe, because it is essentially - // equivalent to NPN_GetURL, where Flash would expect re-entrancy. - ppapi::proxy::HostDispatcher* host_dispatcher = - ppapi::proxy::HostDispatcher::GetForInstance(pp_instance()); - host_dispatcher->set_allow_plugin_reentrancy(); - - // Grab a weak pointer to ourselves on the stack so we can check if we are - // still alive. - base::WeakPtr weak_ptr = weak_factory_.GetWeakPtr(); - // Keep track of reply contexts in case we are destroyed during a Navigate - // call. Even if we are destroyed, we still need to send these replies to - // unblock the plugin process. - navigate_replies_.push_back(host_context->MakeReplyMessageContext()); - plugin_instance->Navigate(data, target.c_str(), from_user_action); - // This object might have been destroyed by this point. If it is destroyed - // the reply will be sent in the destructor. Otherwise send the reply here. - if (weak_ptr.get()) { - SendReply(navigate_replies_.back(), IPC::Message()); - navigate_replies_.pop_back(); - } - - // Return PP_OK_COMPLETIONPENDING so that no reply is automatically sent. - return PP_OK_COMPLETIONPENDING; -} - -int32_t PepperFlashRendererHost::OnIsRectTopmost( - ppapi::host::HostMessageContext* host_context, - const PP_Rect& rect) { - content::PepperPluginInstance* plugin_instance = - host_->GetPluginInstance(pp_instance()); - if (plugin_instance && - plugin_instance->IsRectTopmost(gfx::Rect( - rect.point.x, rect.point.y, rect.size.width, rect.size.height))) - return PP_OK; - return PP_ERROR_FAILED; -} diff --git a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.h b/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.h deleted file mode 100644 index f37907a8655e6..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_flash_renderer_host.h +++ /dev/null @@ -1,68 +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_RENDERER_PEPPER_PEPPER_FLASH_RENDERER_HOST_H_ -#define CHROME_RENDERER_PEPPER_PEPPER_FLASH_RENDERER_HOST_H_ - -#include -#include - -#include "base/memory/weak_ptr.h" -#include "ppapi/host/host_message_context.h" -#include "ppapi/host/resource_host.h" - -struct PP_Rect; - -namespace ppapi { -struct URLRequestInfoData; -} - -namespace ppapi { -namespace proxy { -struct PPBFlash_DrawGlyphs_Params; -} -} - -namespace content { -class RendererPpapiHost; -} - -class PepperFlashRendererHost : public ppapi::host::ResourceHost { - public: - PepperFlashRendererHost(content::RendererPpapiHost* host, - PP_Instance instance, - PP_Resource resource); - ~PepperFlashRendererHost() override; - - // ppapi::host::ResourceHost override. - int32_t OnResourceMessageReceived( - const IPC::Message& msg, - ppapi::host::HostMessageContext* context) override; - - private: - int32_t OnGetProxyForURL(ppapi::host::HostMessageContext* host_context, - const std::string& url); - int32_t OnSetInstanceAlwaysOnTop( - ppapi::host::HostMessageContext* host_context, - bool on_top); - int32_t OnDrawGlyphs(ppapi::host::HostMessageContext* host_context, - ppapi::proxy::PPBFlash_DrawGlyphs_Params params); - int32_t OnNavigate(ppapi::host::HostMessageContext* host_context, - const ppapi::URLRequestInfoData& data, - const std::string& target, - bool from_user_action); - int32_t OnIsRectTopmost(ppapi::host::HostMessageContext* host_context, - const PP_Rect& rect); - - // A stack of ReplyMessageContexts to track Navigate() calls which have not - // yet been replied to. - std::vector navigate_replies_; - - content::RendererPpapiHost* host_; - base::WeakPtrFactory weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(PepperFlashRendererHost); -}; - -#endif // CHROME_RENDERER_PEPPER_PEPPER_FLASH_RENDERER_HOST_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_helper.cc b/chromium_src/chrome/renderer/pepper/pepper_helper.cc deleted file mode 100644 index c9700c997137d..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_helper.cc +++ /dev/null @@ -1,26 +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/renderer/pepper/pepper_helper.h" - -#include "chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h" -#include "chrome/renderer/pepper/pepper_shared_memory_message_filter.h" -#include "content/public/renderer/renderer_ppapi_host.h" -#include "ppapi/host/ppapi_host.h" - -PepperHelper::PepperHelper(content::RenderFrame* render_frame) - : RenderFrameObserver(render_frame) {} - -PepperHelper::~PepperHelper() {} - -void PepperHelper::DidCreatePepperPlugin(content::RendererPpapiHost* host) { - // TODO(brettw) figure out how to hook up the host factory. It needs some - // kind of filter-like system to allow dynamic additions. - host->GetPpapiHost()->AddHostFactoryFilter( - std::unique_ptr( - new ChromeRendererPepperHostFactory(host))); - host->GetPpapiHost()->AddInstanceMessageFilter( - std::unique_ptr( - new PepperSharedMemoryMessageFilter(host))); -} diff --git a/chromium_src/chrome/renderer/pepper/pepper_helper.h b/chromium_src/chrome/renderer/pepper/pepper_helper.h deleted file mode 100644 index b3e850b2481b0..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_helper.h +++ /dev/null @@ -1,25 +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_RENDERER_PEPPER_PEPPER_HELPER_H_ -#define CHROME_RENDERER_PEPPER_PEPPER_HELPER_H_ - -#include "base/compiler_specific.h" -#include "content/public/renderer/render_frame_observer.h" - -// This class listens for Pepper creation events from the RenderFrame and -// attaches the parts required for Chrome-specific plugin support. -class PepperHelper : public content::RenderFrameObserver { - public: - explicit PepperHelper(content::RenderFrame* render_frame); - ~PepperHelper() override; - - // RenderFrameObserver. - void DidCreatePepperPlugin(content::RendererPpapiHost* host) override; - - private: - DISALLOW_COPY_AND_ASSIGN(PepperHelper); -}; - -#endif // CHROME_RENDERER_PEPPER_PEPPER_HELPER_H_ diff --git a/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc b/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc deleted file mode 100644 index 9919fb47b03ff..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.cc +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 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. - -#include "chrome/renderer/pepper/pepper_shared_memory_message_filter.h" - -#include - -#include "base/memory/shared_memory.h" -#include "base/process/process_handle.h" -#include "content/public/common/content_client.h" -#include "content/public/renderer/pepper_plugin_instance.h" -#include "content/public/renderer/render_thread.h" -#include "content/public/renderer/renderer_ppapi_host.h" -#include "ppapi/host/ppapi_host.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/shared_impl/var_tracker.h" - -PepperSharedMemoryMessageFilter::PepperSharedMemoryMessageFilter( - content::RendererPpapiHost* host) - : InstanceMessageFilter(host->GetPpapiHost()), host_(host) {} - -PepperSharedMemoryMessageFilter::~PepperSharedMemoryMessageFilter() {} - -bool PepperSharedMemoryMessageFilter::OnInstanceMessageReceived( - const IPC::Message& msg) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PepperSharedMemoryMessageFilter, msg) - IPC_MESSAGE_HANDLER(PpapiHostMsg_SharedMemory_CreateSharedMemory, - OnHostMsgCreateSharedMemory) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -bool PepperSharedMemoryMessageFilter::Send(IPC::Message* msg) { - return host_->GetPpapiHost()->Send(msg); -} - -void PepperSharedMemoryMessageFilter::OnHostMsgCreateSharedMemory( - PP_Instance instance, - uint32_t size, - int* host_handle_id, - ppapi::proxy::SerializedHandle* plugin_handle) { - plugin_handle->set_null_shmem(); - *host_handle_id = -1; - std::unique_ptr shm( - content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(size)); - if (!shm.get()) - return; - - base::SharedMemoryHandle host_shm_handle; - shm->ShareToProcess(base::GetCurrentProcessHandle(), &host_shm_handle); - *host_handle_id = - content::PepperPluginInstance::Get(instance) - ->GetVarTracker() - ->TrackSharedMemoryHandle(instance, host_shm_handle, size); - - // We set auto_close to false since we need our file descriptor to - // actually be duplicated on linux. The shared memory destructor will - // close the original handle for us. - plugin_handle->set_shmem( - host_->ShareSharedMemoryHandleWithRemote(host_shm_handle), size); -} diff --git a/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.h b/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.h deleted file mode 100644 index 860e1c9dbd15e..0000000000000 --- a/chromium_src/chrome/renderer/pepper/pepper_shared_memory_message_filter.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 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_RENDERER_PEPPER_PEPPER_SHARED_MEMORY_MESSAGE_FILTER_H_ -#define CHROME_RENDERER_PEPPER_PEPPER_SHARED_MEMORY_MESSAGE_FILTER_H_ - -#include "ppapi/c/pp_instance.h" -#include "ppapi/host/instance_message_filter.h" - -namespace content { -class RendererPpapiHost; -} - -namespace ppapi { -namespace proxy { -class SerializedHandle; -} -} - -// Implements the backend for shared memory messages from a plugin process. -class PepperSharedMemoryMessageFilter - : public ppapi::host::InstanceMessageFilter { - public: - explicit PepperSharedMemoryMessageFilter(content::RendererPpapiHost* host); - ~PepperSharedMemoryMessageFilter() override; - - // InstanceMessageFilter: - bool OnInstanceMessageReceived(const IPC::Message& msg) override; - - bool Send(IPC::Message* msg); - - private: - // Message handlers. - void OnHostMsgCreateSharedMemory( - PP_Instance instance, - uint32_t size, - int* host_shm_handle_id, - ppapi::proxy::SerializedHandle* plugin_shm_handle); - - content::RendererPpapiHost* host_; - - DISALLOW_COPY_AND_ASSIGN(PepperSharedMemoryMessageFilter); -}; - -#endif // CHROME_RENDERER_PEPPER_PEPPER_SHARED_MEMORY_MESSAGE_FILTER_H_ diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc deleted file mode 100644 index 7ff3471f953a6..0000000000000 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc +++ /dev/null @@ -1,1449 +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/renderer/printing/print_web_view_helper.h" - -#include - -#include "base/auto_reset.h" -#include "base/command_line.h" -#include "base/json/json_writer.h" -#include "base/logging.h" -#include "base/message_loop/message_loop.h" -#include "base/metrics/histogram.h" -#include "base/process/process_handle.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/common/print_messages.h" -#include "content/public/common/web_preferences.h" -#include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_thread.h" -#include "content/public/renderer/render_view.h" -#include "net/base/escape.h" -#include "printing/pdf_metafile_skia.h" -#include "printing/units.h" -#include "third_party/WebKit/public/platform/WebSize.h" -#include "third_party/WebKit/public/platform/WebURLRequest.h" -#include "third_party/WebKit/public/web/WebConsoleMessage.h" -#include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebElement.h" -#include "third_party/WebKit/public/web/WebFrameClient.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebPlugin.h" -#include "third_party/WebKit/public/web/WebPluginDocument.h" -#include "third_party/WebKit/public/web/WebPrintParams.h" -#include "third_party/WebKit/public/web/WebPrintScalingOption.h" -#include "third_party/WebKit/public/web/WebScriptSource.h" -#include "third_party/WebKit/public/web/WebSettings.h" -#include "third_party/WebKit/public/web/WebView.h" -#include "third_party/WebKit/public/web/WebViewClient.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "ui/base/resource/resource_bundle.h" - -using content::WebPreferences; - -namespace printing { - -namespace { - -const double kMinDpi = 1.0; - -int GetDPI(const PrintMsg_Print_Params* print_params) { -#if defined(OS_MACOSX) - // On the Mac, the printable area is in points, don't do any scaling based - // on dpi. - return kPointsPerInch; -#else - return static_cast(print_params->dpi); -#endif // defined(OS_MACOSX) -} - -bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) { - return !params.content_size.IsEmpty() && !params.page_size.IsEmpty() && - !params.printable_area.IsEmpty() && params.document_cookie && - params.desired_dpi && params.dpi && params.margin_top >= 0 && - params.margin_left >= 0 && params.dpi > kMinDpi && - params.document_cookie != 0; -} - -PrintMsg_Print_Params GetCssPrintParams( - blink::WebFrame* frame, - int page_index, - const PrintMsg_Print_Params& page_params) { - PrintMsg_Print_Params page_css_params = page_params; - int dpi = GetDPI(&page_params); - - blink::WebSize page_size_in_pixels( - ConvertUnit(page_params.page_size.width(), dpi, kPixelsPerInch), - ConvertUnit(page_params.page_size.height(), dpi, kPixelsPerInch)); - int margin_top_in_pixels = - ConvertUnit(page_params.margin_top, dpi, kPixelsPerInch); - int margin_right_in_pixels = ConvertUnit( - page_params.page_size.width() - - page_params.content_size.width() - page_params.margin_left, - dpi, kPixelsPerInch); - int margin_bottom_in_pixels = ConvertUnit( - page_params.page_size.height() - - page_params.content_size.height() - page_params.margin_top, - dpi, kPixelsPerInch); - int margin_left_in_pixels = ConvertUnit( - page_params.margin_left, - dpi, kPixelsPerInch); - - blink::WebSize original_page_size_in_pixels = page_size_in_pixels; - - if (frame) { - frame->pageSizeAndMarginsInPixels(page_index, - page_size_in_pixels, - margin_top_in_pixels, - margin_right_in_pixels, - margin_bottom_in_pixels, - margin_left_in_pixels); - } - - int new_content_width = page_size_in_pixels.width - - margin_left_in_pixels - margin_right_in_pixels; - int new_content_height = page_size_in_pixels.height - - margin_top_in_pixels - margin_bottom_in_pixels; - - // Invalid page size and/or margins. We just use the default setting. - if (new_content_width < 1 || new_content_height < 1) { - CHECK(frame != NULL); - page_css_params = GetCssPrintParams(NULL, page_index, page_params); - return page_css_params; - } - - page_css_params.content_size = gfx::Size( - ConvertUnit(new_content_width, kPixelsPerInch, dpi), - ConvertUnit(new_content_height, kPixelsPerInch, dpi)); - - if (original_page_size_in_pixels != page_size_in_pixels) { - page_css_params.page_size = gfx::Size( - ConvertUnit(page_size_in_pixels.width, kPixelsPerInch, dpi), - ConvertUnit(page_size_in_pixels.height, kPixelsPerInch, dpi)); - } else { - // Printing frame doesn't have any page size css. Pixels to dpi conversion - // causes rounding off errors. Therefore use the default page size values - // directly. - page_css_params.page_size = page_params.page_size; - } - - page_css_params.margin_top = - ConvertUnit(margin_top_in_pixels, kPixelsPerInch, dpi); - page_css_params.margin_left = - ConvertUnit(margin_left_in_pixels, kPixelsPerInch, dpi); - return page_css_params; -} - -double FitPrintParamsToPage(const PrintMsg_Print_Params& page_params, - PrintMsg_Print_Params* params_to_fit) { - double content_width = - static_cast(params_to_fit->content_size.width()); - double content_height = - static_cast(params_to_fit->content_size.height()); - int default_page_size_height = page_params.page_size.height(); - int default_page_size_width = page_params.page_size.width(); - int css_page_size_height = params_to_fit->page_size.height(); - int css_page_size_width = params_to_fit->page_size.width(); - - double scale_factor = 1.0f; - if (page_params.page_size == params_to_fit->page_size) - return scale_factor; - - if (default_page_size_width < css_page_size_width || - default_page_size_height < css_page_size_height) { - double ratio_width = - static_cast(default_page_size_width) / css_page_size_width; - double ratio_height = - static_cast(default_page_size_height) / css_page_size_height; - scale_factor = ratio_width < ratio_height ? ratio_width : ratio_height; - content_width *= scale_factor; - content_height *= scale_factor; - } - params_to_fit->margin_top = static_cast( - (default_page_size_height - css_page_size_height * scale_factor) / 2 + - (params_to_fit->margin_top * scale_factor)); - params_to_fit->margin_left = static_cast( - (default_page_size_width - css_page_size_width * scale_factor) / 2 + - (params_to_fit->margin_left * scale_factor)); - params_to_fit->content_size = gfx::Size( - static_cast(content_width), static_cast(content_height)); - params_to_fit->page_size = page_params.page_size; - return scale_factor; -} - -void CalculatePageLayoutFromPrintParams( - const PrintMsg_Print_Params& params, - PageSizeMargins* page_layout_in_points) { - int dpi = GetDPI(¶ms); - int content_width = params.content_size.width(); - int content_height = params.content_size.height(); - - int margin_bottom = params.page_size.height() - - content_height - params.margin_top; - int margin_right = params.page_size.width() - - content_width - params.margin_left; - - page_layout_in_points->content_width = - ConvertUnit(content_width, dpi, kPointsPerInch); - page_layout_in_points->content_height = - ConvertUnit(content_height, dpi, kPointsPerInch); - page_layout_in_points->margin_top = - ConvertUnit(params.margin_top, dpi, kPointsPerInch); - page_layout_in_points->margin_right = - ConvertUnit(margin_right, dpi, kPointsPerInch); - page_layout_in_points->margin_bottom = - ConvertUnit(margin_bottom, dpi, kPointsPerInch); - page_layout_in_points->margin_left = - ConvertUnit(params.margin_left, dpi, kPointsPerInch); -} - -void EnsureOrientationMatches(const PrintMsg_Print_Params& css_params, - PrintMsg_Print_Params* page_params) { - if ((page_params->page_size.width() > page_params->page_size.height()) == - (css_params.page_size.width() > css_params.page_size.height())) { - return; - } - - // Swap the |width| and |height| values. - page_params->page_size.SetSize(page_params->page_size.height(), - page_params->page_size.width()); - page_params->content_size.SetSize(page_params->content_size.height(), - page_params->content_size.width()); - page_params->printable_area.set_size( - gfx::Size(page_params->printable_area.height(), - page_params->printable_area.width())); -} - -void ComputeWebKitPrintParamsInDesiredDpi( - const PrintMsg_Print_Params& print_params, - blink::WebPrintParams* webkit_print_params) { - int dpi = GetDPI(&print_params); - webkit_print_params->printerDPI = dpi; - webkit_print_params->printScalingOption = print_params.print_scaling_option; - - webkit_print_params->printContentArea.width = - ConvertUnit(print_params.content_size.width(), dpi, - print_params.desired_dpi); - webkit_print_params->printContentArea.height = - ConvertUnit(print_params.content_size.height(), dpi, - print_params.desired_dpi); - - webkit_print_params->printableArea.x = - ConvertUnit(print_params.printable_area.x(), dpi, - print_params.desired_dpi); - webkit_print_params->printableArea.y = - ConvertUnit(print_params.printable_area.y(), dpi, - print_params.desired_dpi); - webkit_print_params->printableArea.width = - ConvertUnit(print_params.printable_area.width(), dpi, - print_params.desired_dpi); - webkit_print_params->printableArea.height = - ConvertUnit(print_params.printable_area.height(), - dpi, print_params.desired_dpi); - - webkit_print_params->paperSize.width = - ConvertUnit(print_params.page_size.width(), dpi, - print_params.desired_dpi); - webkit_print_params->paperSize.height = - ConvertUnit(print_params.page_size.height(), dpi, - print_params.desired_dpi); -} - -blink::WebPlugin* GetPlugin(const blink::WebFrame* frame) { - return frame->document().isPluginDocument() ? - frame->document().to().plugin() : NULL; -} - -bool PrintingNodeOrPdfFrame(const blink::WebFrame* frame, - const blink::WebNode& node) { - if (!node.isNull()) - return true; - blink::WebPlugin* plugin = GetPlugin(frame); - return plugin && plugin->supportsPaginatedPrint(); -} - -MarginType GetMarginsForPdf(blink::WebFrame* frame, - const blink::WebNode& node) { - if (frame->isPrintScalingDisabledForPlugin(node)) - return NO_MARGINS; - else - return PRINTABLE_AREA_MARGINS; -} - -PrintMsg_Print_Params CalculatePrintParamsForCss( - blink::WebFrame* frame, - int page_index, - const PrintMsg_Print_Params& page_params, - bool ignore_css_margins, - bool fit_to_page, - double* scale_factor) { - PrintMsg_Print_Params css_params = GetCssPrintParams(frame, page_index, - page_params); - - PrintMsg_Print_Params params = page_params; - EnsureOrientationMatches(css_params, ¶ms); - - if (ignore_css_margins && fit_to_page) - return params; - - PrintMsg_Print_Params result_params = css_params; - if (ignore_css_margins) { - result_params.margin_top = params.margin_top; - result_params.margin_left = params.margin_left; - - DCHECK(!fit_to_page); - // Since we are ignoring the margins, the css page size is no longer - // valid. - int default_margin_right = params.page_size.width() - - params.content_size.width() - params.margin_left; - int default_margin_bottom = params.page_size.height() - - params.content_size.height() - params.margin_top; - result_params.content_size = gfx::Size( - result_params.page_size.width() - result_params.margin_left - - default_margin_right, - result_params.page_size.height() - result_params.margin_top - - default_margin_bottom); - } - - if (fit_to_page) { - double factor = FitPrintParamsToPage(params, &result_params); - if (scale_factor) - *scale_factor = factor; - } - return result_params; -} - -} // namespace - -FrameReference::FrameReference(blink::WebLocalFrame* frame) { - Reset(frame); -} - -FrameReference::FrameReference() { - Reset(NULL); -} - -FrameReference::~FrameReference() { -} - -void FrameReference::Reset(blink::WebLocalFrame* frame) { - if (frame) { - view_ = frame->view(); - frame_ = frame; - } else { - view_ = NULL; - frame_ = NULL; - } -} - -blink::WebLocalFrame* FrameReference::GetFrame() { - if (view_ == NULL || frame_ == NULL) - return NULL; - for (blink::WebFrame* frame = view_->mainFrame(); frame != NULL; - frame = frame->traverseNext(false)) { - if (frame == frame_) - return frame_; - } - return NULL; -} - -blink::WebView* FrameReference::view() { - return view_; -} - -// static - Not anonymous so that platform implementations can use it. -float PrintWebViewHelper::RenderPageContent(blink::WebFrame* frame, - int page_number, - const gfx::Rect& canvas_area, - const gfx::Rect& content_area, - double scale_factor, - blink::WebCanvas* canvas) { - SkAutoCanvasRestore auto_restore(canvas, true); - if (content_area != canvas_area) { - canvas->translate((content_area.x() - canvas_area.x()) / scale_factor, - (content_area.y() - canvas_area.y()) / scale_factor); - SkRect clip_rect( - SkRect::MakeXYWH(content_area.origin().x() / scale_factor, - content_area.origin().y() / scale_factor, - content_area.size().width() / scale_factor, - content_area.size().height() / scale_factor)); - SkIRect clip_int_rect; - clip_rect.roundOut(&clip_int_rect); - SkRegion clip_region(clip_int_rect); - canvas->setClipRegion(clip_region); - } - return frame->printPage(page_number, canvas); -} - -// Class that calls the Begin and End print functions on the frame and changes -// the size of the view temporarily to support full page printing.. -class PrepareFrameAndViewForPrint : public blink::WebViewClient, - public blink::WebFrameClient { - public: - PrepareFrameAndViewForPrint(const PrintMsg_Print_Params& params, - blink::WebLocalFrame* frame, - const blink::WebNode& node, - bool ignore_css_margins); - ~PrepareFrameAndViewForPrint() override; - - // Optional. Replaces |frame_| with selection if needed. Will call |on_ready| - // when completed. - void CopySelectionIfNeeded(const WebPreferences& preferences, - const base::Closure& on_ready); - - // Prepares frame for printing. - void StartPrinting(); - - blink::WebLocalFrame* frame() { - return frame_.GetFrame(); - } - - const blink::WebNode& node() const { - return node_to_print_; - } - - int GetExpectedPageCount() const { - return expected_pages_count_; - } - - void FinishPrinting(); - - bool IsLoadingSelection() { - // It's not selection if not |owns_web_view_|. - return owns_web_view_ && frame() && frame()->isLoading(); - } - - protected: - // blink::WebViewClient override: - void didStopLoading() override; - bool allowsBrokenNullLayerTreeView() const override; - - // blink::WebFrameClient: - blink::WebFrame* createChildFrame( - blink::WebLocalFrame* parent, - blink::WebTreeScopeType scope, - const blink::WebString& name, - const blink::WebString& unique_name, - blink::WebSandboxFlags sandbox_flags, - const blink::WebFrameOwnerProperties& frame_owner_properties) override; - void frameDetached(blink::WebFrame* frame, DetachType type) override; - - private: - void CallOnReady(); - void ResizeForPrinting(); - void RestoreSize(); - void CopySelection(const WebPreferences& preferences); - - base::WeakPtrFactory weak_ptr_factory_; - - FrameReference frame_; - blink::WebNode node_to_print_; - bool owns_web_view_; - blink::WebPrintParams web_print_params_; - gfx::Size prev_view_size_; - gfx::Size prev_scroll_offset_; - int expected_pages_count_; - base::Closure on_ready_; - bool should_print_backgrounds_; - bool should_print_selection_only_; - bool is_printing_started_; - - DISALLOW_COPY_AND_ASSIGN(PrepareFrameAndViewForPrint); -}; - -PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint( - const PrintMsg_Print_Params& params, - blink::WebLocalFrame* frame, - const blink::WebNode& node, - bool ignore_css_margins) - : weak_ptr_factory_(this), - frame_(frame), - node_to_print_(node), - owns_web_view_(false), - expected_pages_count_(0), - should_print_backgrounds_(params.should_print_backgrounds), - should_print_selection_only_(params.selection_only), - is_printing_started_(false) { - PrintMsg_Print_Params print_params = params; - if (!should_print_selection_only_ || - !PrintingNodeOrPdfFrame(frame, node_to_print_)) { - bool fit_to_page = ignore_css_margins && - print_params.print_scaling_option == - blink::WebPrintScalingOptionFitToPrintableArea; - ComputeWebKitPrintParamsInDesiredDpi(params, &web_print_params_); - frame->printBegin(web_print_params_, node_to_print_); - print_params = CalculatePrintParamsForCss(frame, 0, print_params, - ignore_css_margins, fit_to_page, - NULL); - frame->printEnd(); - } - ComputeWebKitPrintParamsInDesiredDpi(print_params, &web_print_params_); -} - -PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() { - FinishPrinting(); -} - -void PrepareFrameAndViewForPrint::ResizeForPrinting() { - // Layout page according to printer page size. Since WebKit shrinks the - // size of the page automatically (from 125% to 200%) we trick it to - // think the page is 125% larger so the size of the page is correct for - // minimum (default) scaling. - // This is important for sites that try to fill the page. - // The 1.25 value is |printingMinimumShrinkFactor|. - gfx::Size print_layout_size(web_print_params_.printContentArea.width, - web_print_params_.printContentArea.height); - print_layout_size.set_height( - static_cast(static_cast(print_layout_size.height()) * 1.25)); - - if (!frame()) - return; - blink::WebView* web_view = frame_.view(); - // Backup size and offset. - if (blink::WebFrame* web_frame = web_view->mainFrame()) - prev_scroll_offset_ = web_frame->scrollOffset(); - prev_view_size_ = web_view->size(); - - web_view->resize(print_layout_size); -} - - -void PrepareFrameAndViewForPrint::StartPrinting() { - ResizeForPrinting(); - blink::WebView* web_view = frame_.view(); - web_view->settings()->setShouldPrintBackgrounds(should_print_backgrounds_); - expected_pages_count_ = - frame()->printBegin(web_print_params_, node_to_print_); - is_printing_started_ = true; -} - -void PrepareFrameAndViewForPrint::CopySelectionIfNeeded( - const WebPreferences& preferences, - const base::Closure& on_ready) { - on_ready_ = on_ready; - if (should_print_selection_only_) { - CopySelection(preferences); - } else { - // Call immediately, async call crashes scripting printing. - CallOnReady(); - } -} - -void PrepareFrameAndViewForPrint::CopySelection( - const WebPreferences& preferences) { - ResizeForPrinting(); - std::string url_str = "data:text/html;charset=utf-8,"; - url_str.append( - net::EscapeQueryParamValue(frame()->selectionAsMarkup().utf8(), false)); - RestoreSize(); - // Create a new WebView with the same settings as the current display one. - // Except that we disable javascript (don't want any active content running - // on the page). - WebPreferences prefs = preferences; - prefs.javascript_enabled = false; - - blink::WebView* web_view = blink::WebView::create(this); - owns_web_view_ = true; - content::RenderView::ApplyWebPreferences(prefs, web_view); - web_view->setMainFrame( - blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, this)); - frame_.Reset(web_view->mainFrame()->toWebLocalFrame()); - node_to_print_.reset(); - - // When loading is done this will call didStopLoading() and that will do the - // actual printing. - frame()->loadRequest(blink::WebURLRequest(GURL(url_str))); -} - -bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const { - return true; -} - -void PrepareFrameAndViewForPrint::didStopLoading() { - DCHECK(!on_ready_.is_null()); - // Don't call callback here, because it can delete |this| and WebView that is - // called didStopLoading. - base::MessageLoop::current()->PostTask( - FROM_HERE, - base::Bind(&PrepareFrameAndViewForPrint::CallOnReady, - weak_ptr_factory_.GetWeakPtr())); -} - -blink::WebFrame* PrepareFrameAndViewForPrint::createChildFrame( - blink::WebLocalFrame* parent, - blink::WebTreeScopeType scope, - const blink::WebString& name, - const blink::WebString& unique_name, - blink::WebSandboxFlags sandbox_flags, - const blink::WebFrameOwnerProperties& frame_owner_properties) { - blink::WebFrame* frame = blink::WebLocalFrame::create(scope, this); - parent->appendChild(frame); - return frame; -} - -void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame* frame, - DetachType type) { - DCHECK(type == DetachType::Remove); - if (frame->parent()) - frame->parent()->removeChild(frame); - frame->close(); -} - -void PrepareFrameAndViewForPrint::CallOnReady() { - return on_ready_.Run(); // Can delete |this|. -} - -void PrepareFrameAndViewForPrint::RestoreSize() { - if (frame()) { - blink::WebView* web_view = frame_.GetFrame()->view(); - web_view->resize(prev_view_size_); - if (blink::WebFrame* web_frame = web_view->mainFrame()) - web_frame->setScrollOffset(prev_scroll_offset_); - } -} - -void PrepareFrameAndViewForPrint::FinishPrinting() { - blink::WebLocalFrame* frame = frame_.GetFrame(); - if (frame) { - blink::WebView* web_view = frame->view(); - if (is_printing_started_) { - is_printing_started_ = false; - frame->printEnd(); - if (!owns_web_view_) { - web_view->settings()->setShouldPrintBackgrounds(false); - RestoreSize(); - } - } - if (owns_web_view_) { - DCHECK(!frame->isLoading()); - owns_web_view_ = false; - web_view->close(); - } - } - frame_.Reset(NULL); - on_ready_.Reset(); -} - -PrintWebViewHelper::PrintWebViewHelper(content::RenderView* render_view) - : content::RenderViewObserver(render_view), - content::RenderViewObserverTracker(render_view), - reset_prep_frame_view_(false), - is_print_ready_metafile_sent_(false), - ignore_css_margins_(false), - is_scripted_printing_blocked_(false), - notify_browser_of_print_failure_(true), - print_for_preview_(false), - print_node_in_progress_(false), - is_loading_(false), - is_scripted_preview_delayed_(false), - weak_ptr_factory_(this) { -} - -PrintWebViewHelper::~PrintWebViewHelper() {} - -// Prints |frame| which called window.print(). -void PrintWebViewHelper::PrintPage(blink::WebLocalFrame* frame, - bool user_initiated) { - DCHECK(frame); - Print(frame, blink::WebNode()); -} - -bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message) - IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages) - IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone, OnPrintingDone) - IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview, OnPrintPreview) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame** frame) { - DCHECK(frame); - blink::WebView* webView = render_view()->GetWebView(); - DCHECK(webView); - if (!webView) - return false; - - // If the user has selected text in the currently focused frame we print - // only that frame (this makes print selection work for multiple frames). - blink::WebLocalFrame* focusedFrame = - webView->focusedFrame()->toWebLocalFrame(); - *frame = focusedFrame->hasSelection() - ? focusedFrame - : webView->mainFrame()->toWebLocalFrame(); - return true; -} - -#if !defined(DISABLE_BASIC_PRINTING) -void PrintWebViewHelper::OnPrintPages(bool silent, bool print_background) { - blink::WebLocalFrame* frame; - if (GetPrintFrame(&frame)) - Print(frame, blink::WebNode(), silent, print_background); -} -#endif // !DISABLE_BASIC_PRINTING - -void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout( - const PageSizeMargins& page_layout_in_points, - gfx::Size* page_size, - gfx::Rect* content_area) { - *page_size = gfx::Size( - page_layout_in_points.content_width + - page_layout_in_points.margin_right + - page_layout_in_points.margin_left, - page_layout_in_points.content_height + - page_layout_in_points.margin_top + - page_layout_in_points.margin_bottom); - *content_area = gfx::Rect(page_layout_in_points.margin_left, - page_layout_in_points.margin_top, - page_layout_in_points.content_width, - page_layout_in_points.content_height); -} - -void PrintWebViewHelper::UpdateFrameMarginsCssInfo( - const base::DictionaryValue& settings) { - int margins_type = 0; - if (!settings.GetInteger(kSettingMarginsType, &margins_type)) - margins_type = DEFAULT_MARGINS; - ignore_css_margins_ = (margins_type != DEFAULT_MARGINS); -} - -void PrintWebViewHelper::OnPrintingDone(bool success) { - notify_browser_of_print_failure_ = false; - if (!success) - LOG(ERROR) << "Failure in OnPrintingDone"; - DidFinishPrinting(success ? OK : FAIL_PRINT); -} - -void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) { - blink::WebLocalFrame* frame; - if (GetPrintFrame(&frame)) { - print_preview_context_.InitWithFrame(frame); - if (!print_preview_context_.source_frame()) { - DidFinishPrinting(FAIL_PREVIEW); - return; - } - - if (!UpdatePrintSettings(print_preview_context_.source_frame(), - print_preview_context_.source_node(), settings)) { - DidFinishPrinting(FAIL_PREVIEW); - return; - } - is_print_ready_metafile_sent_ = false; - PrepareFrameForPreviewDocument(); - } -} - -void PrintWebViewHelper::PrepareFrameForPreviewDocument() { - reset_prep_frame_view_ = false; - - if (!print_pages_params_) { - DidFinishPrinting(FAIL_PREVIEW); - return; - } - - // Don't reset loading frame or WebKit will fail assert. Just retry when - // current selection is loaded. - if (prep_frame_view_ && prep_frame_view_->IsLoadingSelection()) { - reset_prep_frame_view_ = true; - return; - } - - const PrintMsg_Print_Params& print_params = print_pages_params_->params; - prep_frame_view_.reset(new PrepareFrameAndViewForPrint( - print_params, print_preview_context_.source_frame(), - print_preview_context_.source_node(), ignore_css_margins_)); - prep_frame_view_->CopySelectionIfNeeded( - render_view()->GetWebkitPreferences(), - base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument, - base::Unretained(this))); -} - -void PrintWebViewHelper::OnFramePreparedForPreviewDocument() { - if (reset_prep_frame_view_) { - PrepareFrameForPreviewDocument(); - return; - } - DidFinishPrinting(CreatePreviewDocument() ? OK : FAIL_PREVIEW); -} - -bool PrintWebViewHelper::CreatePreviewDocument() { - if (!print_pages_params_) - return false; - - const PrintMsg_Print_Params& print_params = print_pages_params_->params; - const std::vector& pages = print_pages_params_->pages; - - if (!print_preview_context_.CreatePreviewDocument(prep_frame_view_.release(), - pages)) { - return false; - } - - while (!print_preview_context_.IsFinalPageRendered()) { - int page_number = print_preview_context_.GetNextPageNumber(); - DCHECK_GE(page_number, 0); - if (!RenderPreviewPage(page_number, print_params)) - return false; - - // We must call PrepareFrameAndViewForPrint::FinishPrinting() (by way of - // print_preview_context_.AllPagesRendered()) before calling - // FinalizePrintReadyDocument() when printing a PDF because the plugin - // code does not generate output until we call FinishPrinting(). We do not - // generate draft pages for PDFs, so IsFinalPageRendered() and - // IsLastPageOfPrintReadyMetafile() will be true in the same iteration of - // the loop. - if (print_preview_context_.IsFinalPageRendered()) - print_preview_context_.AllPagesRendered(); - - if (print_preview_context_.IsLastPageOfPrintReadyMetafile()) { - DCHECK(print_preview_context_.IsModifiable() || - print_preview_context_.IsFinalPageRendered()); - if (!FinalizePrintReadyDocument()) - return false; - } - } - print_preview_context_.Finished(); - return true; -} - -bool PrintWebViewHelper::FinalizePrintReadyDocument() { - DCHECK(!is_print_ready_metafile_sent_); - print_preview_context_.FinalizePrintReadyDocument(); - - PdfMetafileSkia* metafile = print_preview_context_.metafile(); - - PrintHostMsg_DidPreviewDocument_Params preview_params; - - // Ask the browser to create the shared memory for us. - if (!CopyMetafileDataToSharedMem(*metafile, - &(preview_params.metafile_data_handle))) { - LOG(ERROR) << "CopyMetafileDataToSharedMem failed"; - print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED); - return false; - } - - preview_params.data_size = metafile->GetDataSize(); - preview_params.document_cookie = print_pages_params_->params.document_cookie; - preview_params.expected_pages_count = - print_preview_context_.total_page_count(); - preview_params.modifiable = print_preview_context_.IsModifiable(); - preview_params.preview_request_id = - print_pages_params_->params.preview_request_id; - - is_print_ready_metafile_sent_ = true; - - Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params)); - return true; -} - -void PrintWebViewHelper::PrintNode(const blink::WebNode& node) { - if (node.isNull() || !node.document().frame()) { - // This can occur when the context menu refers to an invalid WebNode. - // See http://crbug.com/100890#c17 for a repro case. - return; - } - - if (print_node_in_progress_) { - // This can happen as a result of processing sync messages when printing - // from ppapi plugins. It's a rare case, so its OK to just fail here. - // See http://crbug.com/159165. - return; - } - - print_node_in_progress_ = true; - blink::WebNode duplicate_node(node); - Print(duplicate_node.document().frame(), duplicate_node); - - print_node_in_progress_ = false; -} - -void PrintWebViewHelper::Print(blink::WebLocalFrame* frame, - const blink::WebNode& node, - bool silent, - bool print_background) { - // If still not finished with earlier print request simply ignore. - if (prep_frame_view_) - return; - - FrameReference frame_ref(frame); - - int expected_page_count = 0; - if (!CalculateNumberOfPages(frame, node, &expected_page_count)) { - DidFinishPrinting(FAIL_PRINT_INIT); - return; // Failed to init print page settings. - } - - // Some full screen plugins can say they don't want to print. - if (!expected_page_count) { - DidFinishPrinting(FAIL_PRINT); - return; - } - - // Ask the browser to show UI to retrieve the final print settings. - if (!silent && !GetPrintSettingsFromUser(frame_ref.GetFrame(), node, - expected_page_count)) { - DidFinishPrinting(OK); // Release resources and fail silently. - return; - } - - print_pages_params_->params.should_print_backgrounds = print_background; - - // Render Pages for printing. - if (!RenderPagesForPrint(frame_ref.GetFrame(), node)) { - LOG(ERROR) << "RenderPagesForPrint failed"; - DidFinishPrinting(FAIL_PRINT); - } -} - -void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) { - switch (result) { - case OK: - break; - - case FAIL_PRINT_INIT: - DCHECK(!notify_browser_of_print_failure_); - break; - - case FAIL_PRINT: - if (notify_browser_of_print_failure_ && print_pages_params_) { - int cookie = print_pages_params_->params.document_cookie; - Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie)); - } - break; - - case FAIL_PREVIEW: - LOG(ERROR) << "PREVIEW FAILED."; - if (print_pages_params_) { - Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), - print_pages_params_->params.document_cookie, - print_pages_params_->params.preview_request_id)); - } - break; - } - prep_frame_view_.reset(); - print_pages_params_.reset(); - notify_browser_of_print_failure_ = true; -} - -void PrintWebViewHelper::OnFramePreparedForPrintPages() { - PrintPages(); - FinishFramePrinting(); -} - -void PrintWebViewHelper::PrintPages() { - if (!prep_frame_view_) // Printing is already canceled or failed. - return; - prep_frame_view_->StartPrinting(); - - int page_count = prep_frame_view_->GetExpectedPageCount(); - if (!page_count) { - LOG(ERROR) << "Can't print 0 pages."; - return DidFinishPrinting(FAIL_PRINT); - } - - const PrintMsg_PrintPages_Params& params = *print_pages_params_; - const PrintMsg_Print_Params& print_params = params.params; - -#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) - // TODO(vitalybuka): should be page_count or valid pages from params.pages. - // See http://crbug.com/161576 - Send(new PrintHostMsg_DidGetPrintedPagesCount(routing_id(), - print_params.document_cookie, - page_count)); -#endif // !defined(OS_CHROMEOS) - - if (!PrintPagesNative(prep_frame_view_->frame(), page_count)) { - LOG(ERROR) << "Printing failed."; - return DidFinishPrinting(FAIL_PRINT); - } -} - -void PrintWebViewHelper::FinishFramePrinting() { - prep_frame_view_.reset(); -} - -#if defined(OS_MACOSX) -bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, - int page_count) { - const PrintMsg_PrintPages_Params& params = *print_pages_params_; - const PrintMsg_Print_Params& print_params = params.params; - - PrintMsg_PrintPage_Params page_params; - page_params.params = print_params; - if (params.pages.empty()) { - for (int i = 0; i < page_count; ++i) { - page_params.page_number = i; - PrintPageInternal(page_params, frame); - } - } else { - for (size_t i = 0; i < params.pages.size(); ++i) { - if (params.pages[i] >= page_count) - break; - page_params.page_number = params.pages[i]; - PrintPageInternal(page_params, frame); - } - } - return true; -} - -#endif // OS_MACOSX - -// static - Not anonymous so that platform implementations can use it. -void PrintWebViewHelper::ComputePageLayoutInPointsForCss( - blink::WebFrame* frame, - int page_index, - const PrintMsg_Print_Params& page_params, - bool ignore_css_margins, - double* scale_factor, - PageSizeMargins* page_layout_in_points) { - PrintMsg_Print_Params params = CalculatePrintParamsForCss( - frame, page_index, page_params, ignore_css_margins, - page_params.print_scaling_option == - blink::WebPrintScalingOptionFitToPrintableArea, - scale_factor); - CalculatePageLayoutFromPrintParams(params, page_layout_in_points); -} - -bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) { - PrintMsg_PrintPages_Params settings; - Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(), - &settings.params)); - // Check if the printer returned any settings, if the settings is empty, we - // can safely assume there are no printer drivers configured. So we safely - // terminate. - bool result = true; - if (!PrintMsg_Print_Params_IsValid(settings.params)) - result = false; - - // Reset to default values. - ignore_css_margins_ = false; - settings.pages.clear(); - - settings.params.print_scaling_option = - blink::WebPrintScalingOptionSourceSize; - if (fit_to_paper_size) { - settings.params.print_scaling_option = - blink::WebPrintScalingOptionFitToPrintableArea; - } - - SetPrintPagesParams(settings); - return result; -} - -bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame, - const blink::WebNode& node, - int* number_of_pages) { - DCHECK(frame); - bool fit_to_paper_size = !(PrintingNodeOrPdfFrame(frame, node)); - if (!InitPrintSettings(fit_to_paper_size)) { - notify_browser_of_print_failure_ = false; - Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id())); - return false; - } - - const PrintMsg_Print_Params& params = print_pages_params_->params; - PrepareFrameAndViewForPrint prepare(params, frame, node, ignore_css_margins_); - prepare.StartPrinting(); - - *number_of_pages = prepare.GetExpectedPageCount(); - return true; -} - -bool PrintWebViewHelper::UpdatePrintSettings( - blink::WebLocalFrame* frame, - const blink::WebNode& node, - const base::DictionaryValue& passed_job_settings) { - const base::DictionaryValue* job_settings = &passed_job_settings; - base::DictionaryValue modified_job_settings; - if (job_settings->empty()) { - if (!print_for_preview_) - print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING); - return false; - } - - bool source_is_html = true; - if (print_for_preview_) { - if (!job_settings->GetBoolean(kSettingPreviewModifiable, &source_is_html)) { - NOTREACHED(); - } - } else { - source_is_html = !PrintingNodeOrPdfFrame(frame, node); - } - - if (print_for_preview_ || !source_is_html) { - modified_job_settings.MergeDictionary(job_settings); - modified_job_settings.SetBoolean(kSettingHeaderFooterEnabled, false); - modified_job_settings.SetInteger(kSettingMarginsType, NO_MARGINS); - job_settings = &modified_job_settings; - } - - // Send the cookie so that UpdatePrintSettings can reuse PrinterQuery when - // possible. - int cookie = - print_pages_params_ ? print_pages_params_->params.document_cookie : 0; - PrintMsg_PrintPages_Params settings; - bool canceled = false; - Send(new PrintHostMsg_UpdatePrintSettings(routing_id(), cookie, *job_settings, - &settings, &canceled)); - if (canceled) { - notify_browser_of_print_failure_ = false; - return false; - } - - if (!print_for_preview_) { - job_settings->GetInteger(kPreviewRequestID, - &settings.params.preview_request_id); - settings.params.print_to_pdf = true; - UpdateFrameMarginsCssInfo(*job_settings); - settings.params.print_scaling_option = - blink::WebPrintScalingOptionSourceSize; - } - - SetPrintPagesParams(settings); - - if (!PrintMsg_Print_Params_IsValid(settings.params)) { - if (!print_for_preview_) - print_preview_context_.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS); - return false; - } - - return true; -} - - -bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame* frame, - const blink::WebNode& node, - int expected_pages_count) { - PrintHostMsg_ScriptedPrint_Params params; - PrintMsg_PrintPages_Params print_settings; - - params.cookie = print_pages_params_->params.document_cookie; - params.has_selection = frame->hasSelection(); - params.expected_pages_count = expected_pages_count; - MarginType margin_type = DEFAULT_MARGINS; - if (PrintingNodeOrPdfFrame(frame, node)) - margin_type = GetMarginsForPdf(frame, node); - params.margin_type = margin_type; - - // PrintHostMsg_ScriptedPrint will reset print_scaling_option, so we save the - // value before and restore it afterwards. - blink::WebPrintScalingOption scaling_option = - print_pages_params_->params.print_scaling_option; - - print_pages_params_.reset(); - IPC::SyncMessage* msg = - new PrintHostMsg_ScriptedPrint(routing_id(), params, &print_settings); - msg->EnableMessagePumping(); - Send(msg); - print_settings.params.print_scaling_option = scaling_option; - SetPrintPagesParams(print_settings); - return (print_settings.params.dpi && print_settings.params.document_cookie); -} - -bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame, - const blink::WebNode& node) { - if (!frame || prep_frame_view_) - return false; - const PrintMsg_PrintPages_Params& params = *print_pages_params_; - const PrintMsg_Print_Params& print_params = params.params; - prep_frame_view_.reset(new PrepareFrameAndViewForPrint( - print_params, frame, node, ignore_css_margins_)); - DCHECK(!print_pages_params_->params.selection_only || - print_pages_params_->pages.empty()); - prep_frame_view_->CopySelectionIfNeeded( - render_view()->GetWebkitPreferences(), - base::Bind(&PrintWebViewHelper::OnFramePreparedForPrintPages, - base::Unretained(this))); - return true; -} - -#if defined(OS_POSIX) -bool PrintWebViewHelper::CopyMetafileDataToSharedMem( - const PdfMetafileSkia& metafile, - base::SharedMemoryHandle* shared_mem_handle) { - uint32_t buf_size = metafile.GetDataSize(); - if (buf_size == 0) - return false; - - std::unique_ptr shared_buf( - content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(buf_size)); - if (!shared_buf) - return false; - - if (!shared_buf->Map(buf_size)) - return false; - - if (!metafile.GetData(shared_buf->memory(), buf_size)) - return false; - - return shared_buf->GiveToProcess(base::GetCurrentProcessHandle(), - shared_mem_handle); -} -#endif // defined(OS_POSIX) - -void PrintWebViewHelper::SetPrintPagesParams( - const PrintMsg_PrintPages_Params& settings) { - print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings)); -} - -bool PrintWebViewHelper::PreviewPageRendered(int page_number, - PdfMetafileSkia* metafile) { - DCHECK_GE(page_number, FIRST_PAGE_INDEX); - - // For non-modifiable files, |metafile| should be NULL, so do not bother - // sending a message. If we don't generate draft metafiles, |metafile| is - // NULL. - if (!print_preview_context_.IsModifiable() || - !print_preview_context_.generate_draft_pages()) { - DCHECK(!metafile); - return true; - } - - if (!metafile) { - NOTREACHED(); - print_preview_context_.set_error( - PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE); - return false; - } - - return true; -} - -PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext() - : total_page_count_(0), - current_page_index_(0), - generate_draft_pages_(true), - print_ready_metafile_page_count_(0), - error_(PREVIEW_ERROR_NONE), - state_(UNINITIALIZED) { -} - -PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() { -} - -void PrintWebViewHelper::PrintPreviewContext::InitWithFrame( - blink::WebLocalFrame* web_frame) { - DCHECK(web_frame); - DCHECK(!IsRendering()); - state_ = INITIALIZED; - source_frame_.Reset(web_frame); - source_node_.reset(); -} - -void PrintWebViewHelper::PrintPreviewContext::InitWithNode( - const blink::WebNode& web_node) { - DCHECK(!web_node.isNull()); - DCHECK(web_node.document().frame()); - DCHECK(!IsRendering()); - state_ = INITIALIZED; - source_frame_.Reset(web_node.document().frame()); - source_node_ = web_node; -} - -void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() { - DCHECK_EQ(INITIALIZED, state_); - ClearContext(); -} - -bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument( - PrepareFrameAndViewForPrint* prepared_frame, - const std::vector& pages) { - DCHECK_EQ(INITIALIZED, state_); - state_ = RENDERING; - - // Need to make sure old object gets destroyed first. - prep_frame_view_.reset(prepared_frame); - prep_frame_view_->StartPrinting(); - - total_page_count_ = prep_frame_view_->GetExpectedPageCount(); - if (total_page_count_ == 0) { - LOG(ERROR) << "CreatePreviewDocument got 0 page count"; - set_error(PREVIEW_ERROR_ZERO_PAGES); - return false; - } - - metafile_.reset(new PdfMetafileSkia); - CHECK(metafile_->Init()); - - current_page_index_ = 0; - pages_to_render_ = pages; - // Sort and make unique. - std::sort(pages_to_render_.begin(), pages_to_render_.end()); - pages_to_render_.resize( - std::unique(pages_to_render_.begin(), pages_to_render_.end()) - - pages_to_render_.begin()); - // Remove invalid pages. - pages_to_render_.resize(std::lower_bound(pages_to_render_.begin(), - pages_to_render_.end(), - total_page_count_) - - pages_to_render_.begin()); - print_ready_metafile_page_count_ = pages_to_render_.size(); - if (pages_to_render_.empty()) { - print_ready_metafile_page_count_ = total_page_count_; - // Render all pages. - for (int i = 0; i < total_page_count_; ++i) - pages_to_render_.push_back(i); - } else if (generate_draft_pages_) { - int pages_index = 0; - for (int i = 0; i < total_page_count_; ++i) { - if (pages_index < print_ready_metafile_page_count_ && - i == pages_to_render_[pages_index]) { - pages_index++; - continue; - } - pages_to_render_.push_back(i); - } - } - - document_render_time_ = base::TimeDelta(); - begin_time_ = base::TimeTicks::Now(); - - return true; -} - -void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage( - const base::TimeDelta& page_time) { - DCHECK_EQ(RENDERING, state_); - document_render_time_ += page_time; - UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time); -} - -void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() { - DCHECK_EQ(RENDERING, state_); - state_ = DONE; - prep_frame_view_->FinishPrinting(); -} - -void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() { - DCHECK(IsRendering()); - - base::TimeTicks begin_time = base::TimeTicks::Now(); - metafile_->FinishDocument(); - - if (print_ready_metafile_page_count_ <= 0) { - NOTREACHED(); - return; - } - - UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime", - document_render_time_); - base::TimeDelta total_time = - (base::TimeTicks::Now() - begin_time) + document_render_time_; - UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime", - total_time); - UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage", - total_time / pages_to_render_.size()); -} - -void PrintWebViewHelper::PrintPreviewContext::Finished() { - DCHECK_EQ(DONE, state_); - state_ = INITIALIZED; - ClearContext(); -} - -void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error) { - DCHECK(state_ == INITIALIZED || state_ == RENDERING); - state_ = INITIALIZED; - if (report_error) { - DCHECK_NE(PREVIEW_ERROR_NONE, error_); - UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_, - PREVIEW_ERROR_LAST_ENUM); - } - ClearContext(); -} - -int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() { - DCHECK_EQ(RENDERING, state_); - if (IsFinalPageRendered()) - return -1; - return pages_to_render_[current_page_index_++]; -} - -bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const { - return state_ == RENDERING || state_ == DONE; -} - -bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() { - // The only kind of node we can print right now is a PDF node. - return !PrintingNodeOrPdfFrame(source_frame(), source_node_); -} - -bool PrintWebViewHelper::PrintPreviewContext::HasSelection() { - return IsModifiable() && source_frame()->hasSelection(); -} - -bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile() - const { - DCHECK(IsRendering()); - return current_page_index_ == print_ready_metafile_page_count_; -} - -bool PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const { - DCHECK(IsRendering()); - return static_cast(current_page_index_) == pages_to_render_.size(); -} - -void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages( - bool generate_draft_pages) { - DCHECK_EQ(INITIALIZED, state_); - generate_draft_pages_ = generate_draft_pages; -} - -void PrintWebViewHelper::PrintPreviewContext::set_error( - enum PrintPreviewErrorBuckets error) { - error_ = error; -} - -blink::WebLocalFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() { - DCHECK(state_ != UNINITIALIZED); - return source_frame_.GetFrame(); -} - -const blink::WebNode& - PrintWebViewHelper::PrintPreviewContext::source_node() const { - DCHECK(state_ != UNINITIALIZED); - return source_node_; -} - -blink::WebLocalFrame* -PrintWebViewHelper::PrintPreviewContext::prepared_frame() { - DCHECK(state_ != UNINITIALIZED); - return prep_frame_view_->frame(); -} - -const blink::WebNode& - PrintWebViewHelper::PrintPreviewContext::prepared_node() const { - DCHECK(state_ != UNINITIALIZED); - return prep_frame_view_->node(); -} - -int PrintWebViewHelper::PrintPreviewContext::total_page_count() const { - DCHECK(state_ != UNINITIALIZED); - return total_page_count_; -} - -bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() const { - return generate_draft_pages_; -} - -PdfMetafileSkia* PrintWebViewHelper::PrintPreviewContext::metafile() { - DCHECK(IsRendering()); - return metafile_.get(); -} - -int PrintWebViewHelper::PrintPreviewContext::last_error() const { - return error_; -} - -void PrintWebViewHelper::PrintPreviewContext::ClearContext() { - prep_frame_view_.reset(); - metafile_.reset(); - pages_to_render_.clear(); - error_ = PREVIEW_ERROR_NONE; -} - -} // namespace printing diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.h b/chromium_src/chrome/renderer/printing/print_web_view_helper.h deleted file mode 100644 index 0a00f2ebb1a1f..0000000000000 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.h +++ /dev/null @@ -1,392 +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_RENDERER_PRINTING_PRINT_WEB_VIEW_HELPER_H_ -#define CHROME_RENDERER_PRINTING_PRINT_WEB_VIEW_HELPER_H_ - -#include -#include - -#include "base/callback.h" -#include "base/gtest_prod_util.h" -#include "base/memory/shared_memory.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" -#include "content/public/renderer/render_view_observer.h" -#include "content/public/renderer/render_view_observer_tracker.h" -#include "printing/pdf_metafile_skia.h" -#include "third_party/WebKit/public/platform/WebCanvas.h" -#include "third_party/WebKit/public/web/WebNode.h" -#include "third_party/WebKit/public/web/WebPrintParams.h" -#include "ui/gfx/geometry/size.h" - -struct PrintMsg_Print_Params; -struct PrintMsg_PrintPage_Params; -struct PrintMsg_PrintPages_Params; -struct PrintHostMsg_SetOptionsFromDocument_Params; - -namespace base { -class DictionaryValue; -} - -namespace blink { -class WebFrame; -class WebView; -} - -namespace printing { - -struct PageSizeMargins; -class PrepareFrameAndViewForPrint; - -// Stores reference to frame using WebVew and unique name. -// Workaround to modal dialog issue on Linux. crbug.com/236147. -// If WebFrame someday supports WeakPtr, we should use it here. -class FrameReference { - public: - explicit FrameReference(blink::WebLocalFrame* frame); - FrameReference(); - ~FrameReference(); - - void Reset(blink::WebLocalFrame* frame); - - blink::WebLocalFrame* GetFrame(); - blink::WebView* view(); - - private: - blink::WebView* view_; - blink::WebLocalFrame* frame_; -}; - -// PrintWebViewHelper handles most of the printing grunt work for RenderView. -// We plan on making print asynchronous and that will require copying the DOM -// of the document and creating a new WebView with the contents. -class PrintWebViewHelper - : public content::RenderViewObserver, - public content::RenderViewObserverTracker { - public: - explicit PrintWebViewHelper(content::RenderView* render_view); - virtual ~PrintWebViewHelper(); - - void PrintNode(const blink::WebNode& node); - - private: - enum PrintingResult { - OK, - FAIL_PRINT_INIT, - FAIL_PRINT, - FAIL_PREVIEW, - }; - - enum PrintPreviewErrorBuckets { - PREVIEW_ERROR_NONE, // Always first. - PREVIEW_ERROR_BAD_SETTING, - PREVIEW_ERROR_METAFILE_COPY_FAILED, - PREVIEW_ERROR_METAFILE_INIT_FAILED_DEPRECATED, - PREVIEW_ERROR_ZERO_PAGES, - PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED_DEPRECATED, - PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE, - PREVIEW_ERROR_INVALID_PRINTER_SETTINGS, - PREVIEW_ERROR_LAST_ENUM // Always last. - }; - - // RenderViewObserver implementation. - virtual bool OnMessageReceived(const IPC::Message& message) override; - virtual void PrintPage(blink::WebLocalFrame* frame, - bool user_initiated) override; - - // Message handlers --------------------------------------------------------- -#if !defined(DISABLE_BASIC_PRINTING) - void OnPrintPages(bool silent, bool print_background); - void OnPrintingDone(bool success); -#endif // !DISABLE_BASIC_PRINTING - void OnPrintPreview(const base::DictionaryValue& settings); - - - // Get |page_size| and |content_area| information from - // |page_layout_in_points|. - void GetPageSizeAndContentAreaFromPageLayout( - const PageSizeMargins& page_layout_in_points, - gfx::Size* page_size, - gfx::Rect* content_area); - - // Update |ignore_css_margins_| based on settings. - void UpdateFrameMarginsCssInfo(const base::DictionaryValue& settings); - - // Prepare frame for creating preview document. - void PrepareFrameForPreviewDocument(); - - // Continue creating preview document. - void OnFramePreparedForPreviewDocument(); - - // Finalize the print ready preview document. - bool FinalizePrintReadyDocument(); - - // Renders a print preview page. |page_number| is 0-based. - // Returns true if print preview should continue, false on failure. - bool RenderPreviewPage(int page_number, - const PrintMsg_Print_Params& print_params); - - - // Initialize the print preview document. - bool CreatePreviewDocument(); - - // Main printing code ------------------------------------------------------- - - void Print(blink::WebLocalFrame* frame, - const blink::WebNode& node, - bool silent = false, - bool print_background = false); - - // Notification when printing is done - signal tear-down/free resources. - void DidFinishPrinting(PrintingResult result); - - // Print Settings ----------------------------------------------------------- - - // Initialize print page settings with default settings. - // Used only for native printing workflow. - bool InitPrintSettings(bool fit_to_paper_size); - - // Calculate number of pages in source document. - bool CalculateNumberOfPages(blink::WebLocalFrame* frame, - const blink::WebNode& node, - int* number_of_pages); - - // Update the current print settings with new |passed_job_settings|. - // |passed_job_settings| dictionary contains print job details such as printer - // name, number of copies, page range, etc. - bool UpdatePrintSettings(blink::WebLocalFrame* frame, - const blink::WebNode& node, - const base::DictionaryValue& passed_job_settings); - - - // Get final print settings from the user. - // Return false if the user cancels or on error. - bool GetPrintSettingsFromUser(blink::WebFrame* frame, - const blink::WebNode& node, - int expected_pages_count); - - // Page Printing / Rendering ------------------------------------------------ - - void OnFramePreparedForPrintPages(); - void PrintPages(); - bool PrintPagesNative(blink::WebFrame* frame, int page_count); - void FinishFramePrinting(); - - // Prints the page listed in |params|. -#if defined(OS_LINUX) || defined(OS_ANDROID) - void PrintPageInternal(const PrintMsg_PrintPage_Params& params, - blink::WebFrame* frame, - PdfMetafileSkia* metafile); -#elif defined(OS_WIN) - void PrintPageInternal(const PrintMsg_PrintPage_Params& params, - blink::WebFrame* frame, - PdfMetafileSkia* metafile, - gfx::Size* page_size_in_dpi, - gfx::Rect* content_area_in_dpi); -#else - void PrintPageInternal(const PrintMsg_PrintPage_Params& params, - blink::WebFrame* frame); -#endif - - // Render the frame for printing. - bool RenderPagesForPrint(blink::WebLocalFrame* frame, - const blink::WebNode& node); - - // Platform specific helper function for rendering page(s) to |metafile|. -#if defined(OS_MACOSX) - void RenderPage(const PrintMsg_Print_Params& params, - int page_number, - blink::WebFrame* frame, - bool is_preview, - PdfMetafileSkia* metafile, - gfx::Size* page_size, - gfx::Rect* content_rect); -#endif // defined(OS_MACOSX) - - // Renders page contents from |frame| to |content_area| of |canvas|. - // |page_number| is zero-based. - // When method is called, canvas should be setup to draw to |canvas_area| - // with |scale_factor|. - static float RenderPageContent(blink::WebFrame* frame, - int page_number, - const gfx::Rect& canvas_area, - const gfx::Rect& content_area, - double scale_factor, - blink::WebCanvas* canvas); - - // Helper methods ----------------------------------------------------------- - - bool CopyMetafileDataToSharedMem(const PdfMetafileSkia& metafile, - base::SharedMemoryHandle* shared_mem_handle); - - // Helper method to get page layout in points and fit to page if needed. - static void ComputePageLayoutInPointsForCss( - blink::WebFrame* frame, - int page_index, - const PrintMsg_Print_Params& default_params, - bool ignore_css_margins, - double* scale_factor, - PageSizeMargins* page_layout_in_points); - - bool GetPrintFrame(blink::WebLocalFrame** frame); - - // Script Initiated Printing ------------------------------------------------ - - // Notifies the browser a print preview page has been rendered. - // |page_number| is 0-based. - // For a valid |page_number| with modifiable content, - // |metafile| is the rendered page. Otherwise |metafile| is NULL. - // Returns true if print preview should continue, false on failure. - bool PreviewPageRendered(int page_number, PdfMetafileSkia* metafile); - - void SetPrintPagesParams(const PrintMsg_PrintPages_Params& settings); - - // WebView used only to print the selection. - std::unique_ptr prep_frame_view_; - bool reset_prep_frame_view_; - - std::unique_ptr print_pages_params_; - bool is_print_ready_metafile_sent_; - bool ignore_css_margins_; - - // Used for scripted initiated printing blocking. - bool is_scripted_printing_blocked_; - - // Let the browser process know of a printing failure. Only set to false when - // the failure came from the browser in the first place. - bool notify_browser_of_print_failure_; - - // True, when printing from print preview. - bool print_for_preview_; - - // Keeps track of the state of print preview between messages. - // TODO(vitalybuka): Create PrintPreviewContext when needed and delete after - // use. Now it's interaction with various messages is confusing. - class PrintPreviewContext { - public: - PrintPreviewContext(); - ~PrintPreviewContext(); - - // Initializes the print preview context. Need to be called to set - // the |web_frame| / |web_node| to generate the print preview for. - void InitWithFrame(blink::WebLocalFrame* web_frame); - void InitWithNode(const blink::WebNode& web_node); - - // Does bookkeeping at the beginning of print preview. - void OnPrintPreview(); - - // Create the print preview document. |pages| is empty to print all pages. - // Takes ownership of |prepared_frame|. - bool CreatePreviewDocument(PrepareFrameAndViewForPrint* prepared_frame, - const std::vector& pages); - - // Called after a page gets rendered. |page_time| is how long the - // rendering took. - void RenderedPreviewPage(const base::TimeDelta& page_time); - - // Updates the print preview context when the required pages are rendered. - void AllPagesRendered(); - - // Finalizes the print ready preview document. - void FinalizePrintReadyDocument(); - - // Cleanup after print preview finishes. - void Finished(); - - // Cleanup after print preview fails. - void Failed(bool report_error); - - // Helper functions - int GetNextPageNumber(); - bool IsRendering() const; - bool IsModifiable(); - bool HasSelection(); - bool IsLastPageOfPrintReadyMetafile() const; - bool IsFinalPageRendered() const; - - // Setters - void set_generate_draft_pages(bool generate_draft_pages); - void set_error(enum PrintPreviewErrorBuckets error); - - // Getters - // Original frame for which preview was requested. - blink::WebLocalFrame* source_frame(); - // Original node for which preview was requested. - const blink::WebNode& source_node() const; - - // Frame to be use to render preview. May be the same as source_frame(), or - // generated from it, e.g. copy of selected block. - blink::WebLocalFrame* prepared_frame(); - // Node to be use to render preview. May be the same as source_node(), or - // generated from it, e.g. copy of selected block. - const blink::WebNode& prepared_node() const; - - int total_page_count() const; - bool generate_draft_pages() const; - PdfMetafileSkia* metafile(); - int last_error() const; - - private: - enum State { - UNINITIALIZED, // Not ready to render. - INITIALIZED, // Ready to render. - RENDERING, // Rendering. - DONE // Finished rendering. - }; - - // Reset some of the internal rendering context. - void ClearContext(); - - // Specifies what to render for print preview. - FrameReference source_frame_; - blink::WebNode source_node_; - - std::unique_ptr prep_frame_view_; - std::unique_ptr metafile_; - - // Total page count in the renderer. - int total_page_count_; - - // The current page to render. - int current_page_index_; - - // List of page indices that need to be rendered. - std::vector pages_to_render_; - - // True, when draft pages needs to be generated. - bool generate_draft_pages_; - - // Specifies the total number of pages in the print ready metafile. - int print_ready_metafile_page_count_; - - base::TimeDelta document_render_time_; - base::TimeTicks begin_time_; - - enum PrintPreviewErrorBuckets error_; - - State state_; - }; - - - bool print_node_in_progress_; - bool is_loading_; - bool is_scripted_preview_delayed_; - - PrintPreviewContext print_preview_context_; - - // Used to fix a race condition where the source is a PDF and print preview - // hangs because RequestPrintPreview is called before DidStopLoading() is - // called. This is a store for the RequestPrintPreview() call and its - // parameters so that it can be invoked after DidStopLoading. - base::Closure on_stop_loading_closure_; - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelper); -}; - -} // namespace printing - -#endif // CHROME_RENDERER_PRINTING_PRINT_WEB_VIEW_HELPER_H_ diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc deleted file mode 100644 index 216d8236a88b7..0000000000000 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc +++ /dev/null @@ -1,142 +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/renderer/printing/print_web_view_helper.h" - -#include - -#include "base/logging.h" -#include "chrome/common/print_messages.h" -#include "content/public/renderer/render_thread.h" -#include "printing/metafile_skia_wrapper.h" -#include "printing/page_size_margins.h" -#include "printing/pdf_metafile_skia.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" - -#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) -#include "base/process/process_handle.h" -#else -#include "base/file_descriptor_posix.h" -#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) - -namespace printing { - -using blink::WebFrame; - -bool PrintWebViewHelper::RenderPreviewPage( - int page_number, - const PrintMsg_Print_Params& print_params) { - PrintMsg_PrintPage_Params page_params; - page_params.params = print_params; - page_params.page_number = page_number; - std::unique_ptr draft_metafile; - PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile(); - if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { - draft_metafile.reset(new PdfMetafileSkia); - initial_render_metafile = draft_metafile.get(); - } - - base::TimeTicks begin_time = base::TimeTicks::Now(); - PrintPageInternal(page_params, - print_preview_context_.prepared_frame(), - initial_render_metafile); - print_preview_context_.RenderedPreviewPage( - base::TimeTicks::Now() - begin_time); - if (draft_metafile.get()) { - draft_metafile->FinishDocument(); - } else if (print_preview_context_.IsModifiable() && - print_preview_context_.generate_draft_pages()) { - DCHECK(!draft_metafile.get()); - draft_metafile = - print_preview_context_.metafile()->GetMetafileForCurrentPage(); - } - return PreviewPageRendered(page_number, draft_metafile.get()); -} - -bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, - int page_count) { - PdfMetafileSkia metafile; - if (!metafile.Init()) - return false; - - const PrintMsg_PrintPages_Params& params = *print_pages_params_; - std::vector printed_pages; - - if (params.pages.empty()) { - for (int i = 0; i < page_count; ++i) { - printed_pages.push_back(i); - } - } else { - // TODO(vitalybuka): redesign to make more code cross platform. - for (size_t i = 0; i < params.pages.size(); ++i) { - if (params.pages[i] >= 0 && params.pages[i] < page_count) { - printed_pages.push_back(params.pages[i]); - } - } - } - - if (printed_pages.empty()) - return false; - - PrintMsg_PrintPage_Params page_params; - page_params.params = params.params; - for (size_t i = 0; i < printed_pages.size(); ++i) { - page_params.page_number = printed_pages[i]; - PrintPageInternal(page_params, frame, &metafile); - } - - // blink::printEnd() for PDF should be called before metafile is closed. - FinishFramePrinting(); - - metafile.FinishDocument(); - - PrintHostMsg_DidPrintPage_Params printed_page_params; - if (!CopyMetafileDataToSharedMem( - metafile, &printed_page_params.metafile_data_handle)) { - return false; - } - - printed_page_params.data_size = metafile.GetDataSize(); - printed_page_params.document_cookie = params.params.document_cookie; - - for (size_t i = 0; i < printed_pages.size(); ++i) { - printed_page_params.page_number = printed_pages[i]; - Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params)); - // Send the rest of the pages with an invalid metafile handle. - printed_page_params.metafile_data_handle.fd = -1; - } - return true; -} - -void PrintWebViewHelper::PrintPageInternal( - const PrintMsg_PrintPage_Params& params, - WebFrame* frame, - PdfMetafileSkia* metafile) { - PageSizeMargins page_layout_in_points; - double scale_factor = 1.0f; - ComputePageLayoutInPointsForCss(frame, params.page_number, params.params, - ignore_css_margins_, &scale_factor, - &page_layout_in_points); - gfx::Size page_size; - gfx::Rect content_area; - GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size, - &content_area); - gfx::Rect canvas_area = content_area; - - SkCanvas* canvas = metafile->GetVectorCanvasForNewPage( - page_size, canvas_area, scale_factor); - if (!canvas) - return; - - MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile); - - RenderPageContent(frame, params.page_number, canvas_area, content_area, - scale_factor, canvas); - - // Done printing. Close the device context to retrieve the compiled metafile. - if (!metafile->FinishPage()) - NOTREACHED() << "metafile failed"; -} - -} // namespace printing diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm b/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm deleted file mode 100644 index 36ba4a597cddb..0000000000000 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm +++ /dev/null @@ -1,129 +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/renderer/printing/print_web_view_helper.h" - -#import - -#include "base/logging.h" -#include "base/mac/scoped_nsautorelease_pool.h" -#include "base/metrics/histogram.h" -#include "chrome/common/print_messages.h" -#include "printing/metafile_skia_wrapper.h" -#include "printing/page_size_margins.h" -#include "third_party/WebKit/public/platform/WebCanvas.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/skia/include/core/SkCanvas.h" - -namespace printing { - -using blink::WebFrame; - -void PrintWebViewHelper::PrintPageInternal( - const PrintMsg_PrintPage_Params& params, - WebFrame* frame) { - PdfMetafileSkia metafile; - CHECK(metafile.Init()); - - int page_number = params.page_number; - gfx::Size page_size_in_dpi; - gfx::Rect content_area_in_dpi; - RenderPage(print_pages_params_->params, page_number, frame, false, &metafile, - &page_size_in_dpi, &content_area_in_dpi); - metafile.FinishDocument(); - - PrintHostMsg_DidPrintPage_Params page_params; - page_params.data_size = metafile.GetDataSize(); - page_params.page_number = page_number; - page_params.document_cookie = params.params.document_cookie; - page_params.page_size = page_size_in_dpi; - page_params.content_area = content_area_in_dpi; - - // Ask the browser to create the shared memory for us. - if (!CopyMetafileDataToSharedMem(metafile, - &(page_params.metafile_data_handle))) { - // TODO(thestig): Fail and return false instead. - page_params.data_size = 0; - } - - Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params)); -} - -bool PrintWebViewHelper::RenderPreviewPage( - int page_number, - const PrintMsg_Print_Params& print_params) { - PrintMsg_Print_Params printParams = print_params; - std::unique_ptr draft_metafile; - PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile(); - - bool render_to_draft = print_preview_context_.IsModifiable() && - is_print_ready_metafile_sent_; - - if (render_to_draft) { - draft_metafile.reset(new PdfMetafileSkia()); - CHECK(draft_metafile->Init()); - initial_render_metafile = draft_metafile.get(); - } - - base::TimeTicks begin_time = base::TimeTicks::Now(); - gfx::Size page_size; - RenderPage(printParams, page_number, print_preview_context_.prepared_frame(), - true, initial_render_metafile, &page_size, NULL); - print_preview_context_.RenderedPreviewPage( - base::TimeTicks::Now() - begin_time); - - if (draft_metafile.get()) { - draft_metafile->FinishDocument(); - } else { - if (print_preview_context_.IsModifiable() && - print_preview_context_.generate_draft_pages()) { - DCHECK(!draft_metafile.get()); - draft_metafile = - print_preview_context_.metafile()->GetMetafileForCurrentPage(); - } - } - return PreviewPageRendered(page_number, draft_metafile.get()); -} - -void PrintWebViewHelper::RenderPage(const PrintMsg_Print_Params& params, - int page_number, - WebFrame* frame, - bool is_preview, - PdfMetafileSkia* metafile, - gfx::Size* page_size, - gfx::Rect* content_rect) { - double scale_factor = 1.0f; - double webkit_shrink_factor = frame->getPrintPageShrink(page_number); - PageSizeMargins page_layout_in_points; - gfx::Rect content_area; - - ComputePageLayoutInPointsForCss(frame, page_number, params, - ignore_css_margins_, &scale_factor, - &page_layout_in_points); - GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, page_size, - &content_area); - if (content_rect) - *content_rect = content_area; - - scale_factor *= webkit_shrink_factor; - - gfx::Rect canvas_area = content_area; - - { - SkCanvas* canvas = metafile->GetVectorCanvasForNewPage( - *page_size, canvas_area, scale_factor); - if (!canvas) - return; - - MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile); - skia::SetIsPreviewMetafile(*canvas, is_preview); - RenderPageContent(frame, page_number, canvas_area, content_area, - scale_factor, static_cast(canvas)); - } - - // Done printing. Close the device context to retrieve the compiled metafile. - metafile->FinishPage(); -} - -} // namespace printing diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc deleted file mode 100644 index 96a128652a7f9..0000000000000 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc +++ /dev/null @@ -1,220 +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. - -#include "chrome/renderer/printing/print_web_view_helper.h" - -#include - -#include "base/logging.h" -#include "base/process/process_handle.h" -#include "chrome/common/print_messages.h" -#include "content/public/renderer/render_thread.h" -#include "printing/metafile_skia_wrapper.h" -#include "printing/page_size_margins.h" -#include "printing/pdf_metafile_skia.h" -#include "printing/units.h" -#include "skia/ext/platform_device.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" - - -namespace printing { - -using blink::WebFrame; - -bool PrintWebViewHelper::RenderPreviewPage( - int page_number, - const PrintMsg_Print_Params& print_params) { - PrintMsg_PrintPage_Params page_params; - page_params.params = print_params; - page_params.page_number = page_number; - std::unique_ptr draft_metafile; - PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile(); - if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { - draft_metafile.reset(new PdfMetafileSkia); - initial_render_metafile = draft_metafile.get(); - } - - base::TimeTicks begin_time = base::TimeTicks::Now(); - PrintPageInternal(page_params, - print_preview_context_.prepared_frame(), - initial_render_metafile, - NULL, - NULL); - print_preview_context_.RenderedPreviewPage( - base::TimeTicks::Now() - begin_time); - if (draft_metafile.get()) { - draft_metafile->FinishDocument(); - } else if (print_preview_context_.IsModifiable() && - print_preview_context_.generate_draft_pages()) { - DCHECK(!draft_metafile.get()); - draft_metafile = - print_preview_context_.metafile()->GetMetafileForCurrentPage(); - } - return PreviewPageRendered(page_number, draft_metafile.get()); -} - -bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, - int page_count) { - PdfMetafileSkia metafile; - if (!metafile.Init()) - return false; - - const PrintMsg_PrintPages_Params& params = *print_pages_params_; - std::vector printed_pages; - if (params.pages.empty()) { - for (int i = 0; i < page_count; ++i) { - printed_pages.push_back(i); - } - } else { - // TODO(vitalybuka): redesign to make more code cross platform. - for (size_t i = 0; i < params.pages.size(); ++i) { - if (params.pages[i] >= 0 && params.pages[i] < page_count) { - printed_pages.push_back(params.pages[i]); - } - } - } - if (printed_pages.empty()) - return false; - - std::vector page_size_in_dpi(printed_pages.size()); - std::vector content_area_in_dpi(printed_pages.size()); - - PrintMsg_PrintPage_Params page_params; - page_params.params = params.params; - for (size_t i = 0; i < printed_pages.size(); ++i) { - page_params.page_number = printed_pages[i]; - PrintPageInternal(page_params, - frame, - &metafile, - &page_size_in_dpi[i], - &content_area_in_dpi[i]); - } - - // blink::printEnd() for PDF should be called before metafile is closed. - FinishFramePrinting(); - - metafile.FinishDocument(); - - PrintHostMsg_DidPrintPage_Params printed_page_params; - if (!CopyMetafileDataToSharedMem( - metafile, &printed_page_params.metafile_data_handle)) { - return false; - } - - printed_page_params.content_area = params.params.printable_area; - printed_page_params.data_size = metafile.GetDataSize(); - printed_page_params.document_cookie = params.params.document_cookie; - printed_page_params.page_size = params.params.page_size; - - for (size_t i = 0; i < printed_pages.size(); ++i) { - printed_page_params.page_number = printed_pages[i]; - printed_page_params.page_size = page_size_in_dpi[i]; - printed_page_params.content_area = content_area_in_dpi[i]; - Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params)); - // Send the rest of the pages with an invalid metafile handle. - printed_page_params.metafile_data_handle = base::SharedMemoryHandle(); - } - return true; -} - -void PrintWebViewHelper::PrintPageInternal( - const PrintMsg_PrintPage_Params& params, - WebFrame* frame, - PdfMetafileSkia* metafile, - gfx::Size* page_size_in_dpi, - gfx::Rect* content_area_in_dpi) { - PageSizeMargins page_layout_in_points; - double css_scale_factor = 1.0f; - ComputePageLayoutInPointsForCss(frame, params.page_number, params.params, - ignore_css_margins_, &css_scale_factor, - &page_layout_in_points); - gfx::Size page_size; - gfx::Rect content_area; - GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size, - &content_area); - int dpi = static_cast(params.params.dpi); - // Calculate the actual page size and content area in dpi. - if (page_size_in_dpi) { - *page_size_in_dpi = - gfx::Size(static_cast(ConvertUnitDouble( - page_size.width(), kPointsPerInch, dpi)), - static_cast(ConvertUnitDouble( - page_size.height(), kPointsPerInch, dpi))); - } - - if (content_area_in_dpi) { - // Output PDF matches paper size and should be printer edge to edge. - *content_area_in_dpi = - gfx::Rect(0, 0, page_size_in_dpi->width(), page_size_in_dpi->height()); - } - - gfx::Rect canvas_area = - content_area; -#if 0 - params.params.display_header_footer ? gfx::Rect(page_size) : content_area; -#endif - - float webkit_page_shrink_factor = - frame->getPrintPageShrink(params.page_number); - float scale_factor = css_scale_factor * webkit_page_shrink_factor; - - SkCanvas* canvas = metafile->GetVectorCanvasForNewPage( - page_size, canvas_area, scale_factor); - if (!canvas) - return; - - MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile); - -#if 0 - if (params.params.display_header_footer) { - // |page_number| is 0-based, so 1 is added. - PrintHeaderAndFooter(canvas.get(), - params.page_number + 1, - print_preview_context_.total_page_count(), - *frame, - scale_factor, - page_layout_in_points, - params.params); - } -#endif - - float webkit_scale_factor = RenderPageContent(frame, - params.page_number, - canvas_area, - content_area, - scale_factor, - canvas); - DCHECK_GT(webkit_scale_factor, 0.0f); - // Done printing. Close the device context to retrieve the compiled metafile. - if (!metafile->FinishPage()) - NOTREACHED() << "metafile failed"; -} - -bool PrintWebViewHelper::CopyMetafileDataToSharedMem( - const PdfMetafileSkia& metafile, - base::SharedMemoryHandle* shared_mem_handle) { - uint32_t buf_size = metafile.GetDataSize(); - if (buf_size == 0) - return false; - - base::SharedMemory shared_buf; - // Allocate a shared memory buffer to hold the generated metafile data. - if (!shared_buf.CreateAndMapAnonymous(buf_size)) - return false; - - // Copy the bits into shared memory. - if (!metafile.GetData(shared_buf.memory(), buf_size)) - return false; - - if (!shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), - shared_mem_handle)) { - return false; - } - - Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle, - shared_mem_handle)); - return true; -} - -} // namespace printing diff --git a/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.cc b/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.cc deleted file mode 100644 index 46465f4dfd4ad..0000000000000 --- a/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.cc +++ /dev/null @@ -1,421 +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. - -// Implements a custom word iterator used for our spellchecker. - -#include "chrome/renderer/spellchecker/spellcheck_worditerator.h" - -#include -#include - -#include "base/i18n/break_iterator.h" -#include "base/logging.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "third_party/icu/source/common/unicode/normlzr.h" -#include "third_party/icu/source/common/unicode/schriter.h" -#include "third_party/icu/source/common/unicode/uscript.h" -#include "third_party/icu/source/i18n/unicode/ulocdata.h" - -// SpellcheckCharAttribute implementation: - -SpellcheckCharAttribute::SpellcheckCharAttribute() - : script_code_(USCRIPT_LATIN) { -} - -SpellcheckCharAttribute::~SpellcheckCharAttribute() { -} - -void SpellcheckCharAttribute::SetDefaultLanguage(const std::string& language) { - CreateRuleSets(language); -} - -base::string16 SpellcheckCharAttribute::GetRuleSet( - bool allow_contraction) const { - return allow_contraction ? - ruleset_allow_contraction_ : ruleset_disallow_contraction_; -} - -void SpellcheckCharAttribute::CreateRuleSets(const std::string& language) { - // The template for our custom rule sets, which is based on the word-break - // rules of ICU 4.0: - // . - // The major differences from the original one are listed below: - // * It discards comments in the original rules. - // * It discards characters not needed by our spellchecker (e.g. numbers, - // punctuation characters, Hiraganas, Katakanas, CJK Ideographs, and so on). - // * It allows customization of the $ALetter value (i.e. word characters). - // * It allows customization of the $ALetterPlus value (i.e. whether or not to - // use the dictionary data). - // * It allows choosing whether or not to split a text at contraction - // characters. - // This template only changes the forward-iteration rules. So, calling - // ubrk_prev() returns the same results as the original template. - static const char kRuleTemplate[] = - "!!chain;" - "$CR = [\\p{Word_Break = CR}];" - "$LF = [\\p{Word_Break = LF}];" - "$Newline = [\\p{Word_Break = Newline}];" - "$Extend = [\\p{Word_Break = Extend}];" - "$Format = [\\p{Word_Break = Format}];" - "$Katakana = [\\p{Word_Break = Katakana}];" - // Not all the characters in a given script are ALetter. - // For instance, U+05F4 is MidLetter. So, this may be - // better, but it leads to an empty set error in Thai. - // "$ALetter = [[\\p{script=%s}] & [\\p{Word_Break = ALetter}]];" - "$ALetter = [\\p{script=%s}%s];" - // U+0027 (single quote/apostrophe) is not in MidNumLet any more - // in UAX 29 rev 21 or later. For our purpose, U+0027 - // has to be treated as MidNumLet. ( http://crbug.com/364072 ) - "$MidNumLet = [\\p{Word_Break = MidNumLet} \\u0027];" - "$MidLetter = [\\p{Word_Break = MidLetter}%s];" - "$MidNum = [\\p{Word_Break = MidNum}];" - "$Numeric = [\\p{Word_Break = Numeric}];" - "$ExtendNumLet = [\\p{Word_Break = ExtendNumLet}];" - - "$Control = [\\p{Grapheme_Cluster_Break = Control}]; " - "%s" // ALetterPlus - - "$KatakanaEx = $Katakana ($Extend | $Format)*;" - "$ALetterEx = $ALetterPlus ($Extend | $Format)*;" - "$MidNumLetEx = $MidNumLet ($Extend | $Format)*;" - "$MidLetterEx = $MidLetter ($Extend | $Format)*;" - "$MidNumEx = $MidNum ($Extend | $Format)*;" - "$NumericEx = $Numeric ($Extend | $Format)*;" - "$ExtendNumLetEx = $ExtendNumLet ($Extend | $Format)*;" - - "$Hiragana = [\\p{script=Hiragana}];" - "$Ideographic = [\\p{Ideographic}];" - "$HiraganaEx = $Hiragana ($Extend | $Format)*;" - "$IdeographicEx = $Ideographic ($Extend | $Format)*;" - - "!!forward;" - "$CR $LF;" - "[^$CR $LF $Newline]? ($Extend | $Format)+;" - "$ALetterEx {200};" - "$ALetterEx $ALetterEx {200};" - "%s" // (Allow|Disallow) Contraction - - "!!reverse;" - "$BackALetterEx = ($Format | $Extend)* $ALetterPlus;" - "$BackMidNumLetEx = ($Format | $Extend)* $MidNumLet;" - "$BackNumericEx = ($Format | $Extend)* $Numeric;" - "$BackMidNumEx = ($Format | $Extend)* $MidNum;" - "$BackMidLetterEx = ($Format | $Extend)* $MidLetter;" - "$BackKatakanaEx = ($Format | $Extend)* $Katakana;" - "$BackExtendNumLetEx= ($Format | $Extend)* $ExtendNumLet;" - "$LF $CR;" - "($Format | $Extend)* [^$CR $LF $Newline]?;" - "$BackALetterEx $BackALetterEx;" - "$BackALetterEx ($BackMidLetterEx | $BackMidNumLetEx) $BackALetterEx;" - "$BackNumericEx $BackNumericEx;" - "$BackNumericEx $BackALetterEx;" - "$BackALetterEx $BackNumericEx;" - "$BackNumericEx ($BackMidNumEx | $BackMidNumLetEx) $BackNumericEx;" - "$BackKatakanaEx $BackKatakanaEx;" - "$BackExtendNumLetEx ($BackALetterEx | $BackNumericEx |" - " $BackKatakanaEx | $BackExtendNumLetEx);" - "($BackALetterEx | $BackNumericEx | $BackKatakanaEx)" - " $BackExtendNumLetEx;" - - "!!safe_reverse;" - "($Extend | $Format)+ .?;" - "($MidLetter | $MidNumLet) $BackALetterEx;" - "($MidNum | $MidNumLet) $BackNumericEx;" - - "!!safe_forward;" - "($Extend | $Format)+ .?;" - "($MidLetterEx | $MidNumLetEx) $ALetterEx;" - "($MidNumEx | $MidNumLetEx) $NumericEx;"; - - // Retrieve the script codes used by the given language from ICU. When the - // given language consists of two or more scripts, we just use the first - // script. The size of returned script codes is always < 8. Therefore, we use - // an array of size 8 so we can include all script codes without insufficient - // buffer errors. - UErrorCode error = U_ZERO_ERROR; - UScriptCode script_code[8]; - int scripts = uscript_getCode(language.c_str(), script_code, - arraysize(script_code), &error); - if (U_SUCCESS(error) && scripts >= 1) - script_code_ = script_code[0]; - - // Retrieve the values for $ALetter and $ALetterPlus. We use the dictionary - // only for the languages which need it (i.e. Korean and Thai) to prevent ICU - // from returning dictionary words (i.e. Korean or Thai words) for languages - // which don't need them. - const char* aletter = uscript_getName(script_code_); - if (!aletter) - aletter = "Latin"; - - const char kWithDictionary[] = - "$dictionary = [:LineBreak = Complex_Context:];" - "$ALetterPlus = [$ALetter [$dictionary-$Extend-$Control]];"; - const char kWithoutDictionary[] = "$ALetterPlus = $ALetter;"; - const char* aletter_plus = kWithoutDictionary; - if (script_code_ == USCRIPT_HANGUL || script_code_ == USCRIPT_THAI || - script_code_ == USCRIPT_LAO || script_code_ == USCRIPT_KHMER) - aletter_plus = kWithDictionary; - - // Treat numbers as word characters except for Arabic and Hebrew. - const char* aletter_extra = " [0123456789]"; - if (script_code_ == USCRIPT_HEBREW || script_code_ == USCRIPT_ARABIC) - aletter_extra = ""; - - const char kMidLetterExtra[] = ""; - // For Hebrew, treat single/double quoation marks as MidLetter. - const char kMidLetterExtraHebrew[] = "\"'"; - const char* midletter_extra = kMidLetterExtra; - if (script_code_ == USCRIPT_HEBREW) - midletter_extra = kMidLetterExtraHebrew; - - // Create two custom rule-sets: one allows contraction and the other does not. - // We save these strings in UTF-16 so we can use it without conversions. (ICU - // needs UTF-16 strings.) - const char kAllowContraction[] = - "$ALetterEx ($MidLetterEx | $MidNumLetEx) $ALetterEx {200};"; - const char kDisallowContraction[] = ""; - - ruleset_allow_contraction_ = base::ASCIIToUTF16( - base::StringPrintf(kRuleTemplate, - aletter, - aletter_extra, - midletter_extra, - aletter_plus, - kAllowContraction)); - ruleset_disallow_contraction_ = base::ASCIIToUTF16( - base::StringPrintf(kRuleTemplate, - aletter, - aletter_extra, - midletter_extra, - aletter_plus, - kDisallowContraction)); -} - -bool SpellcheckCharAttribute::OutputChar(UChar c, - base::string16* output) const { - // Call the language-specific function if necessary. - // Otherwise, we call the default one. - switch (script_code_) { - case USCRIPT_ARABIC: - return OutputArabic(c, output); - - case USCRIPT_HANGUL: - return OutputHangul(c, output); - - case USCRIPT_HEBREW: - return OutputHebrew(c, output); - - default: - return OutputDefault(c, output); - } -} - -bool SpellcheckCharAttribute::OutputArabic(UChar c, - base::string16* output) const { - // Discard characters not from Arabic alphabets. We also discard vowel marks - // of Arabic (Damma, Fatha, Kasra, etc.) to prevent our Arabic dictionary from - // marking an Arabic word including vowel marks as misspelled. (We need to - // check these vowel marks manually and filter them out since their script - // codes are USCRIPT_ARABIC.) - if (0x0621 <= c && c <= 0x064D) - output->push_back(c); - return true; -} - -bool SpellcheckCharAttribute::OutputHangul(UChar c, - base::string16* output) const { - // Decompose a Hangul character to a Hangul vowel and consonants used by our - // spellchecker. A Hangul character of Unicode is a ligature consisting of a - // Hangul vowel and consonants, e.g. U+AC01 "Gag" consists of U+1100 "G", - // U+1161 "a", and U+11A8 "g". That is, we can treat each Hangul character as - // a point of a cubic linear space consisting of (first consonant, vowel, last - // consonant). Therefore, we can compose a Hangul character from a vowel and - // two consonants with linear composition: - // character = 0xAC00 + - // (first consonant - 0x1100) * 28 * 21 + - // (vowel - 0x1161) * 28 + - // (last consonant - 0x11A7); - // We can also decompose a Hangul character with linear decomposition: - // first consonant = (character - 0xAC00) / 28 / 21; - // vowel = (character - 0xAC00) / 28 % 21; - // last consonant = (character - 0xAC00) % 28; - // This code is copied from Unicode Standard Annex #15 - // and added some comments. - const int kSBase = 0xAC00; // U+AC00: the top of Hangul characters. - const int kLBase = 0x1100; // U+1100: the top of Hangul first consonants. - const int kVBase = 0x1161; // U+1161: the top of Hangul vowels. - const int kTBase = 0x11A7; // U+11A7: the top of Hangul last consonants. - const int kLCount = 19; // The number of Hangul first consonants. - const int kVCount = 21; // The number of Hangul vowels. - const int kTCount = 28; // The number of Hangul last consonants. - const int kNCount = kVCount * kTCount; - const int kSCount = kLCount * kNCount; - - int index = c - kSBase; - if (index < 0 || index >= kSBase + kSCount) { - // This is not a Hangul syllable. Call the default output function since we - // should output this character when it is a Hangul syllable. - return OutputDefault(c, output); - } - - // This is a Hangul character. Decompose this characters into Hangul vowels - // and consonants. - int l = kLBase + index / kNCount; - int v = kVBase + (index % kNCount) / kTCount; - int t = kTBase + index % kTCount; - output->push_back(l); - output->push_back(v); - if (t != kTBase) - output->push_back(t); - return true; -} - -bool SpellcheckCharAttribute::OutputHebrew(UChar c, - base::string16* output) const { - // Discard characters except Hebrew alphabets. We also discard Hebrew niqquds - // to prevent our Hebrew dictionary from marking a Hebrew word including - // niqquds as misspelled. (Same as Arabic vowel marks, we need to check - // niqquds manually and filter them out since their script codes are - // USCRIPT_HEBREW.) - // Pass through ASCII single/double quotation marks and Hebrew Geresh and - // Gershayim. - if ((0x05D0 <= c && c <= 0x05EA) || c == 0x22 || c == 0x27 || - c == 0x05F4 || c == 0x05F3) - output->push_back(c); - return true; -} - -bool SpellcheckCharAttribute::OutputDefault(UChar c, - base::string16* output) const { - // Check the script code of this character and output only if it is the one - // used by the spellchecker language. - UErrorCode status = U_ZERO_ERROR; - UScriptCode script_code = uscript_getScript(c, &status); - if (script_code == script_code_ || script_code == USCRIPT_COMMON) - output->push_back(c); - return true; -} - -// SpellcheckWordIterator implementation: - -SpellcheckWordIterator::SpellcheckWordIterator() - : text_(NULL), - attribute_(NULL), - iterator_() { -} - -SpellcheckWordIterator::~SpellcheckWordIterator() { - Reset(); -} - -bool SpellcheckWordIterator::Initialize( - const SpellcheckCharAttribute* attribute, - bool allow_contraction) { - // Create a custom ICU break iterator with empty text used in this object. (We - // allow setting text later so we can re-use this iterator.) - DCHECK(attribute); - const base::string16 rule(attribute->GetRuleSet(allow_contraction)); - - // If there is no rule set, the attributes were invalid. - if (rule.empty()) - return false; - - std::unique_ptr iterator( - new base::i18n::BreakIterator(base::string16(), rule)); - if (!iterator->Init()) { - // Since we're not passing in any text, the only reason this could fail - // is if we fail to parse the rules. Since the rules are hardcoded, - // that would be a bug in this class. - NOTREACHED() << "failed to open iterator (broken rules)"; - return false; - } - iterator_ = std::move(iterator); - - // Set the character attributes so we can normalize the words extracted by - // this iterator. - attribute_ = attribute; - return true; -} - -bool SpellcheckWordIterator::IsInitialized() const { - // Return true iff we have an iterator. - return !!iterator_; -} - -bool SpellcheckWordIterator::SetText(const base::char16* text, size_t length) { - DCHECK(!!iterator_); - - // Set the text to be split by this iterator. - if (!iterator_->SetText(text, length)) { - LOG(ERROR) << "failed to set text"; - return false; - } - - text_ = text; - return true; -} - -bool SpellcheckWordIterator::GetNextWord(base::string16* word_string, - int* word_start, - int* word_length) { - DCHECK(!!text_); - - word_string->clear(); - *word_start = 0; - *word_length = 0; - - if (!text_) { - return false; - } - - // Find a word that can be checked for spelling. Our rule sets filter out - // invalid words (e.g. numbers and characters not supported by the - // spellchecker language) so this ubrk_getRuleStatus() call returns - // UBRK_WORD_NONE when this iterator finds an invalid word. So, we skip such - // words until we can find a valid word or reach the end of the input string. - while (iterator_->Advance()) { - const size_t start = iterator_->prev(); - const size_t length = iterator_->pos() - start; - if (iterator_->IsWord()) { - if (Normalize(start, length, word_string)) { - *word_start = start; - *word_length = length; - return true; - } - } - } - - // There aren't any more words in the given text. - return false; -} - -void SpellcheckWordIterator::Reset() { - iterator_.reset(); -} - -bool SpellcheckWordIterator::Normalize(int input_start, - int input_length, - base::string16* output_string) const { - // We use NFKC (Normalization Form, Compatible decomposition, followed by - // canonical Composition) defined in Unicode Standard Annex #15 to normalize - // this token because it it the most suitable normalization algorithm for our - // spellchecker. Nevertheless, it is not a perfect algorithm for our - // spellchecker and we need manual normalization as well. The normalized - // text does not have to be NUL-terminated since its characters are copied to - // string16, which adds a NUL character when we need. - icu::UnicodeString input(FALSE, &text_[input_start], input_length); - UErrorCode status = U_ZERO_ERROR; - icu::UnicodeString output; - icu::Normalizer::normalize(input, UNORM_NFKC, 0, output, status); - if (status != U_ZERO_ERROR && status != U_STRING_NOT_TERMINATED_WARNING) - return false; - - // Copy the normalized text to the output. - icu::StringCharacterIterator it(output); - for (UChar c = it.first(); c != icu::CharacterIterator::DONE; c = it.next()) - attribute_->OutputChar(c, output_string); - - return !output_string->empty(); -} diff --git a/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h b/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h deleted file mode 100644 index 7e07d29273a11..0000000000000 --- a/chromium_src/chrome/renderer/spellchecker/spellcheck_worditerator.h +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) 2011 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. - -// Defines an iterator class that enumerates words supported by our spellchecker -// from multi-language text. This class is used for filtering out characters -// not supported by our spellchecker. - -#ifndef CHROME_RENDERER_SPELLCHECKER_SPELLCHECK_WORDITERATOR_H_ -#define CHROME_RENDERER_SPELLCHECKER_SPELLCHECK_WORDITERATOR_H_ - -#include -#include - -#include "base/macros.h" -#include "base/strings/string16.h" -#include "third_party/icu/source/common/unicode/uscript.h" - -namespace base { -namespace i18n { -class BreakIterator; -} // namespace i18n -} // namespace base - -// A class which encapsulates language-specific operations used by -// SpellcheckWordIterator. When we set the spellchecker language, this class -// creates rule sets that filter out the characters not supported by the -// spellchecker. (Please read the comment in the SpellcheckWordIterator class -// about how to use this class.) -class SpellcheckCharAttribute { - public: - SpellcheckCharAttribute(); - ~SpellcheckCharAttribute(); - - // Sets the language of the spellchecker. When this function is called with an - // ISO language code, this function creates the custom rule-sets used by - // the ICU break iterator so it can extract only words used by the language. - // GetRuleSet() returns the rule-sets created in this function. - void SetDefaultLanguage(const std::string& language); - - // Returns a custom rule-set string used by the ICU break iterator. This class - // has two rule-sets, one splits a contraction and the other does not, so we - // can split a concaticated word (e.g. "seven-year-old") into words (e.g. - // "seven", "year", and "old") and check their spellings. The result stirng is - // encoded in UTF-16 since ICU needs UTF-16 strings. - base::string16 GetRuleSet(bool allow_contraction) const; - - // Outputs a character only if it is a word character. (Please read the - // comments in CreateRuleSets() why we need this function.) - bool OutputChar(UChar c, base::string16* output) const; - - private: - // Creates the rule-sets that return words possibly used by the given - // language. Unfortunately, these rule-sets are not perfect and have some - // false-positives. For example, they return combined accent marks even though - // we need English words only. We call OutputCharacter() to filter out such - // false-positive characters. - void CreateRuleSets(const std::string& language); - - // Outputs a character only if it is one used by the given language. These - // functions are called from OutputChar(). - bool OutputArabic(UChar c, base::string16* output) const; - bool OutputHangul(UChar c, base::string16* output) const; - bool OutputHebrew(UChar c, base::string16* output) const; - bool OutputDefault(UChar c, base::string16* output) const; - - // The custom rule-set strings used by ICU break iterator. Since it is not so - // easy to create custom rule-sets from an ISO language code, this class - // saves these rule-set strings created when we set the language. - base::string16 ruleset_allow_contraction_; - base::string16 ruleset_disallow_contraction_; - - // The script code used by this language. - UScriptCode script_code_; - - DISALLOW_COPY_AND_ASSIGN(SpellcheckCharAttribute); -}; - -// A class which extracts words that can be checked for spelling from a -// multi-language string. The ICU word-break iterator does not discard some -// punctuation characters attached to a word. For example, when we set a word -// "_hello_" to a word-break iterator, it just returns "_hello_". Neither does -// it discard characters not used by the language. For example, it returns -// Russian words even though we need English words only. To extract only the -// words that our spellchecker can check their spellings, this class uses custom -// rule-sets created by the SpellcheckCharAttribute class. Also, this class -// normalizes extracted words so our spellchecker can check the spellings of -// words that include ligatures, combined characters, full-width characters, -// etc. This class uses UTF-16 strings as its input and output strings since -// UTF-16 is the native encoding of ICU and avoid unnecessary conversions -// when changing the encoding of this string for our spellchecker. (Chrome can -// use two or more spellcheckers and we cannot assume their encodings.) -// The following snippet is an example that extracts words with this class. -// -// // Creates the language-specific attributes for US English. -// SpellcheckCharAttribute attribute; -// attribute.SetDefaultLanguage("en-US"); -// -// // Set up a SpellcheckWordIterator object which extracts English words, -// // and retrieve them. -// SpellcheckWordIterator iterator; -// base::string16 text(base::UTF8ToUTF16("this is a test.")); -// iterator.Initialize(&attribute, true); -// iterator.SetText(text.c_str(), text_.length()); -// -// base::string16 word; -// int offset; -// int length; -// while (iterator.GetNextWord(&word, &offset, &length)) { -// ... -// } -// -class SpellcheckWordIterator { - public: - SpellcheckWordIterator(); - ~SpellcheckWordIterator(); - - // Initializes a word-iterator object with the language-specific attribute. If - // we need to split contractions and concatenated words, call this function - // with its 'allow_contraction' parameter false. (This function uses lots of - // temporal memory to compile a custom word-break rule into an automaton.) - bool Initialize(const SpellcheckCharAttribute* attribute, - bool allow_contraction); - - // Returns whether this word iterator is initialized. - bool IsInitialized() const; - - // Set text to be iterated. (This text does not have to be NULL-terminated.) - // This function also resets internal state so we can reuse this iterator - // without calling Initialize(). - bool SetText(const base::char16* text, size_t length); - - // Retrieves a word (or a contraction), stores its copy to 'word_string', and - // stores the position and the length for input word to 'word_start'. Since - // this function normalizes the output word, the length of 'word_string' may - // be different from the 'word_length'. Therefore, when we call functions that - // changes the input text, such as string16::replace(), we need to use - // 'word_start' and 'word_length' as listed in the following snippet. - // - // while(iterator.GetNextWord(&word, &offset, &length)) - // text.replace(offset, length, word); - // - bool GetNextWord(base::string16* word_string, - int* word_start, - int* word_length); - - // Releases all the resources attached to this object. - void Reset(); - - private: - // Normalizes a non-terminated string returned from an ICU word-break - // iterator. A word returned from an ICU break iterator may include characters - // not supported by our spellchecker, e.g. ligatures, combining/ characters, - // full-width letters, etc. This function replaces such characters with - // alternative characters supported by our spellchecker. This function also - // calls SpellcheckWordIterator::OutputChar() to filter out false-positive - // characters. - bool Normalize(int input_start, - int input_length, - base::string16* output_string) const; - - // The pointer to the input string from which we are extracting words. - const base::char16* text_; - - // The language-specific attributes used for filtering out non-word - // characters. - const SpellcheckCharAttribute* attribute_; - - // The break iterator. - std::unique_ptr iterator_; - - DISALLOW_COPY_AND_ASSIGN(SpellcheckWordIterator); -}; - -#endif // CHROME_RENDERER_SPELLCHECKER_SPELLCHECK_WORDITERATOR_H_ diff --git a/chromium_src/chrome/renderer/tts_dispatcher.cc b/chromium_src/chrome/renderer/tts_dispatcher.cc deleted file mode 100644 index 0d3b97c845492..0000000000000 --- a/chromium_src/chrome/renderer/tts_dispatcher.cc +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 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. - -#include "chrome/renderer/tts_dispatcher.h" - -#include "base/strings/utf_string_conversions.h" -#include "chrome/common/tts_messages.h" -#include "chrome/common/tts_utterance_request.h" -#include "content/public/renderer/render_thread.h" -#include "third_party/WebKit/public/platform/WebCString.h" -#include "third_party/WebKit/public/platform/WebSpeechSynthesisUtterance.h" -#include "third_party/WebKit/public/platform/WebSpeechSynthesisVoice.h" -#include "third_party/WebKit/public/platform/WebString.h" -#include "third_party/WebKit/public/platform/WebVector.h" - -using content::RenderThread; -using blink::WebSpeechSynthesizerClient; -using blink::WebSpeechSynthesisUtterance; -using blink::WebSpeechSynthesisVoice; -using blink::WebString; -using blink::WebVector; - -int TtsDispatcher::next_utterance_id_ = 1; - -TtsDispatcher::TtsDispatcher(WebSpeechSynthesizerClient* client) - : synthesizer_client_(client) { - RenderThread::Get()->AddObserver(this); -} - -TtsDispatcher::~TtsDispatcher() { - RenderThread::Get()->RemoveObserver(this); -} - -bool TtsDispatcher::OnControlMessageReceived(const IPC::Message& message) { - IPC_BEGIN_MESSAGE_MAP(TtsDispatcher, message) - IPC_MESSAGE_HANDLER(TtsMsg_SetVoiceList, OnSetVoiceList) - IPC_MESSAGE_HANDLER(TtsMsg_DidStartSpeaking, OnDidStartSpeaking) - IPC_MESSAGE_HANDLER(TtsMsg_DidFinishSpeaking, OnDidFinishSpeaking) - IPC_MESSAGE_HANDLER(TtsMsg_DidPauseSpeaking, OnDidPauseSpeaking) - IPC_MESSAGE_HANDLER(TtsMsg_DidResumeSpeaking, OnDidResumeSpeaking) - IPC_MESSAGE_HANDLER(TtsMsg_WordBoundary, OnWordBoundary) - IPC_MESSAGE_HANDLER(TtsMsg_SentenceBoundary, OnSentenceBoundary) - IPC_MESSAGE_HANDLER(TtsMsg_MarkerEvent, OnMarkerEvent) - IPC_MESSAGE_HANDLER(TtsMsg_WasInterrupted, OnWasInterrupted) - IPC_MESSAGE_HANDLER(TtsMsg_WasCancelled, OnWasCancelled) - IPC_MESSAGE_HANDLER(TtsMsg_SpeakingErrorOccurred, OnSpeakingErrorOccurred) - IPC_END_MESSAGE_MAP() - - // Always return false because there may be multiple TtsDispatchers - // and we want them all to have a chance to handle this message. - return false; -} - -void TtsDispatcher::updateVoiceList() { - RenderThread::Get()->Send(new TtsHostMsg_InitializeVoiceList()); -} - -void TtsDispatcher::speak(const WebSpeechSynthesisUtterance& web_utterance) { - int id = next_utterance_id_++; - - utterance_id_map_[id] = web_utterance; - - TtsUtteranceRequest utterance; - utterance.id = id; - utterance.text = web_utterance.text().utf8(); - utterance.lang = web_utterance.lang().utf8(); - utterance.voice = web_utterance.voice().utf8(); - utterance.volume = web_utterance.volume(); - utterance.rate = web_utterance.rate(); - utterance.pitch = web_utterance.pitch(); - RenderThread::Get()->Send(new TtsHostMsg_Speak(utterance)); -} - -void TtsDispatcher::pause() { - RenderThread::Get()->Send(new TtsHostMsg_Pause()); -} - -void TtsDispatcher::resume() { - RenderThread::Get()->Send(new TtsHostMsg_Resume()); -} - -void TtsDispatcher::cancel() { - RenderThread::Get()->Send(new TtsHostMsg_Cancel()); -} - -WebSpeechSynthesisUtterance TtsDispatcher::FindUtterance(int utterance_id) { - base::hash_map::const_iterator iter = - utterance_id_map_.find(utterance_id); - if (iter == utterance_id_map_.end()) - return WebSpeechSynthesisUtterance(); - return iter->second; -} - -void TtsDispatcher::OnSetVoiceList(const std::vector& voices) { - WebVector out_voices(voices.size()); - for (size_t i = 0; i < voices.size(); ++i) { - out_voices[i] = WebSpeechSynthesisVoice(); - out_voices[i].setVoiceURI(WebString::fromUTF8(voices[i].voice_uri)); - out_voices[i].setName(WebString::fromUTF8(voices[i].name)); - out_voices[i].setLanguage(WebString::fromUTF8(voices[i].lang)); - out_voices[i].setIsLocalService(voices[i].local_service); - out_voices[i].setIsDefault(voices[i].is_default); - } - synthesizer_client_->setVoiceList(out_voices); -} - -void TtsDispatcher::OnDidStartSpeaking(int utterance_id) { - if (utterance_id_map_.find(utterance_id) == utterance_id_map_.end()) - return; - - WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.isNull()) - return; - - synthesizer_client_->didStartSpeaking(utterance); -} - -void TtsDispatcher::OnDidFinishSpeaking(int utterance_id) { - WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.isNull()) - return; - - synthesizer_client_->didFinishSpeaking(utterance); - utterance_id_map_.erase(utterance_id); -} - -void TtsDispatcher::OnDidPauseSpeaking(int utterance_id) { - WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.isNull()) - return; - - synthesizer_client_->didPauseSpeaking(utterance); -} - -void TtsDispatcher::OnDidResumeSpeaking(int utterance_id) { - WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.isNull()) - return; - - synthesizer_client_->didResumeSpeaking(utterance); -} - -void TtsDispatcher::OnWordBoundary(int utterance_id, int char_index) { - CHECK(char_index >= 0); - - WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.isNull()) - return; - - synthesizer_client_->wordBoundaryEventOccurred( - utterance, static_cast(char_index)); -} - -void TtsDispatcher::OnSentenceBoundary(int utterance_id, int char_index) { - CHECK(char_index >= 0); - - WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.isNull()) - return; - - synthesizer_client_->sentenceBoundaryEventOccurred( - utterance, static_cast(char_index)); -} - -void TtsDispatcher::OnMarkerEvent(int utterance_id, int char_index) { - // Not supported yet. -} - -void TtsDispatcher::OnWasInterrupted(int utterance_id) { - WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.isNull()) - return; - - // The web speech API doesn't support "interrupted". - synthesizer_client_->didFinishSpeaking(utterance); - utterance_id_map_.erase(utterance_id); -} - -void TtsDispatcher::OnWasCancelled(int utterance_id) { - WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.isNull()) - return; - - // The web speech API doesn't support "cancelled". - synthesizer_client_->didFinishSpeaking(utterance); - utterance_id_map_.erase(utterance_id); -} - -void TtsDispatcher::OnSpeakingErrorOccurred(int utterance_id, - const std::string& error_message) { - WebSpeechSynthesisUtterance utterance = FindUtterance(utterance_id); - if (utterance.isNull()) - return; - - // The web speech API doesn't support an error message. - synthesizer_client_->speakingErrorOccurred(utterance); - utterance_id_map_.erase(utterance_id); -} diff --git a/chromium_src/chrome/renderer/tts_dispatcher.h b/chromium_src/chrome/renderer/tts_dispatcher.h deleted file mode 100644 index 45db9751c8b83..0000000000000 --- a/chromium_src/chrome/renderer/tts_dispatcher.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 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_RENDERER_TTS_DISPATCHER_H_ -#define CHROME_RENDERER_TTS_DISPATCHER_H_ - -#include - -#include "base/containers/hash_tables.h" -#include "content/public/renderer/render_thread_observer.h" -#include "third_party/WebKit/public/platform/WebSpeechSynthesizer.h" -#include "third_party/WebKit/public/platform/WebSpeechSynthesizerClient.h" - -namespace IPC { -class Message; -} - -struct TtsVoice; - -// TtsDispatcher is a delegate for methods used by Blink for speech synthesis -// APIs. It's the complement of TtsDispatcherHost (owned by RenderViewHost). -// Each TtsDispatcher is owned by the WebSpeechSynthesizerClient in Blink; -// it registers itself to listen to IPC upon construction and unregisters -// itself when deleted. There can be multiple TtsDispatchers alive at once, -// so each one routes IPC messages to its WebSpeechSynthesizerClient only if -// the utterance id (which is globally unique) matches. -class TtsDispatcher - : public blink::WebSpeechSynthesizer, - public content::RenderThreadObserver { - public: - explicit TtsDispatcher(blink::WebSpeechSynthesizerClient* client); - - private: - virtual ~TtsDispatcher(); - - // RenderProcessObserver override. - virtual bool OnControlMessageReceived(const IPC::Message& message) override; - - // blink::WebSpeechSynthesizer implementation. - virtual void updateVoiceList() override; - virtual void speak(const blink::WebSpeechSynthesisUtterance& utterance) - override; - virtual void pause() override; - virtual void resume() override; - virtual void cancel() override; - - blink::WebSpeechSynthesisUtterance FindUtterance(int utterance_id); - - void OnSetVoiceList(const std::vector& voices); - void OnDidStartSpeaking(int utterance_id); - void OnDidFinishSpeaking(int utterance_id); - void OnDidPauseSpeaking(int utterance_id); - void OnDidResumeSpeaking(int utterance_id); - void OnWordBoundary(int utterance_id, int char_index); - void OnSentenceBoundary(int utterance_id, int char_index); - void OnMarkerEvent(int utterance_id, int char_index); - void OnWasInterrupted(int utterance_id); - void OnWasCancelled(int utterance_id); - void OnSpeakingErrorOccurred(int utterance_id, - const std::string& error_message); - - // The WebKit client class that we use to send events back to the JS world. - // Weak reference, this will be valid as long as this object exists. - blink::WebSpeechSynthesizerClient* synthesizer_client_; - - // Next utterance id, used to map response IPCs to utterance objects. - static int next_utterance_id_; - - // Map from id to utterance objects. - base::hash_map utterance_id_map_; - - DISALLOW_COPY_AND_ASSIGN(TtsDispatcher); -}; - -#endif // CHROME_RENDERER_TTS_DISPATCHER_H_ diff --git a/chromium_src/chrome/utility/printing_handler_win.cc b/chromium_src/chrome/utility/printing_handler_win.cc deleted file mode 100644 index 105e574f7358e..0000000000000 --- a/chromium_src/chrome/utility/printing_handler_win.cc +++ /dev/null @@ -1,139 +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. - -#include "chrome/utility/printing_handler_win.h" - -#include "base/files/file_util.h" -#include "base/lazy_instance.h" -#include "base/path_service.h" -#include "base/scoped_native_library.h" -#include "chrome/common/print_messages.h" -#include "content/public/utility/utility_thread.h" -#include "pdf/pdf.h" -#include "printing/emf_win.h" -#include "printing/page_range.h" -#include "printing/pdf_render_settings.h" -#include "ui/gfx/gdi_util.h" - -namespace printing { - -namespace { - -bool Send(IPC::Message* message) { - return content::UtilityThread::Get()->Send(message); -} - -void ReleaseProcessIfNeeded() { - content::UtilityThread::Get()->ReleaseProcessIfNeeded(); -} - -} // namespace - -PrintingHandlerWin::PrintingHandlerWin() {} - -PrintingHandlerWin::~PrintingHandlerWin() {} - -bool PrintingHandlerWin::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PrintingHandlerWin, message) - IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles, - OnRenderPDFPagesToMetafile) - IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage, - OnRenderPDFPagesToMetafileGetPage) - IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop, - OnRenderPDFPagesToMetafileStop) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void PrintingHandlerWin::OnRenderPDFPagesToMetafile( - IPC::PlatformFileForTransit pdf_transit, - const PdfRenderSettings& settings) { - pdf_rendering_settings_ = settings; - base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit); - int page_count = LoadPDF(std::move(pdf_file)); - //int page_count = 1; - Send( - new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount(page_count)); -} - -void PrintingHandlerWin::OnRenderPDFPagesToMetafileGetPage( - int page_number, - IPC::PlatformFileForTransit output_file) { - base::File emf_file = IPC::PlatformFileForTransitToFile(output_file); - float scale_factor = 1.0f; - bool success = - RenderPdfPageToMetafile(page_number, std::move(emf_file), &scale_factor); - Send(new ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone( - success, scale_factor)); -} - -void PrintingHandlerWin::OnRenderPDFPagesToMetafileStop() { - ReleaseProcessIfNeeded(); -} - -int PrintingHandlerWin::LoadPDF(base::File pdf_file) { - int64_t length64 = pdf_file.GetLength(); - if (length64 <= 0 || length64 > std::numeric_limits::max()) - return 0; - int length = static_cast(length64); - - pdf_data_.resize(length); - if (length != pdf_file.Read(0, pdf_data_.data(), pdf_data_.size())) - return 0; - - int total_page_count = 0; - if (!chrome_pdf::GetPDFDocInfo(&pdf_data_.front(), pdf_data_.size(), - &total_page_count, nullptr)) { - return 0; - } - return total_page_count; -} - -bool PrintingHandlerWin::RenderPdfPageToMetafile(int page_number, - base::File output_file, - float* scale_factor) { - Emf metafile; - metafile.Init(); - - // We need to scale down DC to fit an entire page into DC available area. - // Current metafile is based on screen DC and have current screen size. - // Writing outside of those boundaries will result in the cut-off output. - // On metafiles (this is the case here), scaling down will still record - // original coordinates and we'll be able to print in full resolution. - // Before playback we'll need to counter the scaling up that will happen - // in the service (print_system_win.cc). - *scale_factor = - gfx::CalculatePageScale(metafile.context(), - pdf_rendering_settings_.area().right(), - pdf_rendering_settings_.area().bottom()); - gfx::ScaleDC(metafile.context(), *scale_factor); - - // The underlying metafile is of type Emf and ignores the arguments passed - // to StartPage. - metafile.StartPage(gfx::Size(), gfx::Rect(), 1); - if (!chrome_pdf::RenderPDFPageToDC( - &pdf_data_.front(), - pdf_data_.size(), - page_number, - metafile.context(), - pdf_rendering_settings_.dpi(), - pdf_rendering_settings_.area().x(), - pdf_rendering_settings_.area().y(), - pdf_rendering_settings_.area().width(), - pdf_rendering_settings_.area().height(), - true, - false, - true, - true, - pdf_rendering_settings_.autorotate())) { - return false; - } - metafile.FinishPage(); - metafile.FinishDocument(); - return metafile.SaveTo(&output_file); -} - -} // printing diff --git a/chromium_src/chrome/utility/printing_handler_win.h b/chromium_src/chrome/utility/printing_handler_win.h deleted file mode 100644 index e7fcc5bed158a..0000000000000 --- a/chromium_src/chrome/utility/printing_handler_win.h +++ /dev/null @@ -1,51 +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. - -#ifndef CHROME_UTILITY_PRINTING_HANDLER_WIN_H_ -#define CHROME_UTILITY_PRINTING_HANDLER_WIN_H_ - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "chrome/utility/utility_message_handler.h" -#include "ipc/ipc_platform_file.h" -#include "printing/pdf_render_settings.h" - -namespace printing { - -class PdfRenderSettings; -struct PwgRasterSettings; -struct PageRange; - -// Dispatches IPCs for printing. -class PrintingHandlerWin : public UtilityMessageHandler { - public: - PrintingHandlerWin(); - ~PrintingHandlerWin() override; - - // IPC::Listener: - bool OnMessageReceived(const IPC::Message& message) override; - - private: - // IPC message handlers. - void OnRenderPDFPagesToMetafile(IPC::PlatformFileForTransit pdf_transit, - const PdfRenderSettings& settings); - void OnRenderPDFPagesToMetafileGetPage( - int page_number, - IPC::PlatformFileForTransit output_file); - void OnRenderPDFPagesToMetafileStop(); - - int LoadPDF(base::File pdf_file); - bool RenderPdfPageToMetafile(int page_number, - base::File output_file, - float* scale_factor); - - std::vector pdf_data_; - PdfRenderSettings pdf_rendering_settings_; - - DISALLOW_COPY_AND_ASSIGN(PrintingHandlerWin); -}; - -} // namespace printing - -#endif // CHROME_UTILITY_PRINTING_HANDLER_WIN_H_ diff --git a/chromium_src/chrome/utility/utility_message_handler.h b/chromium_src/chrome/utility/utility_message_handler.h deleted file mode 100644 index 3ccff1a0fbed0..0000000000000 --- a/chromium_src/chrome/utility/utility_message_handler.h +++ /dev/null @@ -1,21 +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_UTILITY_UTILITY_MESSAGE_HANDLER_H_ -#define CHROME_UTILITY_UTILITY_MESSAGE_HANDLER_H_ - -namespace IPC { -class Message; -} - -class UtilityMessageHandler { - public: - virtual ~UtilityMessageHandler() {} - - // Called when a message is received. Returns true iff the message was - // handled. - virtual bool OnMessageReceived(const IPC::Message& message) = 0; -}; - -#endif // CHROME_UTILITY_UTILITY_MESSAGE_HANDLER_H_ diff --git a/chromium_src/extensions/browser/app_window/size_constraints.cc b/chromium_src/extensions/browser/app_window/size_constraints.cc deleted file mode 100644 index 6d248c16017a7..0000000000000 --- a/chromium_src/extensions/browser/app_window/size_constraints.cc +++ /dev/null @@ -1,83 +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. - -#include "extensions/browser/app_window/size_constraints.h" - -#include - -#include "ui/gfx/geometry/insets.h" - -namespace extensions { - -SizeConstraints::SizeConstraints() - : maximum_size_(kUnboundedSize, kUnboundedSize) {} - -SizeConstraints::SizeConstraints(const gfx::Size& min_size, - const gfx::Size& max_size) - : minimum_size_(min_size), maximum_size_(max_size) {} - -SizeConstraints::~SizeConstraints() {} - -// static -gfx::Size SizeConstraints::AddFrameToConstraints( - const gfx::Size& size_constraints, - const gfx::Insets& frame_insets) { - return gfx::Size( - size_constraints.width() == kUnboundedSize - ? kUnboundedSize - : size_constraints.width() + frame_insets.width(), - size_constraints.height() == kUnboundedSize - ? kUnboundedSize - : size_constraints.height() + frame_insets.height()); -} - -gfx::Size SizeConstraints::ClampSize(gfx::Size size) const { - const gfx::Size max_size = GetMaximumSize(); - if (max_size.width() != kUnboundedSize) - size.set_width(std::min(size.width(), max_size.width())); - if (max_size.height() != kUnboundedSize) - size.set_height(std::min(size.height(), max_size.height())); - size.SetToMax(GetMinimumSize()); - return size; -} - -bool SizeConstraints::HasMinimumSize() const { - const gfx::Size min_size = GetMinimumSize(); - return min_size.width() != kUnboundedSize || - min_size.height() != kUnboundedSize; -} - -bool SizeConstraints::HasMaximumSize() const { - const gfx::Size max_size = GetMaximumSize(); - return max_size.width() != kUnboundedSize || - max_size.height() != kUnboundedSize; -} - -bool SizeConstraints::HasFixedSize() const { - return !GetMinimumSize().IsEmpty() && GetMinimumSize() == GetMaximumSize(); -} - -gfx::Size SizeConstraints::GetMinimumSize() const { - return minimum_size_; -} - -gfx::Size SizeConstraints::GetMaximumSize() const { - return gfx::Size( - maximum_size_.width() == kUnboundedSize - ? kUnboundedSize - : std::max(maximum_size_.width(), minimum_size_.width()), - maximum_size_.height() == kUnboundedSize - ? kUnboundedSize - : std::max(maximum_size_.height(), minimum_size_.height())); -} - -void SizeConstraints::set_minimum_size(const gfx::Size& min_size) { - minimum_size_ = min_size; -} - -void SizeConstraints::set_maximum_size(const gfx::Size& max_size) { - maximum_size_ = max_size; -} - -} // namespace extensions diff --git a/chromium_src/extensions/browser/app_window/size_constraints.h b/chromium_src/extensions/browser/app_window/size_constraints.h deleted file mode 100644 index ecacf1e5eb13e..0000000000000 --- a/chromium_src/extensions/browser/app_window/size_constraints.h +++ /dev/null @@ -1,57 +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. - -#ifndef EXTENSIONS_BROWSER_APP_WINDOW_SIZE_CONSTRAINTS_H_ -#define EXTENSIONS_BROWSER_APP_WINDOW_SIZE_CONSTRAINTS_H_ - -#include "ui/gfx/geometry/size.h" - -namespace gfx { -class Insets; -} - -namespace extensions { - -class SizeConstraints { - public: - // The value SizeConstraints uses to represent an unbounded width or height. - // This is an enum so that it can be declared inline here. - enum { kUnboundedSize = 0 }; - - SizeConstraints(); - SizeConstraints(const gfx::Size& min_size, const gfx::Size& max_size); - ~SizeConstraints(); - - // Adds frame insets to a size constraint. - static gfx::Size AddFrameToConstraints(const gfx::Size& size_constraints, - const gfx::Insets& frame_insets); - - // Returns the bounds with its size clamped to the min/max size. - gfx::Size ClampSize(gfx::Size size) const; - - // When gfx::Size is used as a min/max size, a zero represents an unbounded - // component. This method checks whether either component is specified. - // Note we can't use gfx::Size::IsEmpty as it returns true if either width - // or height is zero. - bool HasMinimumSize() const; - bool HasMaximumSize() const; - - // This returns true if all components are specified, and min and max are - // equal. - bool HasFixedSize() const; - - gfx::Size GetMaximumSize() const; - gfx::Size GetMinimumSize() const; - - void set_minimum_size(const gfx::Size& min_size); - void set_maximum_size(const gfx::Size& max_size); - - private: - gfx::Size minimum_size_; - gfx::Size maximum_size_; -}; - -} // namespace extensions - -#endif // EXTENSIONS_BROWSER_APP_WINDOW_SIZE_CONSTRAINTS_H_ diff --git a/chromium_src/extensions/common/url_pattern.cc b/chromium_src/extensions/common/url_pattern.cc deleted file mode 100644 index 4303689fe81c8..0000000000000 --- a/chromium_src/extensions/common/url_pattern.cc +++ /dev/null @@ -1,619 +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 "extensions/common/url_pattern.h" - -#include - -#include "base/strings/pattern.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "content/public/common/url_constants.h" -#include "net/base/registry_controlled_domains/registry_controlled_domain.h" -#include "url/gurl.h" -#include "url/url_util.h" - -const char extensions::URLPattern::kAllUrlsPattern[] = ""; -const char kExtensionScheme[] = "chrome-extension"; - -namespace { - -// TODO(aa): What about more obscure schemes like data: and javascript: ? -// Note: keep this array in sync with kValidSchemeMasks. -const char* kValidSchemes[] = { - url::kHttpScheme, - url::kHttpsScheme, - url::kFileScheme, - url::kFtpScheme, - content::kChromeUIScheme, - kExtensionScheme, - url::kFileSystemScheme, -}; - -const int kValidSchemeMasks[] = { - extensions::URLPattern::SCHEME_HTTP, - extensions::URLPattern::SCHEME_HTTPS, - extensions::URLPattern::SCHEME_FILE, - extensions::URLPattern::SCHEME_FTP, - extensions::URLPattern::SCHEME_CHROMEUI, - extensions::URLPattern::SCHEME_EXTENSION, - extensions::URLPattern::SCHEME_FILESYSTEM, -}; - -static_assert(arraysize(kValidSchemes) == arraysize(kValidSchemeMasks), - "must keep these arrays in sync"); - -const char kParseSuccess[] = "Success."; -const char kParseErrorMissingSchemeSeparator[] = "Missing scheme separator."; -const char kParseErrorInvalidScheme[] = "Invalid scheme."; -const char kParseErrorWrongSchemeType[] = "Wrong scheme type."; -const char kParseErrorEmptyHost[] = "Host can not be empty."; -const char kParseErrorInvalidHostWildcard[] = "Invalid host wildcard."; -const char kParseErrorEmptyPath[] = "Empty path."; -const char kParseErrorInvalidPort[] = "Invalid port."; -const char kParseErrorInvalidHost[] = "Invalid host."; - -// Message explaining each URLPattern::ParseResult. -const char* const kParseResultMessages[] = { - kParseSuccess, - kParseErrorMissingSchemeSeparator, - kParseErrorInvalidScheme, - kParseErrorWrongSchemeType, - kParseErrorEmptyHost, - kParseErrorInvalidHostWildcard, - kParseErrorEmptyPath, - kParseErrorInvalidPort, - kParseErrorInvalidHost, -}; - -static_assert(extensions::URLPattern::NUM_PARSE_RESULTS == arraysize(kParseResultMessages), - "must add message for each parse result"); - -const char kPathSeparator[] = "/"; - -bool IsStandardScheme(const std::string& scheme) { - // "*" gets the same treatment as a standard scheme. - if (scheme == "*") - return true; - - return url::IsStandard(scheme.c_str(), - url::Component(0, static_cast(scheme.length()))); -} - -bool IsValidPortForScheme(const std::string& scheme, const std::string& port) { - if (port == "*") - return true; - - // Only accept non-wildcard ports if the scheme uses ports. - if (url::DefaultPortForScheme(scheme.c_str(), scheme.length()) == - url::PORT_UNSPECIFIED) { - return false; - } - - int parsed_port = url::PORT_UNSPECIFIED; - if (!base::StringToInt(port, &parsed_port)) - return false; - return (parsed_port >= 0) && (parsed_port < 65536); -} - -// Returns |path| with the trailing wildcard stripped if one existed. -// -// The functions that rely on this (OverlapsWith and Contains) are only -// called for the patterns inside URLPatternSet. In those cases, we know that -// the path will have only a single wildcard at the end. This makes figuring -// out overlap much easier. It seems like there is probably a computer-sciency -// way to solve the general case, but we don't need that yet. -std::string StripTrailingWildcard(const std::string& path) { - size_t wildcard_index = path.find('*'); - size_t path_last = path.size() - 1; - return wildcard_index == path_last ? path.substr(0, path_last) : path; -} - -} // namespace - -namespace extensions { -// static -bool URLPattern::IsValidSchemeForExtensions(const std::string& scheme) { - for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { - if (scheme == kValidSchemes[i]) - return true; - } - return false; -} - -URLPattern::URLPattern() - : valid_schemes_(SCHEME_ALL), - match_all_urls_(false), - match_subdomains_(false), - port_("*") {} - -URLPattern::URLPattern(int valid_schemes) - : valid_schemes_(valid_schemes), - match_all_urls_(false), - match_subdomains_(false), - port_("*") {} - -URLPattern::URLPattern(int valid_schemes, const std::string& pattern) - // Strict error checking is used, because this constructor is only - // appropriate when we know |pattern| is valid. - : valid_schemes_(valid_schemes), - match_all_urls_(false), - match_subdomains_(false), - port_("*") { - ParseResult result = Parse(pattern); - if (PARSE_SUCCESS != result) - NOTREACHED() << "URLPattern invalid: " << pattern << " result " << result; -} - -URLPattern::~URLPattern() { -} - -bool URLPattern::operator<(const URLPattern& other) const { - return GetAsString() < other.GetAsString(); -} - -bool URLPattern::operator>(const URLPattern& other) const { - return GetAsString() > other.GetAsString(); -} - -bool URLPattern::operator==(const URLPattern& other) const { - return GetAsString() == other.GetAsString(); -} - -std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern) { - return out << '"' << url_pattern.GetAsString() << '"'; -} - -URLPattern::ParseResult URLPattern::Parse(const std::string& pattern) { - spec_.clear(); - SetMatchAllURLs(false); - SetMatchSubdomains(false); - SetPort("*"); - - // Special case pattern to match every valid URL. - if (pattern == kAllUrlsPattern) { - SetMatchAllURLs(true); - return PARSE_SUCCESS; - } - - // Parse out the scheme. - size_t scheme_end_pos = pattern.find(url::kStandardSchemeSeparator); - bool has_standard_scheme_separator = true; - - // Some urls also use ':' alone as the scheme separator. - if (scheme_end_pos == std::string::npos) { - scheme_end_pos = pattern.find(':'); - has_standard_scheme_separator = false; - } - - if (scheme_end_pos == std::string::npos) - return PARSE_ERROR_MISSING_SCHEME_SEPARATOR; - - if (!SetScheme(pattern.substr(0, scheme_end_pos))) - return PARSE_ERROR_INVALID_SCHEME; - - bool standard_scheme = IsStandardScheme(scheme_); - if (standard_scheme != has_standard_scheme_separator) - return PARSE_ERROR_WRONG_SCHEME_SEPARATOR; - - // Advance past the scheme separator. - scheme_end_pos += - (standard_scheme ? strlen(url::kStandardSchemeSeparator) : 1); - if (scheme_end_pos >= pattern.size()) - return PARSE_ERROR_EMPTY_HOST; - - // Parse out the host and path. - size_t host_start_pos = scheme_end_pos; - size_t path_start_pos = 0; - - if (!standard_scheme) { - path_start_pos = host_start_pos; - } else if (scheme_ == url::kFileScheme) { - size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); - if (host_end_pos == std::string::npos) { - // Allow hostname omission. - // e.g. file://* is interpreted as file:///*, - // file://foo* is interpreted as file:///foo*. - path_start_pos = host_start_pos - 1; - } else { - // Ignore hostname if scheme is file://. - // e.g. file://localhost/foo is equal to file:///foo. - path_start_pos = host_end_pos; - } - } else { - size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); - - // Host is required. - if (host_start_pos == host_end_pos) - return PARSE_ERROR_EMPTY_HOST; - - if (host_end_pos == std::string::npos) - return PARSE_ERROR_EMPTY_PATH; - - host_ = pattern.substr(host_start_pos, host_end_pos - host_start_pos); - - // The first component can optionally be '*' to match all subdomains. - std::vector host_components = base::SplitString( - host_, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - - // Could be empty if the host only consists of whitespace characters. - if (host_components.empty() || - (host_components.size() == 1 && host_components[0].empty())) - return PARSE_ERROR_EMPTY_HOST; - - if (host_components[0] == "*") { - match_subdomains_ = true; - host_components.erase(host_components.begin(), - host_components.begin() + 1); - } - host_ = base::JoinString(host_components, "."); - - path_start_pos = host_end_pos; - } - - SetPath(pattern.substr(path_start_pos)); - - size_t port_pos = host_.find(':'); - if (port_pos != std::string::npos) { - if (!SetPort(host_.substr(port_pos + 1))) - return PARSE_ERROR_INVALID_PORT; - host_ = host_.substr(0, port_pos); - } - - // No other '*' can occur in the host, though. This isn't necessary, but is - // done as a convenience to developers who might otherwise be confused and - // think '*' works as a glob in the host. - if (host_.find('*') != std::string::npos) - return PARSE_ERROR_INVALID_HOST_WILDCARD; - - // Null characters are not allowed in hosts. - if (host_.find('\0') != std::string::npos) - return PARSE_ERROR_INVALID_HOST; - - return PARSE_SUCCESS; -} - -void URLPattern::SetValidSchemes(int valid_schemes) { - spec_.clear(); - valid_schemes_ = valid_schemes; -} - -void URLPattern::SetHost(const std::string& host) { - spec_.clear(); - host_ = host; -} - -void URLPattern::SetMatchAllURLs(bool val) { - spec_.clear(); - match_all_urls_ = val; - - if (val) { - match_subdomains_ = true; - scheme_ = "*"; - host_.clear(); - SetPath("/*"); - } -} - -void URLPattern::SetMatchSubdomains(bool val) { - spec_.clear(); - match_subdomains_ = val; -} - -bool URLPattern::SetScheme(const std::string& scheme) { - spec_.clear(); - scheme_ = scheme; - if (scheme_ == "*") { - valid_schemes_ &= (SCHEME_HTTP | SCHEME_HTTPS); - } else if (!IsValidScheme(scheme_)) { - return false; - } - return true; -} - -bool URLPattern::IsValidScheme(const std::string& scheme) const { - if (valid_schemes_ == SCHEME_ALL) - return true; - - for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { - if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i])) - return true; - } - - return false; -} - -void URLPattern::SetPath(const std::string& path) { - spec_.clear(); - path_ = path; - path_escaped_ = path_; - base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "\\", "\\\\"); - base::ReplaceSubstringsAfterOffset(&path_escaped_, 0, "?", "\\?"); -} - -bool URLPattern::SetPort(const std::string& port) { - spec_.clear(); - if (IsValidPortForScheme(scheme_, port)) { - port_ = port; - return true; - } - return false; -} - -bool URLPattern::MatchesURL(const GURL& test) const { - const GURL* test_url = &test; - bool has_inner_url = test.inner_url() != NULL; - - if (has_inner_url) { - if (!test.SchemeIsFileSystem()) - return false; // The only nested URLs we handle are filesystem URLs. - test_url = test.inner_url(); - } - - if (!MatchesScheme(test_url->scheme())) - return false; - - if (match_all_urls_) - return true; - - std::string path_for_request = test.PathForRequest(); - if (has_inner_url) - path_for_request = test_url->path() + path_for_request; - - return MatchesSecurityOriginHelper(*test_url) && - MatchesPath(path_for_request); -} - -bool URLPattern::MatchesSecurityOrigin(const GURL& test) const { - const GURL* test_url = &test; - bool has_inner_url = test.inner_url() != NULL; - - if (has_inner_url) { - if (!test.SchemeIsFileSystem()) - return false; // The only nested URLs we handle are filesystem URLs. - test_url = test.inner_url(); - } - - if (!MatchesScheme(test_url->scheme())) - return false; - - if (match_all_urls_) - return true; - - return MatchesSecurityOriginHelper(*test_url); -} - -bool URLPattern::MatchesScheme(const std::string& test) const { - if (!IsValidScheme(test)) - return false; - - return scheme_ == "*" || test == scheme_; -} - -bool URLPattern::MatchesHost(const std::string& host) const { - std::string test(url::kHttpScheme); - test += url::kStandardSchemeSeparator; - test += host; - test += "/"; - return MatchesHost(GURL(test)); -} - -bool URLPattern::MatchesHost(const GURL& test) const { - // If the hosts are exactly equal, we have a match. - if (test.host() == host_) - return true; - - // If we're matching subdomains, and we have no host in the match pattern, - // that means that we're matching all hosts, which means we have a match no - // matter what the test host is. - if (match_subdomains_ && host_.empty()) - return true; - - // Otherwise, we can only match if our match pattern matches subdomains. - if (!match_subdomains_) - return false; - - // We don't do subdomain matching against IP addresses, so we can give up now - // if the test host is an IP address. - if (test.HostIsIPAddress()) - return false; - - // Check if the test host is a subdomain of our host. - if (test.host().length() <= (host_.length() + 1)) - return false; - - if (test.host().compare(test.host().length() - host_.length(), - host_.length(), host_) != 0) - return false; - - return test.host()[test.host().length() - host_.length() - 1] == '.'; -} - -bool URLPattern::ImpliesAllHosts() const { - // Check if it matches all urls or is a pattern like http://*/*. - if (match_all_urls_ || - (match_subdomains_ && host_.empty() && port_ == "*" && path_ == "/*")) { - return true; - } - - // If this doesn't even match subdomains, it can't possibly imply all hosts. - if (!match_subdomains_) - return false; - - // If |host_| is a recognized TLD, this will be 0. We don't include private - // TLDs, so that, e.g., *.appspot.com does not imply all hosts. - size_t registry_length = net::registry_controlled_domains::GetRegistryLength( - host_, - net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, - net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); - // If there was more than just a TLD in the host (e.g., *.foobar.com), it - // doesn't imply all hosts. - if (registry_length > 0) - return false; - - // At this point the host could either be just a TLD ("com") or some unknown - // TLD-like string ("notatld"). To disambiguate between them construct a - // fake URL, and check the registry. This returns 0 if the TLD is - // unrecognized, or the length of the recognized TLD. - registry_length = net::registry_controlled_domains::GetRegistryLength( - base::StringPrintf("foo.%s", host_.c_str()), - net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, - net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); - // If we recognized this TLD, then this is a pattern like *.com, and it - // should imply all hosts. Otherwise, this doesn't imply all hosts. - return registry_length > 0; -} - -bool URLPattern::MatchesSingleOrigin() const { - // Strictly speaking, the port is part of the origin, but in URLPattern it - // defaults to *. It's not very interesting anyway, so leave it out. - return !ImpliesAllHosts() && scheme_ != "*" && !match_subdomains_; -} - -bool URLPattern::MatchesPath(const std::string& test) const { - // Make the behaviour of OverlapsWith consistent with MatchesURL, which is - // need to match hosted apps on e.g. 'google.com' also run on 'google.com/'. - if (test + "/*" == path_escaped_) - return true; - - return base::MatchPattern(test, path_escaped_); -} - -const std::string& URLPattern::GetAsString() const { - if (!spec_.empty()) - return spec_; - - if (match_all_urls_) { - spec_ = kAllUrlsPattern; - return spec_; - } - - bool standard_scheme = IsStandardScheme(scheme_); - - std::string spec = scheme_ + - (standard_scheme ? url::kStandardSchemeSeparator : ":"); - - if (scheme_ != url::kFileScheme && standard_scheme) { - if (match_subdomains_) { - spec += "*"; - if (!host_.empty()) - spec += "."; - } - - if (!host_.empty()) - spec += host_; - - if (port_ != "*") { - spec += ":"; - spec += port_; - } - } - - if (!path_.empty()) - spec += path_; - - spec_ = spec; - return spec_; -} - -bool URLPattern::OverlapsWith(const URLPattern& other) const { - if (match_all_urls() || other.match_all_urls()) - return true; - return (MatchesAnyScheme(other.GetExplicitSchemes()) || - other.MatchesAnyScheme(GetExplicitSchemes())) - && (MatchesHost(other.host()) || other.MatchesHost(host())) - && (MatchesPortPattern(other.port()) || other.MatchesPortPattern(port())) - && (MatchesPath(StripTrailingWildcard(other.path())) || - other.MatchesPath(StripTrailingWildcard(path()))); -} - -bool URLPattern::Contains(const URLPattern& other) const { - if (match_all_urls()) - return true; - return MatchesAllSchemes(other.GetExplicitSchemes()) && - MatchesHost(other.host()) && - (!other.match_subdomains_ || match_subdomains_) && - MatchesPortPattern(other.port()) && - MatchesPath(StripTrailingWildcard(other.path())); -} - -bool URLPattern::MatchesAnyScheme( - const std::vector& schemes) const { - for (std::vector::const_iterator i = schemes.begin(); - i != schemes.end(); ++i) { - if (MatchesScheme(*i)) - return true; - } - - return false; -} - -bool URLPattern::MatchesAllSchemes( - const std::vector& schemes) const { - for (std::vector::const_iterator i = schemes.begin(); - i != schemes.end(); ++i) { - if (!MatchesScheme(*i)) - return false; - } - - return true; -} - -bool URLPattern::MatchesSecurityOriginHelper(const GURL& test) const { - // Ignore hostname if scheme is file://. - if (scheme_ != url::kFileScheme && !MatchesHost(test)) - return false; - - if (!MatchesPortPattern(base::IntToString(test.EffectiveIntPort()))) - return false; - - return true; -} - -bool URLPattern::MatchesPortPattern(const std::string& port) const { - return port_ == "*" || port_ == port; -} - -std::vector URLPattern::GetExplicitSchemes() const { - std::vector result; - - if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) { - result.push_back(scheme_); - return result; - } - - for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { - if (MatchesScheme(kValidSchemes[i])) { - result.push_back(kValidSchemes[i]); - } - } - - return result; -} - -std::vector URLPattern::ConvertToExplicitSchemes() const { - std::vector explicit_schemes = GetExplicitSchemes(); - std::vector result; - - for (std::vector::const_iterator i = explicit_schemes.begin(); - i != explicit_schemes.end(); ++i) { - URLPattern temp = *this; - temp.SetScheme(*i); - temp.SetMatchAllURLs(false); - result.push_back(temp); - } - - return result; -} - -// static -const char* URLPattern::GetParseResultString( - URLPattern::ParseResult parse_result) { - return kParseResultMessages[parse_result]; -} - -} // namespace extensions diff --git a/chromium_src/extensions/common/url_pattern.h b/chromium_src/extensions/common/url_pattern.h deleted file mode 100644 index fa9b6495e3172..0000000000000 --- a/chromium_src/extensions/common/url_pattern.h +++ /dev/null @@ -1,264 +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 EXTENSIONS_COMMON_URL_PATTERN_H_ -#define EXTENSIONS_COMMON_URL_PATTERN_H_ - -#include -#include -#include -#include - -class GURL; - -namespace extensions { -// A pattern that can be used to match URLs. A URLPattern is a very restricted -// subset of URL syntax: -// -// := :// | '' -// := '*' | 'http' | 'https' | 'file' | 'ftp' | 'chrome' | -// 'chrome-extension' | 'filesystem' -// := '*' | '*.' + -// := [':' ('*' | )] -// := '/' -// -// * Host is not used when the scheme is 'file'. -// * The path can have embedded '*' characters which act as glob wildcards. -// * '' is a special pattern that matches any URL that contains a -// valid scheme (as specified by valid_schemes_). -// * The '*' scheme pattern excludes file URLs. -// -// Examples of valid patterns: -// - http://*/* -// - http://*/foo* -// - https://*.google.com/foo*bar -// - file://monkey* -// - http://127.0.0.1/* -// -// Examples of invalid patterns: -// - http://* -- path not specified -// - http://*foo/bar -- * not allowed as substring of host component -// - http://foo.*.bar/baz -- * must be first component -// - http:/bar -- scheme separator not found -// - foo://* -- invalid scheme -// - chrome:// -- we don't support chrome internal URLs -class URLPattern { - public: - // A collection of scheme bitmasks for use with valid_schemes. - enum SchemeMasks { - SCHEME_NONE = 0, - SCHEME_HTTP = 1 << 0, - SCHEME_HTTPS = 1 << 1, - SCHEME_FILE = 1 << 2, - SCHEME_FTP = 1 << 3, - SCHEME_CHROMEUI = 1 << 4, - SCHEME_EXTENSION = 1 << 5, - SCHEME_FILESYSTEM = 1 << 6, - - // IMPORTANT! - // SCHEME_ALL will match every scheme, including chrome://, chrome- - // extension://, about:, etc. Because this has lots of security - // implications, third-party extensions should usually not be able to get - // access to URL patterns initialized this way. If there is a reason - // for violating this general rule, document why this it safe. - SCHEME_ALL = -1, - }; - - // Error codes returned from Parse(). - enum ParseResult { - PARSE_SUCCESS = 0, - PARSE_ERROR_MISSING_SCHEME_SEPARATOR, - PARSE_ERROR_INVALID_SCHEME, - PARSE_ERROR_WRONG_SCHEME_SEPARATOR, - PARSE_ERROR_EMPTY_HOST, - PARSE_ERROR_INVALID_HOST_WILDCARD, - PARSE_ERROR_EMPTY_PATH, - PARSE_ERROR_INVALID_PORT, - PARSE_ERROR_INVALID_HOST, - NUM_PARSE_RESULTS - }; - - // The string pattern. - static const char kAllUrlsPattern[]; - - // Returns true if the given |scheme| is considered valid for extensions. - static bool IsValidSchemeForExtensions(const std::string& scheme); - - explicit URLPattern(int valid_schemes); - - // Convenience to construct a URLPattern from a string. If the string is not - // known ahead of time, use Parse() instead, which returns success or failure. - URLPattern(int valid_schemes, const std::string& pattern); - - URLPattern(); - ~URLPattern(); - - bool operator<(const URLPattern& other) const; - bool operator>(const URLPattern& other) const; - bool operator==(const URLPattern& other) const; - - // Initializes this instance by parsing the provided string. Returns - // URLPattern::PARSE_SUCCESS on success, or an error code otherwise. On - // failure, this instance will have some intermediate values and is in an - // invalid state. - ParseResult Parse(const std::string& pattern_str); - - // Gets the bitmask of valid schemes. - int valid_schemes() const { return valid_schemes_; } - void SetValidSchemes(int valid_schemes); - - // Gets the host the pattern matches. This can be an empty string if the - // pattern matches all hosts (the input was ://*/). - const std::string& host() const { return host_; } - void SetHost(const std::string& host); - - // Gets whether to match subdomains of host(). - bool match_subdomains() const { return match_subdomains_; } - void SetMatchSubdomains(bool val); - - // Gets the path the pattern matches with the leading slash. This can have - // embedded asterisks which are interpreted using glob rules. - const std::string& path() const { return path_; } - void SetPath(const std::string& path); - - // Returns true if this pattern matches all urls. - bool match_all_urls() const { return match_all_urls_; } - void SetMatchAllURLs(bool val); - - // Sets the scheme for pattern matches. This can be a single '*' if the - // pattern matches all valid schemes (as defined by the valid_schemes_ - // property). Returns false on failure (if the scheme is not valid). - bool SetScheme(const std::string& scheme); - // Note: You should use MatchesScheme() instead of this getter unless you - // absolutely need the exact scheme. This is exposed for testing. - const std::string& scheme() const { return scheme_; } - - // Returns true if the specified scheme can be used in this URL pattern, and - // false otherwise. Uses valid_schemes_ to determine validity. - bool IsValidScheme(const std::string& scheme) const; - - // Returns true if this instance matches the specified URL. - bool MatchesURL(const GURL& test) const; - - // Returns true if this instance matches the specified security origin. - bool MatchesSecurityOrigin(const GURL& test) const; - - // Returns true if |test| matches our scheme. - // Note that if test is "filesystem", this may fail whereas MatchesURL - // may succeed. MatchesURL is smart enough to look at the inner_url instead - // of the outer "filesystem:" part. - bool MatchesScheme(const std::string& test) const; - - // Returns true if |test| matches our host. - bool MatchesHost(const std::string& test) const; - bool MatchesHost(const GURL& test) const; - - // Returns true if |test| matches our path. - bool MatchesPath(const std::string& test) const; - - // Returns true if the pattern is vague enough that it implies all hosts, - // such as *://*/*. - // This is an expensive method, and should be used sparingly! - // You should probably use URLPatternSet::ShouldWarnAllHosts(), which is - // cached. - bool ImpliesAllHosts() const; - - // Returns true if the pattern only matches a single origin. The pattern may - // include a path. - bool MatchesSingleOrigin() const; - - // Sets the port. Returns false if the port is invalid. - bool SetPort(const std::string& port); - const std::string& port() const { return port_; } - - // Returns a string representing this instance. - const std::string& GetAsString() const; - - // Determines whether there is a URL that would match this instance and - // another instance. This method is symmetrical: Calling - // other.OverlapsWith(this) would result in the same answer. - bool OverlapsWith(const URLPattern& other) const; - - // Returns true if this pattern matches all possible URLs that |other| can - // match. For example, http://*.google.com encompasses http://www.google.com. - bool Contains(const URLPattern& other) const; - - // Converts this URLPattern into an equivalent set of URLPatterns that don't - // use a wildcard in the scheme component. If this URLPattern doesn't use a - // wildcard scheme, then the returned set will contain one element that is - // equivalent to this instance. - std::vector ConvertToExplicitSchemes() const; - - static bool EffectiveHostCompare(const URLPattern& a, const URLPattern& b) { - if (a.match_all_urls_ && b.match_all_urls_) - return false; - return a.host_.compare(b.host_) < 0; - } - - // Used for origin comparisons in a std::set. - class EffectiveHostCompareFunctor { - public: - bool operator()(const URLPattern& a, const URLPattern& b) const { - return EffectiveHostCompare(a, b); - } - }; - - // Get an error string for a ParseResult. - static const char* GetParseResultString(URLPattern::ParseResult parse_result); - - private: - // Returns true if any of the |schemes| items matches our scheme. - bool MatchesAnyScheme(const std::vector& schemes) const; - - // Returns true if all of the |schemes| items matches our scheme. - bool MatchesAllSchemes(const std::vector& schemes) const; - - bool MatchesSecurityOriginHelper(const GURL& test) const; - - // Returns true if our port matches the |port| pattern (it may be "*"). - bool MatchesPortPattern(const std::string& port) const; - - // If the URLPattern contains a wildcard scheme, returns a list of - // equivalent literal schemes, otherwise returns the current scheme. - std::vector GetExplicitSchemes() const; - - // A bitmask containing the schemes which are considered valid for this - // pattern. Parse() uses this to decide whether a pattern contains a valid - // scheme. - int valid_schemes_; - - // True if this is a special-case "" pattern. - bool match_all_urls_; - - // The scheme for the pattern. - std::string scheme_; - - // The host without any leading "*" components. - std::string host_; - - // Whether we should match subdomains of the host. This is true if the first - // component of the pattern's host was "*". - bool match_subdomains_; - - // The port. - std::string port_; - - // The path to match. This is everything after the host of the URL, or - // everything after the scheme in the case of file:// URLs. - std::string path_; - - // The path with "?" and "\" characters escaped for use with the - // MatchPattern() function. - std::string path_escaped_; - - // A string representing this URLPattern. - mutable std::string spec_; -}; - -std::ostream& operator<<(std::ostream& out, const URLPattern& url_pattern); - -typedef std::vector URLPatternList; - -} // namespace extensions - -#endif // EXTENSIONS_COMMON_URL_PATTERN_H_ diff --git a/chromium_src/library_loaders/libspeechd.h b/chromium_src/library_loaders/libspeechd.h deleted file mode 100644 index f7b276287a416..0000000000000 --- a/chromium_src/library_loaders/libspeechd.h +++ /dev/null @@ -1,53 +0,0 @@ -// This is generated file. Do not modify directly. -// Path to the code generator: tools/generate_library_loader/generate_library_loader.py . - -#ifndef LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H -#define LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H - -#include "third_party/speech-dispatcher/libspeechd.h" -#define LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN - - -#include - -class LibSpeechdLoader { - public: - LibSpeechdLoader(); - ~LibSpeechdLoader(); - - bool Load(const std::string& library_name) - __attribute__((warn_unused_result)); - - bool loaded() const { return loaded_; } - - decltype(&::spd_open) spd_open; - decltype(&::spd_say) spd_say; - decltype(&::spd_stop) spd_stop; - decltype(&::spd_close) spd_close; - decltype(&::spd_pause) spd_pause; - decltype(&::spd_resume) spd_resume; - decltype(&::spd_set_notification_on) spd_set_notification_on; - decltype(&::spd_set_voice_rate) spd_set_voice_rate; - decltype(&::spd_set_voice_pitch) spd_set_voice_pitch; - decltype(&::spd_list_synthesis_voices) spd_list_synthesis_voices; - decltype(&::spd_set_synthesis_voice) spd_set_synthesis_voice; - decltype(&::spd_list_modules) spd_list_modules; - decltype(&::spd_set_output_module) spd_set_output_module; - decltype(&::spd_set_language) spd_set_language; - - - private: - void CleanUp(bool unload); - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - void* library_; -#endif - - bool loaded_; - - // Disallow copy constructor and assignment operator. - LibSpeechdLoader(const LibSpeechdLoader&); - void operator=(const LibSpeechdLoader&); -}; - -#endif // LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H diff --git a/chromium_src/library_loaders/libspeechd_loader.cc b/chromium_src/library_loaders/libspeechd_loader.cc deleted file mode 100644 index f09ea3ae861bd..0000000000000 --- a/chromium_src/library_loaders/libspeechd_loader.cc +++ /dev/null @@ -1,245 +0,0 @@ -// This is generated file. Do not modify directly. -// Path to the code generator: tools/generate_library_loader/generate_library_loader.py . - -#include "library_loaders/libspeechd.h" - -#include - -// Put these sanity checks here so that they fire at most once -// (to avoid cluttering the build output). -#if !defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) && !defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) -#error neither LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN nor LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED defined -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) && defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) -#error both LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN and LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED defined -#endif - -LibSpeechdLoader::LibSpeechdLoader() : loaded_(false) { -} - -LibSpeechdLoader::~LibSpeechdLoader() { - CleanUp(loaded_); -} - -bool LibSpeechdLoader::Load(const std::string& library_name) { - if (loaded_) - return false; - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - library_ = dlopen(library_name.c_str(), RTLD_LAZY); - if (!library_) - return false; -#endif - - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_open = - reinterpret_castspd_open)>( - dlsym(library_, "spd_open")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_open = &::spd_open; -#endif - if (!spd_open) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_say = - reinterpret_castspd_say)>( - dlsym(library_, "spd_say")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_say = &::spd_say; -#endif - if (!spd_say) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_stop = - reinterpret_castspd_stop)>( - dlsym(library_, "spd_stop")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_stop = &::spd_stop; -#endif - if (!spd_stop) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_close = - reinterpret_castspd_close)>( - dlsym(library_, "spd_close")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_close = &::spd_close; -#endif - if (!spd_close) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_pause = - reinterpret_castspd_pause)>( - dlsym(library_, "spd_pause")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_pause = &::spd_pause; -#endif - if (!spd_pause) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_resume = - reinterpret_castspd_resume)>( - dlsym(library_, "spd_resume")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_resume = &::spd_resume; -#endif - if (!spd_resume) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_set_notification_on = - reinterpret_castspd_set_notification_on)>( - dlsym(library_, "spd_set_notification_on")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_set_notification_on = &::spd_set_notification_on; -#endif - if (!spd_set_notification_on) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_set_voice_rate = - reinterpret_castspd_set_voice_rate)>( - dlsym(library_, "spd_set_voice_rate")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_set_voice_rate = &::spd_set_voice_rate; -#endif - if (!spd_set_voice_rate) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_set_voice_pitch = - reinterpret_castspd_set_voice_pitch)>( - dlsym(library_, "spd_set_voice_pitch")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_set_voice_pitch = &::spd_set_voice_pitch; -#endif - if (!spd_set_voice_pitch) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_list_synthesis_voices = - reinterpret_castspd_list_synthesis_voices)>( - dlsym(library_, "spd_list_synthesis_voices")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_list_synthesis_voices = &::spd_list_synthesis_voices; -#endif - if (!spd_list_synthesis_voices) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_set_synthesis_voice = - reinterpret_castspd_set_synthesis_voice)>( - dlsym(library_, "spd_set_synthesis_voice")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_set_synthesis_voice = &::spd_set_synthesis_voice; -#endif - if (!spd_set_synthesis_voice) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_list_modules = - reinterpret_castspd_list_modules)>( - dlsym(library_, "spd_list_modules")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_list_modules = &::spd_list_modules; -#endif - if (!spd_list_modules) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_set_output_module = - reinterpret_castspd_set_output_module)>( - dlsym(library_, "spd_set_output_module")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_set_output_module = &::spd_set_output_module; -#endif - if (!spd_set_output_module) { - CleanUp(true); - return false; - } - -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - spd_set_language = - reinterpret_castspd_set_language)>( - dlsym(library_, "spd_set_language")); -#endif -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DT_NEEDED) - spd_set_language = &::spd_set_language; -#endif - if (!spd_set_language) { - CleanUp(true); - return false; - } - - - loaded_ = true; - return true; -} - -void LibSpeechdLoader::CleanUp(bool unload) { -#if defined(LIBRARY_LOADER_OUT_RELEASE_GEN_LIBRARY_LOADERS_LIBSPEECHD_H_DLOPEN) - if (unload) { - dlclose(library_); - library_ = NULL; - } -#endif - loaded_ = false; - spd_open = NULL; - spd_say = NULL; - spd_stop = NULL; - spd_close = NULL; - spd_pause = NULL; - spd_resume = NULL; - spd_set_notification_on = NULL; - spd_set_voice_rate = NULL; - spd_set_voice_pitch = NULL; - spd_list_synthesis_voices = NULL; - spd_set_synthesis_voice = NULL; - spd_list_modules = NULL; - spd_set_output_module = NULL; - spd_set_language = NULL; - -} diff --git a/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc b/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc deleted file mode 100644 index 0b16c1395ebde..0000000000000 --- a/chromium_src/net/test/embedded_test_server/stream_listen_socket.cc +++ /dev/null @@ -1,333 +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 "net/test/embedded_test_server/stream_listen_socket.h" - -#include - -#if defined(OS_WIN) -// winsock2.h must be included first in order to ensure it is included before -// windows.h. -#include -#elif defined(OS_POSIX) -#include -#include -#include -#include -#include -#include "net/base/net_errors.h" -#endif - -#include "base/files/file_util.h" -#include "base/logging.h" -#include "base/memory/ref_counted.h" -#include "base/posix/eintr_wrapper.h" -#include "base/sys_byteorder.h" -#include "base/threading/platform_thread.h" -#include "build/build_config.h" -#include "net/base/ip_endpoint.h" -#include "net/base/net_errors.h" -#include "net/base/network_interfaces.h" -#include "net/base/sockaddr_storage.h" -#include "net/socket/socket_descriptor.h" - -using std::string; - -#if defined(OS_WIN) -typedef int socklen_t; -#endif // defined(OS_WIN) - -namespace net { - -namespace test_server { - -namespace { - -const int kReadBufSize = 4096; - -} // namespace - -#if defined(OS_WIN) -const int StreamListenSocket::kSocketError = SOCKET_ERROR; -#elif defined(OS_POSIX) -const int StreamListenSocket::kSocketError = -1; -#endif - -StreamListenSocket::StreamListenSocket(SocketDescriptor s, - StreamListenSocket::Delegate* del) - : socket_delegate_(del), - socket_(s), - reads_paused_(false), - has_pending_reads_(false) { -#if defined(OS_WIN) - socket_event_ = WSACreateEvent(); - // TODO(ibrar): error handling in case of socket_event_ == WSA_INVALID_EVENT. - WatchSocket(NOT_WAITING); -#elif defined(OS_POSIX) - wait_state_ = NOT_WAITING; -#endif -} - -StreamListenSocket::~StreamListenSocket() { - CloseSocket(); -#if defined(OS_WIN) - if (socket_event_) { - WSACloseEvent(socket_event_); - socket_event_ = WSA_INVALID_EVENT; - } -#endif -} - -void StreamListenSocket::Send(const char* bytes, - int len, - bool append_linefeed) { - SendInternal(bytes, len); - if (append_linefeed) - SendInternal("\r\n", 2); -} - -void StreamListenSocket::Send(const string& str, bool append_linefeed) { - Send(str.data(), static_cast(str.length()), append_linefeed); -} - -int StreamListenSocket::GetLocalAddress(IPEndPoint* address) const { - SockaddrStorage storage; - if (getsockname(socket_, storage.addr, &storage.addr_len)) { -#if defined(OS_WIN) - int err = WSAGetLastError(); -#else - int err = errno; -#endif - return MapSystemError(err); - } - if (!address->FromSockAddr(storage.addr, storage.addr_len)) - return ERR_ADDRESS_INVALID; - return OK; -} - -int StreamListenSocket::GetPeerAddress(IPEndPoint* address) const { - SockaddrStorage storage; - if (getpeername(socket_, storage.addr, &storage.addr_len)) { -#if defined(OS_WIN) - int err = WSAGetLastError(); -#else - int err = errno; -#endif - return MapSystemError(err); - } - - if (!address->FromSockAddr(storage.addr, storage.addr_len)) - return ERR_ADDRESS_INVALID; - - return OK; -} - -SocketDescriptor StreamListenSocket::AcceptSocket() { - SocketDescriptor conn = HANDLE_EINTR(accept(socket_, NULL, NULL)); - if (conn == kInvalidSocket) - LOG(ERROR) << "Error accepting connection."; - else - base::SetNonBlocking(conn); - return conn; -} - -void StreamListenSocket::SendInternal(const char* bytes, int len) { - char* send_buf = const_cast(bytes); - int len_left = len; - while (true) { - int sent = HANDLE_EINTR(send(socket_, send_buf, len_left, 0)); - if (sent == len_left) { // A shortcut to avoid extraneous checks. - break; - } - if (sent == kSocketError) { -#if defined(OS_WIN) - if (WSAGetLastError() != WSAEWOULDBLOCK) { - LOG(ERROR) << "send failed: WSAGetLastError()==" << WSAGetLastError(); -#elif defined(OS_POSIX) - if (errno != EWOULDBLOCK && errno != EAGAIN) { - LOG(ERROR) << "send failed: errno==" << errno; -#endif - break; - } - // Otherwise we would block, and now we have to wait for a retry. - // Fall through to PlatformThread::YieldCurrentThread() - } else { - // sent != len_left according to the shortcut above. - // Shift the buffer start and send the remainder after a short while. - send_buf += sent; - len_left -= sent; - } - base::PlatformThread::YieldCurrentThread(); - } -} - -void StreamListenSocket::Listen() { - int backlog = 10; // TODO(erikkay): maybe don't allow any backlog? - if (listen(socket_, backlog) == -1) { - // TODO(erikkay): error handling. - LOG(ERROR) << "Could not listen on socket."; - return; - } -#if defined(OS_POSIX) - WatchSocket(WAITING_ACCEPT); -#endif -} - -void StreamListenSocket::Read() { - char buf[kReadBufSize + 1]; // +1 for null termination. - int len; - do { - len = HANDLE_EINTR(recv(socket_, buf, kReadBufSize, 0)); - if (len == kSocketError) { -#if defined(OS_WIN) - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK) { -#elif defined(OS_POSIX) - if (errno == EWOULDBLOCK || errno == EAGAIN) { -#endif - break; - } else { - // TODO(ibrar): some error handling required here. - break; - } - } else if (len == 0) { -#if defined(OS_POSIX) - // In Windows, Close() is called by OnObjectSignaled. In POSIX, we need - // to call it here. - Close(); -#endif - } else { - // TODO(ibrar): maybe change DidRead to take a length instead. - DCHECK_GT(len, 0); - DCHECK_LE(len, kReadBufSize); - buf[len] = 0; // Already create a buffer with +1 length. - socket_delegate_->DidRead(this, buf, len); - } - } while (len == kReadBufSize); -} - -void StreamListenSocket::Close() { -#if defined(OS_POSIX) - if (wait_state_ == NOT_WAITING) - return; - wait_state_ = NOT_WAITING; -#endif - UnwatchSocket(); - socket_delegate_->DidClose(this); -} - -void StreamListenSocket::CloseSocket() { - if (socket_ != kInvalidSocket) { - UnwatchSocket(); -#if defined(OS_WIN) - closesocket(socket_); -#elif defined(OS_POSIX) - close(socket_); -#endif - } -} - -void StreamListenSocket::WatchSocket(WaitState state) { -#if defined(OS_WIN) - WSAEventSelect(socket_, socket_event_, FD_ACCEPT | FD_CLOSE | FD_READ); - watcher_.StartWatchingOnce(socket_event_, this); -#elif defined(OS_POSIX) - // Implicitly calls StartWatchingFileDescriptor(). - base::MessageLoopForIO::current()->WatchFileDescriptor( - socket_, true, base::MessageLoopForIO::WATCH_READ, &watcher_, this); - wait_state_ = state; -#endif -} - -void StreamListenSocket::UnwatchSocket() { -#if defined(OS_WIN) - watcher_.StopWatching(); -#elif defined(OS_POSIX) - watcher_.StopWatchingFileDescriptor(); -#endif -} - -// TODO(ibrar): We can add these functions into OS dependent files. -#if defined(OS_WIN) -// MessageLoop watcher callback. -void StreamListenSocket::OnObjectSignaled(HANDLE object) { - WSANETWORKEVENTS ev; - if (kSocketError == WSAEnumNetworkEvents(socket_, socket_event_, &ev)) { - // TODO - return; - } - - // If both FD_CLOSE and FD_READ are set we only call Read(). - // This will cause OnObjectSignaled to be called immediately again - // unless this socket is destroyed in Read(). - if ((ev.lNetworkEvents & (FD_CLOSE | FD_READ)) == FD_CLOSE) { - Close(); - // Close might have deleted this object. We should return immediately. - return; - } - // The object was reset by WSAEnumNetworkEvents. Watch for the next signal. - watcher_.StartWatchingOnce(object, this); - - if (ev.lNetworkEvents == 0) { - // Occasionally the event is set even though there is no new data. - // The net seems to think that this is ignorable. - return; - } - if (ev.lNetworkEvents & FD_ACCEPT) { - Accept(); - } - if (ev.lNetworkEvents & FD_READ) { - if (reads_paused_) { - has_pending_reads_ = true; - } else { - Read(); - // Read might have deleted this object. We should return immediately. - } - } -} -#elif defined(OS_POSIX) -void StreamListenSocket::OnFileCanReadWithoutBlocking(int fd) { - switch (wait_state_) { - case WAITING_ACCEPT: - Accept(); - break; - case WAITING_READ: - if (reads_paused_) { - has_pending_reads_ = true; - } else { - Read(); - } - break; - default: - // Close() is called by Read() in the Linux case. - NOTREACHED(); - break; - } -} - -void StreamListenSocket::OnFileCanWriteWithoutBlocking(int fd) { - // MessagePumpLibevent callback, we don't listen for write events - // so we shouldn't ever reach here. - NOTREACHED(); -} - -#endif - -void StreamListenSocket::PauseReads() { - DCHECK(!reads_paused_); - reads_paused_ = true; -} - -void StreamListenSocket::ResumeReads() { - DCHECK(reads_paused_); - reads_paused_ = false; - if (has_pending_reads_) { - has_pending_reads_ = false; - Read(); - } -} - -} // namespace test_server - -} // namespace net diff --git a/chromium_src/net/test/embedded_test_server/stream_listen_socket.h b/chromium_src/net/test/embedded_test_server/stream_listen_socket.h deleted file mode 100644 index 00d4b58dcf3b3..0000000000000 --- a/chromium_src/net/test/embedded_test_server/stream_listen_socket.h +++ /dev/null @@ -1,152 +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. - -// Stream-based listen socket implementation that handles reading and writing -// to the socket, but does not handle creating the socket nor connecting -// sockets, which are handled by subclasses on creation and in Accept, -// respectively. - -// StreamListenSocket handles IO asynchronously in the specified MessageLoop. -// This class is NOT thread safe. It uses WSAEVENT handles to monitor activity -// in a given MessageLoop. This means that callbacks will happen in that loop's -// thread always and that all other methods (including constructor and -// destructor) should also be called from the same thread. - -#ifndef NET_TEST_EMBEDDED_TEST_SERVER_STREAM_LISTEN_SOCKET_H_ -#define NET_TEST_EMBEDDED_TEST_SERVER_STREAM_LISTEN_SOCKET_H_ - -#include - -#include "build/build_config.h" - -#if defined(OS_WIN) -#include -#endif -#include -#if defined(OS_WIN) -#include "base/win/object_watcher.h" -#elif defined(OS_POSIX) -#include "base/message_loop/message_loop.h" -#endif - -#include "base/macros.h" -#include "base/compiler_specific.h" -#include "net/base/net_export.h" -#include "net/socket/socket_descriptor.h" - -namespace net { - -class IPEndPoint; - -namespace test_server { - -class StreamListenSocket : -#if defined(OS_WIN) - public base::win::ObjectWatcher::Delegate { -#elif defined(OS_POSIX) - public base::MessageLoopForIO::Watcher { -#endif - - public: - ~StreamListenSocket() override; - - // TODO(erikkay): this delegate should really be split into two parts - // to split up the listener from the connected socket. Perhaps this class - // should be split up similarly. - class Delegate { - public: - // |server| is the original listening Socket, connection is the new - // Socket that was created. - virtual void DidAccept(StreamListenSocket* server, - std::unique_ptr connection) = 0; - virtual void DidRead(StreamListenSocket* connection, - const char* data, - int len) = 0; - virtual void DidClose(StreamListenSocket* sock) = 0; - - protected: - virtual ~Delegate() {} - }; - - // Send data to the socket. - void Send(const char* bytes, int len, bool append_linefeed = false); - void Send(const std::string& str, bool append_linefeed = false); - - // Copies the local address to |address|. Returns a network error code. - // This method is virtual to support unit testing. - virtual int GetLocalAddress(IPEndPoint* address) const; - // Copies the peer address to |address|. Returns a network error code. - // This method is virtual to support unit testing. - virtual int GetPeerAddress(IPEndPoint* address) const; - - static const int kSocketError; - - protected: - enum WaitState { NOT_WAITING = 0, WAITING_ACCEPT = 1, WAITING_READ = 2 }; - - StreamListenSocket(SocketDescriptor s, Delegate* del); - - SocketDescriptor AcceptSocket(); - virtual void Accept() = 0; - - void Listen(); - void Read(); - void Close(); - void CloseSocket(); - - // Pass any value in case of Windows, because in Windows - // we are not using state. - void WatchSocket(WaitState state); - void UnwatchSocket(); - - Delegate* const socket_delegate_; - - private: - friend class TransportClientSocketTest; - - void SendInternal(const char* bytes, int len); - -#if defined(OS_WIN) - // ObjectWatcher delegate. - void OnObjectSignaled(HANDLE object) override; - base::win::ObjectWatcher watcher_; - HANDLE socket_event_; -#elif defined(OS_POSIX) - // Called by MessagePumpLibevent when the socket is ready to do I/O. - void OnFileCanReadWithoutBlocking(int fd) override; - void OnFileCanWriteWithoutBlocking(int fd) override; - WaitState wait_state_; - // The socket's libevent wrapper. - base::MessageLoopForIO::FileDescriptorWatcher watcher_; -#endif - - // NOTE: This is for unit test use only! - // Pause/Resume calling Read(). Note that ResumeReads() will also call - // Read() if there is anything to read. - void PauseReads(); - void ResumeReads(); - - const SocketDescriptor socket_; - bool reads_paused_; - bool has_pending_reads_; - - DISALLOW_COPY_AND_ASSIGN(StreamListenSocket); -}; - -// Abstract factory that must be subclassed for each subclass of -// StreamListenSocket. -class StreamListenSocketFactory { - public: - virtual ~StreamListenSocketFactory() {} - - // Returns a new instance of StreamListenSocket or NULL if an error occurred. - virtual std::unique_ptr CreateAndListen( - StreamListenSocket::Delegate* delegate) const = 0; -}; - -} // namespace test_server - -} // namespace net - -#endif // NET_TEST_EMBEDDED_TEST_SERVER_STREAM_LISTEN_SOCKET_H_ diff --git a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc b/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc deleted file mode 100644 index 50aac809052e9..0000000000000 --- a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.cc +++ /dev/null @@ -1,120 +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 "net/test/embedded_test_server/tcp_listen_socket.h" - -#if defined(OS_WIN) -// winsock2.h must be included first in order to ensure it is included before -// windows.h. -#include -#include -#elif defined(OS_POSIX) -#include -#include -#include -#include -#include -#include "net/base/net_errors.h" -#endif - -#include "base/logging.h" -#include "base/sys_byteorder.h" -#include "base/threading/platform_thread.h" -#include "build/build_config.h" -#include "net/base/network_interfaces.h" -#include "net/base/winsock_init.h" -#include "net/socket/socket_descriptor.h" - -using std::string; - -namespace net { - -namespace test_server { - -// static -std::unique_ptr TCPListenSocket::CreateAndListen( - const string& ip, - uint16_t port, - StreamListenSocket::Delegate* del) { - SocketDescriptor s = CreateAndBind(ip, port); - if (s == kInvalidSocket) - return std::unique_ptr(); - std::unique_ptr sock(new TCPListenSocket(s, del)); - sock->Listen(); - return sock; -} - -TCPListenSocket::TCPListenSocket(SocketDescriptor s, - StreamListenSocket::Delegate* del) - : StreamListenSocket(s, del) { -} - -TCPListenSocket::~TCPListenSocket() { -} - -SocketDescriptor TCPListenSocket::CreateAndBind(const string& ip, - uint16_t port) { - SocketDescriptor s = CreatePlatformSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s != kInvalidSocket) { -#if defined(OS_POSIX) - // Allow rapid reuse. - static const int kOn = 1; - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn)); -#endif - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr(ip.c_str()); - addr.sin_port = base::HostToNet16(port); - if (bind(s, reinterpret_cast(&addr), sizeof(addr))) { -#if defined(OS_WIN) - closesocket(s); -#elif defined(OS_POSIX) - close(s); -#endif - LOG(ERROR) << "Could not bind socket to " << ip << ":" << port; - s = kInvalidSocket; - } - } - return s; -} - -SocketDescriptor TCPListenSocket::CreateAndBindAnyPort(const string& ip, - uint16_t* port) { - SocketDescriptor s = CreateAndBind(ip, 0); - if (s == kInvalidSocket) - return kInvalidSocket; - sockaddr_in addr; - socklen_t addr_size = sizeof(addr); - bool failed = getsockname(s, reinterpret_cast(&addr), - &addr_size) != 0; - if (addr_size != sizeof(addr)) - failed = true; - if (failed) { - LOG(ERROR) << "Could not determine bound port, getsockname() failed"; -#if defined(OS_WIN) - closesocket(s); -#elif defined(OS_POSIX) - close(s); -#endif - return kInvalidSocket; - } - *port = base::NetToHost16(addr.sin_port); - return s; -} - -void TCPListenSocket::Accept() { - SocketDescriptor conn = AcceptSocket(); - if (conn == kInvalidSocket) - return; - std::unique_ptr sock(new TCPListenSocket(conn, socket_delegate_)); -#if defined(OS_POSIX) - sock->WatchSocket(WAITING_READ); -#endif - socket_delegate_->DidAccept(this, std::move(sock)); -} - -} // namespace test_server - -} // namespace net diff --git a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h b/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h deleted file mode 100644 index db18fd0f0eb46..0000000000000 --- a/chromium_src/net/test/embedded_test_server/tcp_listen_socket.h +++ /dev/null @@ -1,55 +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 NET_TEST_EMBEDDED_TEST_SERVER_TCP_LISTEN_SOCKET_H_ -#define NET_TEST_EMBEDDED_TEST_SERVER_TCP_LISTEN_SOCKET_H_ - -#include - -#include "base/macros.h" -#include "net/base/net_export.h" -#include "net/socket/socket_descriptor.h" -#include "net/test/embedded_test_server/stream_listen_socket.h" - -namespace net { - -namespace test_server { - -// Implements a TCP socket. -class TCPListenSocket : public StreamListenSocket { - public: - ~TCPListenSocket() override; - - // Listen on port for the specified IP address. Use 127.0.0.1 to only - // accept local connections. - static std::unique_ptr CreateAndListen( - const std::string& ip, - uint16_t port, - StreamListenSocket::Delegate* del); - - protected: - TCPListenSocket(SocketDescriptor s, StreamListenSocket::Delegate* del); - - // Implements StreamListenSocket::Accept. - void Accept() override; - - private: - friend class EmbeddedTestServer; - friend class TCPListenSocketTester; - - // Get raw TCP socket descriptor bound to ip:port. - static SocketDescriptor CreateAndBind(const std::string& ip, uint16_t port); - - // Get raw TCP socket descriptor bound to ip and return port it is bound to. - static SocketDescriptor CreateAndBindAnyPort(const std::string& ip, - uint16_t* port); - - DISALLOW_COPY_AND_ASSIGN(TCPListenSocket); -}; - -} // namespace test_server - -} // namespace net - -#endif // NET_TEST_EMBEDDED_TEST_SERVER_TCP_LISTEN_SOCKET_H_ diff --git a/common.gypi b/common.gypi deleted file mode 100644 index 2a22c957c91ea..0000000000000 --- a/common.gypi +++ /dev/null @@ -1,293 +0,0 @@ -{ - 'includes': [ - 'toolchain.gypi', - 'vendor/brightray/brightray.gypi', - ], - 'variables': { - # Tell crashpad to build as external project. - 'crashpad_dependencies': 'external', - # Required by breakpad. - 'os_bsd': 0, - 'chromeos': 0, - # Reflects node's config.gypi. - 'component%': 'static_library', - 'python': 'python', - 'openssl_fips': '', - 'openssl_no_asm': 1, - 'use_openssl_def': 0, - 'OPENSSL_PRODUCT': 'libopenssl.a', - 'node_release_urlbase': 'https://atom.io/download/atom-shell', - 'node_byteorder': ' { - app.quit() -}) - -exports.load = (appUrl) => { - app.on('ready', () => { - const options = { - width: 800, - height: 600, - autoHideMenuBar: true, - backgroundColor: '#FFFFFF', - useContentSize: true - } - if (process.platform === 'linux') { - options.icon = path.join(__dirname, 'icon.png') - } - - mainWindow = new BrowserWindow(options) - mainWindow.loadURL(appUrl) - mainWindow.focus() - }) -} diff --git a/default_app/default_app.ts b/default_app/default_app.ts new file mode 100644 index 0000000000000..3f4b60b06c242 --- /dev/null +++ b/default_app/default_app.ts @@ -0,0 +1,143 @@ +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; + +// Quit when all windows are closed. +app.on('window-all-closed', () => { + app.quit(); +}); + +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 indexPath = path.resolve(app.getAppPath(), 'index.html'); + +function isTrustedSender(webContents: Electron.WebContents) { + if (webContents !== (mainWindow && mainWindow.webContents)) { + return false; + } + + try { + return url.fileURLToPath(webContents.getURL()) === indexPath; + } catch { + return false; + } +} + +ipcMain.handle('bootstrap', (event) => { + return isTrustedSender(event.sender) ? electronPath : null; +}); + +async function createWindow(backgroundColor?: string) { + await app.whenReady(); + + const options: Electron.BrowserWindowConstructorOptions = { + width: 960, + height: 620, + autoHideMenuBar: true, + backgroundColor, + webPreferences: { + preload: url.fileURLToPath(new URL('preload.js', import.meta.url)), + contextIsolation: true, + sandbox: true, + nodeIntegration: false + }, + useContentSize: true, + show: false + }; + + if (process.platform === 'linux') { + options.icon = url.fileURLToPath(new URL('icon.png', import.meta.url)); + } + + mainWindow = new BrowserWindow(options); + mainWindow.on('ready-to-show', () => mainWindow!.show()); + + mainWindow.webContents.setWindowOpenHandler((details) => { + shell.openExternal(details.url); + return { action: 'deny' }; + }); + + mainWindow.webContents.session.setPermissionRequestHandler((webContents, permission, done) => { + const parsedUrl = new URL(webContents.getURL()); + + const options: Electron.MessageBoxOptions = { + title: 'Permission Request', + message: `Allow '${parsedUrl.origin}' to access '${permission}'?`, + buttons: ['OK', 'Cancel'], + cancelId: 1 + }; + + dialog.showMessageBox(mainWindow!, options).then(({ response }) => { + done(response === 0); + }); + }); + + return mainWindow; +} + +export const loadURL = async (appUrl: string) => { + mainWindow = await createWindow(); + mainWindow.loadURL(appUrl); + mainWindow.focus(); +}; + +export const loadFile = async (appPath: string) => { + mainWindow = await createWindow(appPath === 'index.html' ? '#2f3241' : undefined); + mainWindow.loadFile(appPath); + mainWindow.focus(); +}; diff --git a/default_app/icon.png b/default_app/icon.png index ac3a6547d9ecc..bc527dda8ae2c 100644 Binary files a/default_app/icon.png and b/default_app/icon.png differ diff --git a/default_app/index.html b/default_app/index.html index 67e3e249e37a1..5ac92e4fb8f17 100644 --- a/default_app/index.html +++ b/default_app/index.html @@ -1,219 +1,92 @@ + Electron - + + + + - - -
- + - -
- -

- To run your app with Electron, execute the following command in your - Console (or Terminal): -

- - - -

- The path-to-your-app should be the path to your own Electron - app. -

- -

You can read the - - guide in Electron's - - to learn how to write one. -

- -

- Or you can just drag your app here to run it: -

- -
- Drag your app here to run it +

To run a local app, execute the following on the command line:

+

+
+    
- -
- + - + + \ No newline at end of file diff --git a/default_app/main.js b/default_app/main.js deleted file mode 100644 index b4d74d8109541..0000000000000 --- a/default_app/main.js +++ /dev/null @@ -1,370 +0,0 @@ -const {app, dialog, shell, Menu} = require('electron') - -const fs = require('fs') -const Module = require('module') -const path = require('path') -const url = require('url') - -// Parse command line options. -const argv = process.argv.slice(1) -const option = { file: null, help: null, version: null, abi: null, webdriver: null, modules: [] } -for (let i = 0; i < argv.length; i++) { - if (argv[i] === '--version' || argv[i] === '-v') { - option.version = true - break - } else if (argv[i] === '--abi') { - option.abi = true - break - } else if (argv[i].match(/^--app=/)) { - option.file = argv[i].split('=')[1] - break - } else if (argv[i] === '--help' || argv[i] === '-h') { - option.help = true - break - } else if (argv[i] === '--interactive' || argv[i] === '-i') { - option.interactive = true - } else if (argv[i] === '--test-type=webdriver') { - option.webdriver = true - } else if (argv[i] === '--require' || argv[i] === '-r') { - option.modules.push(argv[++i]) - continue - } else if (argv[i][0] === '-') { - continue - } else { - option.file = argv[i] - break - } -} - -// Quit when all windows are closed and no other one is listening to this. -app.on('window-all-closed', () => { - if (app.listeners('window-all-closed').length === 1 && !option.interactive) { - app.quit() - } -}) - -// Create default menu. -app.once('ready', () => { - if (Menu.getApplicationMenu()) return - - const template = [ - { - label: 'Edit', - submenu: [ - { - role: 'undo' - }, - { - role: 'redo' - }, - { - type: 'separator' - }, - { - role: 'cut' - }, - { - role: 'copy' - }, - { - role: 'paste' - }, - { - role: 'pasteandmatchstyle' - }, - { - role: 'delete' - }, - { - role: 'selectall' - } - ] - }, - { - label: 'View', - submenu: [ - { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click (item, focusedWindow) { - if (focusedWindow) focusedWindow.reload() - } - }, - { - label: 'Toggle Developer Tools', - accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I', - click (item, focusedWindow) { - if (focusedWindow) focusedWindow.toggleDevTools() - } - }, - { - type: 'separator' - }, - { - label: 'Actual Size', - accelerator: 'CmdOrCtrl+0', - click (item, focusedWindow) { - if (focusedWindow) focusedWindow.webContents.setZoomLevel(0) - } - }, - { - label: 'Zoom In', - accelerator: 'CmdOrCtrl+Plus', - click (item, focusedWindow) { - if (focusedWindow) { - const {webContents} = focusedWindow - webContents.getZoomLevel((zoomLevel) => { - webContents.setZoomLevel(zoomLevel + 0.5) - }) - } - } - }, - { - label: 'Zoom Out', - accelerator: 'CmdOrCtrl+-', - click (item, focusedWindow) { - if (focusedWindow) { - const {webContents} = focusedWindow - webContents.getZoomLevel((zoomLevel) => { - webContents.setZoomLevel(zoomLevel - 0.5) - }) - } - } - }, - { - type: 'separator' - }, - { - role: 'togglefullscreen' - } - ] - }, - { - role: 'window', - submenu: [ - { - role: 'minimize' - }, - { - role: 'close' - } - ] - }, - { - role: 'help', - submenu: [ - { - label: 'Learn More', - click () { - shell.openExternal('http://electron.atom.io') - } - }, - { - label: 'Documentation', - click () { - shell.openExternal( - `https://github.com/electron/electron/tree/v${process.versions.electron}/docs#readme` - ) - } - }, - { - label: 'Community Discussions', - click () { - shell.openExternal('https://discuss.atom.io/c/electron') - } - }, - { - label: 'Search Issues', - click () { - shell.openExternal('https://github.com/electron/electron/issues') - } - } - ] - } - ] - - if (process.platform === 'darwin') { - template.unshift({ - label: 'Electron', - submenu: [ - { - role: 'about' - }, - { - type: 'separator' - }, - { - role: 'services', - submenu: [] - }, - { - type: 'separator' - }, - { - role: 'hide' - }, - { - role: 'hideothers' - }, - { - role: 'unhide' - }, - { - type: 'separator' - }, - { - role: 'quit' - } - ] - }) - template[3].submenu = [ - { - role: 'close' - }, - { - role: 'minimize' - }, - { - role: 'zoom' - }, - { - type: 'separator' - }, - { - role: 'front' - } - ] - } else { - template.unshift({ - label: 'File', - submenu: [ - { - role: 'quit' - } - ] - }) - } - - const menu = Menu.buildFromTemplate(template) - Menu.setApplicationMenu(menu) -}) - -if (option.modules.length > 0) { - Module._preloadModules(option.modules) -} - -function loadApplicationPackage (packagePath) { - // Add a flag indicating app is started from default app. - process.defaultApp = true - - try { - // Override app name and version. - packagePath = path.resolve(packagePath) - const packageJsonPath = path.join(packagePath, 'package.json') - if (fs.existsSync(packageJsonPath)) { - let packageJson - try { - packageJson = require(packageJsonPath) - } catch (e) { - showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${e.message}`) - return - } - - if (packageJson.version) { - app.setVersion(packageJson.version) - } - if (packageJson.productName) { - app.setName(packageJson.productName) - } else if (packageJson.name) { - app.setName(packageJson.name) - } - app.setPath('userData', path.join(app.getPath('appData'), app.getName())) - app.setPath('userCache', path.join(app.getPath('cache'), app.getName())) - app.setAppPath(packagePath) - } - - try { - Module._resolveFilename(packagePath, module, true) - } catch (e) { - showErrorMessage(`Unable to find Electron app at ${packagePath}\n\n${e.message}`) - return - } - - // Run the app. - Module._load(packagePath, module, true) - } catch (e) { - console.error('App threw an error during load') - console.error(e.stack || e) - throw e - } -} - -function showErrorMessage (message) { - app.focus() - dialog.showErrorBox('Error launching app', message) - process.exit(1) -} - -function loadApplicationByUrl (appUrl) { - require('./default_app').load(appUrl) -} - -function startRepl () { - if (process.platform === 'win32') { - console.error('Electron REPL not currently supported on Windows') - process.exit(1) - return - } - - const repl = require('repl') - repl.start('> ').on('exit', () => { - process.exit(0) - }) -} - -// Start the specified app if there is one specified in command line, otherwise -// start the default app. -if (option.file && !option.webdriver) { - const file = option.file - const protocol = url.parse(file).protocol - const extension = path.extname(file) - if (protocol === 'http:' || protocol === 'https:' || protocol === 'file:') { - loadApplicationByUrl(file) - } else if (extension === '.html' || extension === '.htm') { - loadApplicationByUrl('file://' + path.resolve(file)) - } else { - loadApplicationPackage(file) - } -} else if (option.version) { - console.log('v' + process.versions.electron) - process.exit(0) -} else if (option.abi) { - console.log(process.versions.modules) - process.exit(0) -} else if (option.help) { - const helpMessage = `Electron ${process.versions.electron} - Build cross platform desktop apps with JavaScript, HTML, and CSS - - Usage: electron [options] [path] - - A path to an Electron app may be specified. The path must be one of the following: - - - index.js file. - - Folder containing a package.json file. - - Folder containing an index.js file. - - .html/.htm file. - - http://, https://, or file:// URL. - - Options: - -h, --help Print this usage message. - -i, --interactive Open a REPL to the main process. - -r, --require Module to preload (option can be repeated) - -v, --version Print the version. - --abi Print the application binary interface.` - console.log(helpMessage) - process.exit(0) -} else if (option.interactive) { - startRepl() -} else { - const indexPath = path.join(__dirname, '/index.html') - loadApplicationByUrl(`file://${indexPath}`) -} diff --git a/default_app/main.ts b/default_app/main.ts new file mode 100644 index 0000000000000..4618482507c89 --- /dev/null +++ b/default_app/main.ts @@ -0,0 +1,342 @@ +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'; + +const { app, dialog } = electron; + +type DefaultAppOptions = { + file: null | string; + noHelp: boolean; + version: boolean; + webdriver: boolean; + interactive: boolean; + abi: boolean; + modules: string[]; +}; + +// Parse command line options. +const argv = process.argv.slice(1); + +const option: DefaultAppOptions = { + file: null, + noHelp: Boolean(process.env.ELECTRON_NO_HELP), + version: false, + webdriver: false, + interactive: false, + abi: false, + modules: [] +}; + +let nextArgIsRequire = false; + +for (const arg of argv) { + if (nextArgIsRequire) { + option.modules.push(arg); + nextArgIsRequire = false; + continue; + } else if (arg === '--version' || arg === '-v') { + option.version = true; + break; + } else if (arg.match(/^--app=/)) { + option.file = arg.split('=')[1]; + break; + } else if (arg === '--interactive' || arg === '-i' || arg === '-repl') { + option.interactive = true; + } else if (arg === '--test-type=webdriver') { + option.webdriver = true; + } else if (arg === '--require' || arg === '-r') { + nextArgIsRequire = true; + continue; + } else if (arg === '--abi' || arg === '-a') { + option.abi = true; + continue; + } else if (arg === '--no-help') { + option.noHelp = true; + continue; + } else if (arg[0] === '-') { + continue; + } else { + option.file = arg; + break; + } +} + +if (nextArgIsRequire) { + console.error('Invalid Usage: --require [file]\n\n"file" is required'); + process.exit(1); +} + +// Set up preload modules +if (option.modules.length > 0) { + (Module as any)._preloadModules(option.modules); +} + +// See lib/browser/desktop-name.ts +function defaultDesktopName(name: string | undefined): string { + const slug = + name && + name + .normalize('NFKD') + .replace(/\p{M}/gu, '') + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, ''); + return slug ? `${slug}.desktop` : `${path.basename(process.execPath)}.desktop`; +} + +async function loadApplicationPackage(packagePath: string) { + // Add a flag indicating app is started from default app. + Object.defineProperty(process, 'defaultApp', { + configurable: false, + enumerable: true, + value: true + }); + + try { + // 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 { + process.emitWarning = () => {}; + packageJson = ( + await import(url.pathToFileURL(packageJsonPath).toString(), { + with: { type: 'json' } + }) + ).default; + } catch (e) { + showErrorMessage(`Unable to parse ${packageJsonPath}\n\n${(e as Error).message}`); + return; + } finally { + process.emitWarning = emitWarning; + } + + if (packageJson.version) { + app.setVersion(packageJson.version); + } + if (packageJson.productName) { + app.name = packageJson.productName; + } else if (packageJson.name) { + app.name = packageJson.name; + } + + app.setDesktopName(packageJson.desktopName || defaultDesktopName(app.name)); + + // 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 { + 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 as Error).message}`); + return; + } + + // Run the app. + await import(url.pathToFileURL(filePath).toString()); + } catch (e) { + console.error('App threw an error during load'); + console.error((e as Error).stack || e); + throw e; + } +} + +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.js'); + loadURL(appUrl); +} + +async function loadApplicationByFile(appPath: string) { + const { loadFile } = await import('./default_app.js'); + loadFile(appPath); +} + +async function startRepl() { + if (process.platform === 'win32') { + console.error('Electron REPL not currently supported on Windows'); + process.exit(1); + } + + // Prevent quitting. + app.on('window-all-closed', () => {}); + + const GREEN = '32'; + const colorize = (color: string, s: string) => `\x1b[${color}m${s}\x1b[0m`; + const electronVersion = colorize(GREEN, `v${process.versions.electron}`); + const nodeVersion = colorize(GREEN, `v${process.versions.node}`); + + console.info(` + Welcome to the Electron.js REPL \\[._.]/ + + You can access all Electron.js modules here as well as Node.js modules. + Using: Node.js ${nodeVersion} and Electron.js ${electronVersion} + `); + + const { start } = await import('node:repl'); + const repl = start({ + prompt: '> ' + }).on('exit', () => { + process.exit(0); + }); + + function defineBuiltin(context: any, name: string, getter: Function) { + const setReal = (val: any) => { + // Deleting the property before re-assigning it disables the + // getter/setter mechanism. + delete context[name]; + context[name] = val; + }; + + Object.defineProperty(context, name, { + get: () => { + const lib = getter(); + + delete context[name]; + Object.defineProperty(context, name, { + get: () => lib, + set: setReal, + configurable: true, + enumerable: false + }); + + return lib; + }, + set: setReal, + configurable: true, + enumerable: false + }); + } + + defineBuiltin(repl.context, 'electron', () => electron); + for (const api of Object.keys(electron) as (keyof typeof electron)[]) { + defineBuiltin(repl.context, api, () => electron[api]); + } + + // Copied from node/lib/repl.js. For better DX, we don't want to + // show e.g 'contentTracing' at a higher priority than 'const', so + // 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' + ]; + + const electronBuiltins = [...Object.keys(electron), 'original-fs', 'electron']; + + 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); + + const filterFn = (c: string) => c.startsWith(currentSymbol); + const ignores = commonWords.filter(filterFn); + const hits = electronBuiltins.filter(filterFn); + + if (!ignores.length && hits.length) { + callback(null, [hits, currentSymbol]); + } else { + defaultComplete.apply(repl, [line, callback]); + } + }; +} + +// Start the specified app if there is one specified in command line, otherwise +// start the default app. +if (option.file && !option.webdriver) { + const file = option.file; + // 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:') { + await loadApplicationByURL(file); + } else if (extension === '.html' || extension === '.htm') { + await loadApplicationByFile(path.resolve(file)); + } else { + await loadApplicationPackage(file); + } +} else if (option.version) { + console.log('v' + process.versions.electron); + process.exit(0); +} else if (option.abi) { + console.log(process.versions.modules); + process.exit(0); +} else if (option.interactive) { + await startRepl(); +} else { + if (!option.noHelp) { + const welcomeMessage = ` +Electron ${process.versions.electron} - Build cross platform desktop apps with JavaScript, HTML, and CSS +Usage: electron [options] [path] + +A path to an Electron app may be specified. It must be one of the following: + - index.js file. + - Folder containing a package.json file. + - Folder containing an index.js file. + - .html/.htm file. + - http://, https://, or file:// URL. + +Options: + -i, --interactive Open a REPL to the main process. + -r, --require Module to preload (option can be repeated). + -v, --version Print the version. + -a, --abi Print the Node ABI version.`; + + console.log(welcomeMessage); + } + + 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 new file mode 100644 index 0000000000000..ed5b0d009872b --- /dev/null +++ b/default_app/preload.ts @@ -0,0 +1,69 @@ +const { ipcRenderer, contextBridge } = require('electron/renderer'); + +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 = policy.createHTML(await response.text()); + return div; + } catch { + return null; + } +} + +async function loadSVG(element: HTMLSpanElement) { + for (const cssClass of element.classList) { + if (cssClass.startsWith('octicon-')) { + const icon = await getOcticonSvg(cssClass.substr(8)); + if (icon) { + for (const elemClass of element.classList) { + icon.classList.add(elemClass); + } + element.before(icon); + element.remove(); + break; + } + } + } +} + +async function initialize() { + const electronPath = await ipcRenderer.invoke('bootstrap'); + function replaceText(selector: string, text: string, link?: string) { + const element = document.querySelector(selector); + if (element) { + 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}`, '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')) { + loadSVG(element); + } +} + +contextBridge.exposeInMainWorld('electronDefaultApp', { + initialize +}); diff --git a/default_app/styles.css b/default_app/styles.css new file mode 100644 index 0000000000000..ffbf55a577cc2 --- /dev/null +++ b/default_app/styles.css @@ -0,0 +1,155 @@ +body { + color: #86a5b1; + background-color: #2f3241; + font-family: Roboto, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Open Sans", sans-serif; + margin: 0; + display: flex; + flex-direction: column; +} + +.container { + margin: 15px 30px; + background-color: #2f3241; + flex: 1; + display: flex; + flex-direction: column; +} + +.svg-stroke { + stroke: #9feaf9; +} + +.svg-fill { + fill: #9feaf9; +} + +.vertical-middle { + vertical-align: middle !important; +} + +h2, h4, p { + text-align: center; +} + +h4 { + font-weight: normal; + margin: 0; + line-height: 3; +} + +.hero-icons { + transform-origin: 50% 50%; +} + +.hero-icon.loop-3 { + transform: translate(79px, 21px); + opacity: 1; +} + +.hero-icon { + fill: #c2f5ff; + opacity: 1; + transform-origin: 50% 50%; +} + +.hero-app { + fill: #71abb7; + transform-origin: 50% 50%; +} + +a { + color: #86a5b1; + text-decoration: none; + transition: all 0.2s; +} + +a:hover { + color: #c2f5ff; + text-decoration: none; +} + +pre, code, .code { + font-family: "Menlo", "Lucida Console", monospace; + color: #c2f5ff; +} + +pre { + background-color: #26282E; + white-space: pre-wrap; + line-height: 2.5; + overflow: auto; + margin: 0 auto; + display: inline-block; + padding: 6px 15px; + text-align: center; + border-radius: 3px; +} + +pre.with-prompt:before { + content: "$ "; + opacity: 0.7; +} + +code { + padding: 1px 4px; + font-size: 14px; + text-align: center; +} + +.versions { + list-style: none; + margin: 0 auto; + padding: 0; + float: none; + clear: both; + overflow: hidden; +} + +.versions li { + display: block; + float: left; + border-right: 1px solid rgba(194, 245, 255, 0.4); + padding: 0 20px; + font-size: 13px; + opacity: 0.8; +} + +.versions li:last-child { + border: none; +} + +nav { + margin: 40px 0 0 0; +} + +.linkcol { + width: 19%; + display: inline-block; + text-align: center; +} + +.hero-octicon { + display: block; + width: 80px; + height: 80px; + margin: 0; + padding: 0; + font-size: 42px !important; + color: #9feaf9; + text-align: center; + background-color: rgba(194, 245, 255, 0.1); + border-radius: 50%; +} + +.hero-octicon svg { + display: block; + padding-top: 20px; + height: 42px; + width: 42px; + margin: 0 auto; +} + +.octicon-gist:before { padding-left: 10px; } +.octicon-gear:before { padding-left: 5px; } +.octicon-star:before { padding-left: 6px; } +.octicon-gift:before { padding-left: 2px; } \ No newline at end of file diff --git a/docs-translations/es/README.md b/docs-translations/es/README.md deleted file mode 100644 index 1d8877bdacee6..0000000000000 --- a/docs-translations/es/README.md +++ /dev/null @@ -1,71 +0,0 @@ -## Guías - -* [Plataformas Soportadas](tutorial/supported-platforms.md) -* [Distribución de la Aplicación](tutorial/application-distribution.md) -* [Empaquetamiento de la Aplicación](tutorial/application-packaging.md) -* [Utilizando Módulos Node Nativos](tutorial/using-native-node-modules.md) -* [Depurando el Proceso Principal](tutorial/debugging-main-process.md) -* [Utilizando Selenium y WebDriver](tutorial/using-selenium-and-webdriver.md) -* [Extensión DevTools](tutorial/devtools-extension.md) -* [Utilizando el plugin Pepper Flash](tutorial/using-pepper-flash-plugin.md) - -## Tutoriales - -* [Introducción](tutorial/quick-start.md) -* [Integración con el entorno de escritorio](tutorial/desktop-environment-integration.md) -* [Detección del evento en línea/fuera de línea](tutorial/online-offline-events.md) - -## Referencias a la API - -* [Sinopsis](api/synopsis.md) -* [Proceso](api/process.md) -* [Parámetros CLI soportados (Chrome)](api/chrome-command-line-switches.md) - -### Elementos DOM personalizados: - -* [Objeto `File`](../../docs/api/file-object.md) -* [Etiqueta ``](../../docs/api/web-view-tag.md) -* [Función `window.open`](../../docs/api/window-open.md) - -### Módulos del Proceso Principal: - -* [app](../../docs/api/app.md) -* [auto-updater](../../docs/api/auto-updater.md) -* [browser-window](../../docs/api/browser-window.md) -* [content-tracing](../../docs/api/content-tracing.md) -* [dialog](../../docs/api/dialog.md) -* [global-shortcut](../../docs/api/global-shortcut.md) -* [ipc (proceso principal)](../../docs/api/ipc-main.md) -* [menu](../../docs/api/menu.md) -* [menu-item](../../docs/api/menu-item.md) -* [power-monitor](../../docs/api/power-monitor.md) -* [power-save-blocker](../../docs/api/power-save-blocker.md) -* [protocol](../../docs/api/protocol.md) -* [session](../../docs/api/session.md) -* [web-contents](../../docs/api/web-contents.md) -* [tray](../../docs/api/tray.md) - -### Módulos del proceso de renderizado (Página Web): - -* [ipc (renderizador)](../../docs/api/ipc-renderer.md) -* [remote](../../docs/api/remote.md) -* [web-frame](../../docs/api/web-frame.md) - -### Módulos de Ambos Procesos: - -* [clipboard](../../docs/api/clipboard.md) -* [crash-reporter](../../docs/api/crash-reporter.md) -* [native-image](../../docs/api/native-image.md) -* [screen](../../docs/api/screen.md) -* [shell](../../docs/api/shell.md) - -## Desarrollo - -* [Guía de Estilo](development/coding-style.md) -* [Estructura de los directorios del Código Fuente](development/source-code-directory-structure.md) -* [Diferencias Técnicas con NW.js (anteriormente conocido como node-webkit)](development/atom-shell-vs-node-webkit.md) -* [Repaso del Sistema de Compilación](development/build-system-overview.md) -* [Instrucciones de Compilación (macOS)](development/build-instructions-osx.md) -* [Instrucciones de Compilación (Windows)](development/build-instructions-windows.md) -* [Instrucciones de Compilación (Linux)](development/build-instructions-linux.md) -* [Configurando un Servidor de Símbolos en el depurador](development/setting-up-symbol-server.md) diff --git a/docs-translations/es/api/chrome-command-line-switches.md b/docs-translations/es/api/chrome-command-line-switches.md deleted file mode 100644 index 56973ec06ad3f..0000000000000 --- a/docs-translations/es/api/chrome-command-line-switches.md +++ /dev/null @@ -1,119 +0,0 @@ -# Parámetros CLI soportados (Chrome) - -Esta página lista las líneas de comandos usadas por el navegador Chrome que también son -soportadas por Electron. Puedes usar [app.commandLine.appendSwitch][append-switch] para -anexarlas en el script principal de tu aplicación antes de que el evento [ready][ready] del -módulo [app][app] sea emitido: - -```javascript -var app = require('app'); -app.commandLine.appendSwitch('remote-debugging-port', '8315'); -app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1'); - -app.on('ready', function() { - // Your code here -}); -``` - -## --client-certificate=`path` - -Establece el `path` del archivo de certificado del cliente. - -## --ignore-connections-limit=`domains` - -Ignora el límite de conexiones para la lista de `domains` separados por `,`. - -## --disable-http-cache - -Deshabilita la caché del disco para las peticiones HTTP. - -## --remote-debugging-port=`port` - -Habilita la depuración remota a través de HTTP en el puerto especificado. - -## --proxy-server=`address:port` - -Usa un servidor proxy especificado, que sobreescribe la configuración del sistema. -Este cambio solo afecta peticiones HTTP y HTTPS. - -## --proxy-pac-url=`url` - -Utiliza el script PAC en la `url` especificada. - -## --no-proxy-server - -No usa un servidor proxy y siempre establece conexiones directas. Anula cualquier -otra bandera de servidor proxy bandera que se pase. - -## --host-rules=`rules` - -Una lista separada por comas de `rules` (reglas) que controlan cómo se asignan los -nombres de host. - -Por ejemplo: - -* `MAP * 127.0.0.1` Obliga a todos los nombres de host a ser asignados a 127.0.0.1 -* `MAP *.google.com proxy` Obliga todos los subdominios google.com a resolverse con - "proxy". -* `MAP test.com [::1]:77` Obliga a resolver "test.com" con un bucle invertido de IPv6. - También obligará a que el puerto de la dirección respuesta sea 77. -* `MAP * baz, EXCLUDE www.google.com` Reasigna todo a "baz", excepto a "www.google.com". - -Estas asignaciones especifican el host final en una petición de red (Anfitrión de la conexión TCP -y de resolución de conexión directa, y el `CONNECT` en una conexión proxy HTTP, y el host final de -la conexión proxy `SOCKS`). - -## --host-resolver-rules=`rules` - -Como `--host-rules` pero estas `rules` solo se aplican al solucionador. - -[app]: app.md -[append-switch]: app.md#appcommandlineappendswitchswitch-value -[ready]: app.md#event-ready - -## --ignore-certificate-errors - -Ignora errores de certificado relacionados. - -## --ppapi-flash-path=`path` - -Asigna la ruta `path` del pepper flash plugin. - -## --ppapi-flash-version=`version` - -Asigna la versión `version` del pepper flash plugin. - -## --log-net-log=`path` - -Permite guardar y escribir eventos de registros de red en `path`. - -## --ssl-version-fallback-min=`version` - -Establece la versión mínima de SSL/TLS ("tls1", "tls1.1" o "tls1.2") que -el repliegue de TLC aceptará. - -## --enable-logging - -Imprime el registro de Chromium en consola. - -Este cambio no puede ser usado en `app.commandLine.appendSwitch` ya que se analiza antes de que la -aplicación del usuario esté cargada. - -## --v=`log_level` - -Da el máximo nivel activo de V-logging por defecto; 0 es el predeterminado. Valores positivos -son normalmente usados para los niveles de V-logging. - -Este modificador sólo funciona cuando también se pasa `--enable-logging`. - -## --vmodule=`pattern` - -Da los niveles máximos de V-logging por módulo para sobreescribir el valor dado por -`--v`. Ej. `my_module=2,foo*=3` cambiaría el nivel de registro para todo el código, -los archivos de origen `my_module.*` y `foo*.*`. - -Cualquier patrón que contiene un slash o un slash invertido será probado contra toda la ruta -y no sólo con el módulo. Ej. `*/foo/bar/*=2` cambiaría el nivel de registro para todo el código -en los archivos origen bajo un directorio `foo/bar`. - -Este modificador sólo funciona cuando también se pasa `--enable-logging`. diff --git a/docs-translations/es/api/process.md b/docs-translations/es/api/process.md deleted file mode 100644 index 1a905125de2f8..0000000000000 --- a/docs-translations/es/api/process.md +++ /dev/null @@ -1,47 +0,0 @@ -# process - -El objeto `process` en Electron tiene las siguientes diferencias con respecto -al node convencional: - -* `process.type` String - El tipo del proceso puede ser `browser` (ej. proceso - principal) o `renderer`. -* `process.versions.electron` String - Versión de Electron. -* `process.versions.chrome` String - Versión de Chromium. -* `process.resourcesPath` String - Ruta al código fuente JavaScript. - -## Events - -### Event: 'loaded' - -Se emite cuando Electron ha cargado su script de inicialización interna y -está comenzando a cargar la página web o el script principal. - -Puede ser usado por el script precargado para añadir de nuevo los símbolos globales -de Node eliminados, al alcance global cuando la integración de Node está apagada: - -```js -// preload.js -var _setImmediate = setImmediate; -var _clearImmediate = clearImmediate; -process.once('loaded', function() { - global.setImmediate = _setImmediate; - global.clearImmediate = _clearImmediate; -}); -``` - -## Methods - -El objeto `process` tiene los siguientes métodos: - -### `process.hang` - -Interrumpe el hilo principal del proceso actual. - - -### process.setFdLimit(maxDescriptors) _macOS_ _Linux_ - -* `maxDescriptors` Integer - -Establece el límite dinámico del descriptor del archivo en `maxDescriptors` -o en el límite estricto del Sistema Operativo, el que sea menor para el -proceso actual. diff --git a/docs-translations/es/api/synopsis.md b/docs-translations/es/api/synopsis.md deleted file mode 100644 index 54c264a1aa748..0000000000000 --- a/docs-translations/es/api/synopsis.md +++ /dev/null @@ -1,47 +0,0 @@ -# Sinopsis - -Todos los [Módulos integrados de Node.js](http://nodejs.org/api/) se encuentran -disponibles en Electron y módulos de terceros son támbien totalmente compatibles -(incluyendo los [módulos nativos](../tutorial/using-native-node-modules.md)). - -Electron también provee algunos módulos integrados adicionales para desarrollar -aplicaciones nativas de escritorio. Algunos módulos sólo se encuentran disponibles -en el proceso principal, algunos sólo en el proceso renderer (página web), y -algunos pueden ser usados en ambos procesos. - -La regla básica es: Si un módulo es -[GUI](https://es.wikipedia.org/wiki/Interfaz_gráfica_de_usuario) o de bajo nivel, -entonces solo estará disponible en el proceso principal. Necesitas familiarizarte -con el concepto de [scripts para proceso principal vs scripts para proceso renderer] -(../tutorial/quick-start.md#the-main-process) para ser capaz de usar esos módulos. - -El script del proceso principal es como un script normal de Node.js: - -```javascript -var app = require('app'); -var BrowserWindow = require('browser-window'); - -var window = null; - -app.on('ready', function() { - window = new BrowserWindow({width: 800, height: 600}); - window.loadURL('https://github.com'); -}); -``` - -El proceso renderer no es diferente de una página web normal, excepto por la -capacidad extra de utilizar módulos de node: - -```html - - - - - - -``` - -Para ejecutar tu aplicación, lee [Ejecutar la aplicación](../tutorial/quick-start.md#run-your-app). diff --git a/docs-translations/es/development/atom-shell-vs-node-webkit.md b/docs-translations/es/development/atom-shell-vs-node-webkit.md deleted file mode 100644 index 8d01706732943..0000000000000 --- a/docs-translations/es/development/atom-shell-vs-node-webkit.md +++ /dev/null @@ -1,34 +0,0 @@ -#Diferencias Técnicas entre Electron y NW.js (anteriormente conocido como node-webkit) - -**Nota:Electron se llamaba antes Atom Shell.** - -Como NW.js, Electron proporciona una plataforma para escribir aplicaciones de escritorio con JavaScript y HTML y tiene la integración de nodo para permitir el acceso al sistema de bajo nivel de las páginas web. - -Pero también hay diferencias fundamentales entre los dos proyectos que hacen a Electron un producto totalmente independiente de NW.js: - -**1. Ingreso a la aplicación** - -En NW.js el principal punto de ingreso de una aplicación es una página web. Usted especifica una página principal de URL en el `package.json` y se abre en una ventana del navegador como ventana principal de la aplicación. - -En Electron, el punto de ingreso es un script de JavaScript. En lugar de proporcionar una dirección URL directamente, usted crea manualmente una ventana del navegador y carga un archivo HTML utilizando la API. También es necesario escuchar a los eventos de la ventana para decidir cuándo salir de la aplicación. - -Electron funciona más como el tiempo de ejecución(Runtime) de Node.js. Las Api's de Electron son de bajo nivel asi que puede usarlo para las pruebas del navegador en lugar de usar [PhantomJS.](http://phantomjs.org/) - -**2.Construir un sistema** - -Con el fin de evitar la complejidad de la construcción de todo Chromium, Electron utiliza `libchromiumcontent` para acceder a al contenido Chromium's API. `libchromiumcontent` es solo una liberia compartida que incluye el módulo de contenido de Chromium y todas sus dependencias. Los usuarios no necesitan una máquina potente para construir con Electron. - -**3.Integración de Node** - -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 code for how that was done. - -En NW.js, la integración de Node en las páginas web requiere parchear Chromium para que funcione, mientras que en Electron elegimos una manera diferente para integrar el cilco libuv con cada ciclo de mensaje de las plataformas para evitar el hacking en Chromium. Ver el código [`node_bindings`][node-bindings] de cómo se hizo. - - -**4. Multi-contexto** - -Si usted es un usuario experimentado NW.js, usted debe estar familiarizado con el concepto de contexto Node y el contexto web. Estos conceptos fueron inventados debido a la forma cómo se implementó NW.js. - -Mediante el uso de la característica [multi-contexto](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/) de Node, Electron no introduce un nuevo contexto JavaScript en páginas web.Resultados de búsqueda - -[node-bindings]: https://github.com/electron/electron/tree/master/atom/common diff --git a/docs-translations/es/development/build-instructions-linux.md b/docs-translations/es/development/build-instructions-linux.md deleted file mode 100644 index 58beef4ecf04b..0000000000000 --- a/docs-translations/es/development/build-instructions-linux.md +++ /dev/null @@ -1,96 +0,0 @@ -#Instrucciones de Compilación (Linux) - -Siga las siguientes pautas para la construcción de Electron en Linux. -#Requisitos previos - - * Python 2.7.x. Algunas distribuciones como CentOS siguen utilizando Python 2.6.x por lo que puede que tenga que comprobar su versión de Python con `Python -V`. - * Node.js v0.12.x. Hay varias formas de instalar Node. Puede descargar el código fuente de Node.js y compilar desde las fuentes. Si lo hace, permite la instalación de Node en el directorio personal como usuario estándar. O intentar de repositorios como NodeSource. - * Clang 3.4 o mayor. - * Cabeceras de desarrollo de GTK + y libnotify. - -En Ubuntu, instalar las siguientes bibliotecas: - -`$ sudo apt-get install build-essential clang libdbus-1-dev libgtk2.0-dev \ - libnotify-dev libgnome-keyring-dev libgconf2-dev \ - libasound2-dev libcap-dev libcups2-dev libxtst-dev \ - libxss1 libnss3-dev gcc-multilib g++-multilib` - -En Fedora, instale las siguientes bibliotecas: - -`$ sudo yum install clang dbus-devel gtk2-devel libnotify-devel libgnome-keyring-devel \ - xorg-x11-server-utils libcap-devel cups-devel libXtst-devel \ - alsa-lib-devel libXrandr-devel GConf2-devel nss-devel` - -Otras distribuciones pueden ofrecer paquetes similares para la instalación, a través de gestores de paquetes como el pacman. O puede compilarlo a partir del código fuente. - -#Si utiliza máquinas virtuales para la construcción - -Si usted planea construir Electron en una máquina virtual, necesitará un dispositivo de al menos 25 gigabytes de tamaño. - -#Obteniendo el codigo - -`$ git clone https://github.com/electron/electron.git` - -#Bootstrapping (Arranque) - -The bootstrap script will download all necessary build dependencies and create the build project files. You must have Python 2.7.x for the script to succeed. Downloading certain files can take a long time. Notice that we are using ninja to build Electron so there is no Makefile generated. - -El script de bootstrap descargará todas las dependencias necesarias para construcción y creara los archivos del proyecto de construcción. Debe tener Python 2.7.x para que la secuencia de comandos tenga éxito. La descarga de determinados archivos puede llevar mucho tiempo. Nótese que estamos usando`ninja` para construir Electron por lo que no hay `Makefile` generado. - - $ cd electron - $ ./script/bootstrap.py -v - -#compilación cruzada - -Si usted quiere construir para un `arm` objetivo también debe instalar las siguientes dependencias: - -`$ sudo apt-get install libc6-dev-armhf-cross linux-libc-dev-armhf-cross \ g++-arm-linux-gnueabihf` - -And to cross compile for arm or ia32 targets, you should pass the --target_arch parameter to the bootstrap.py script: -cruzar y compilar para `arm` o `ia32` objetivos, debe pasar el parámetro `--target_arch` al script `bootstrap.py`: -`$ ./script/bootstrap.py -v --target_arch=arm` - -#Construcción - -Si a usted le gustaría construir dos objetivos de `Release` y `Debug`: - - `$ ./script/build.py` - - -Este script causará que el ejecutable de Electron se muy grande para ser colocado en el directorio `out / R`. El tamaño del archivo es de más de 1,3 gigabytes. Esto sucede porque el binario de destino lanzamiento contiene los símbolos de depuración. Para reducir el tamaño de archivo, ejecute el script `create-dist.py`: - -`$ ./script/create-dist.py` - -This will put a working distribution with much smaller file sizes in the dist directory. After running the create-dist.py script, you may want to remove the 1.3+ gigabyte binary which is still in out/R. - -Esto pondrá una distribución a trabajar con tamaños de archivo mucho más pequeños en el directorio `dist`. Después de ejecutar el script create-dist.py, es posible que desee quitar el binario 1.3+ gigabyte que todavía está en `out/R`. - -También se puede construir sólo el objetivo `Debug`: -`$ ./script/build.py -c D` - -Después de la construcción está hecho, usted puede encontrar el `Electron` de depuración binario bajo `out / D`. - -#Limpieza - -Para limpiar los archivos de creación: - -`$ ./script/clean.py` - -#Solución de problemas -Asegúrese de que ha instalado todas las dependencias de construcción. - -#Error al cargar bibliotecas compartidas: libtinfo.so.5 - -Prebulit clang will try to link to libtinfo.so.5. Depending on the host architecture, symlink to appropriate libncurses: -preconstruir `clang` intentará enlazar a `libtinfo.so.5`. Dependiendo de la arquitectura anfitrión, enlace simbólico apropiado a `libncurses` : - -`$ sudo ln -s /usr/lib/libncurses.so.5 /usr/lib/libtinfo.so.5` - -#Pruebas -Pon a prueba tus cambios que ajustan al estilo de codificación proyecto mediante: - -`$ ./script/cpplint.py` - -prueba de funcionalidad utilizando: - -`$ ./script/test.py` diff --git a/docs-translations/es/development/build-instructions-osx.md b/docs-translations/es/development/build-instructions-osx.md deleted file mode 100644 index 05c3a44f3d574..0000000000000 --- a/docs-translations/es/development/build-instructions-osx.md +++ /dev/null @@ -1,48 +0,0 @@ -#Instrucciones de Compilación (Mac) -Siga las siguientes pautas para la construcción de Electron en macOS. - -#Requisitos previos - - `macOS >= 10.8` - `Xcode >= 5.1` - `node.js (external)` - - -Si está utilizando Python descargado de Homebrew, también es necesario instalar los siguientes módulos de python: - `pyobjc` - -#Obtener el Código - -`$ git clone https://github.com/electron/electron.git` - -#Bootstrapping (arranque) - -The bootstrap script will download all necessary build dependencies and create the build project files. Notice that we're using ninja to build Electron so there is no Xcode project generated. - -El script de bootstrap descargará todas las dependencias de construcción necesarias y creara los archivos del proyecto de compilación. notemos que estamos usando `ninja` para construir Electron por lo que no hay un proyecto de Xcode generado. - -`$ cd electron` -`$ ./script/bootstrap.py -v` - -#Construcción -Construir ambos objetivos de `Release` y `Debug`: - -`$ ./script/build.py` - -También sólo se puede construir el objetivo de `Debug`: -`$ ./script/build.py -c D` - -Después de la construcción está hecho, usted puede encontrar `Electron.app` bajo `out / D.` - -#Soporte de 32bit - -Electron sólo puede construirse para un objetivo de 64 bits en macOS y no hay un plan para apoyar a 32 bit macOS en el futuro. - -#Pruebas - -Pon a prueba tus cambios ajustandose al estilo de codificación del proyecto mediante: -`$ ./script/cpplint.py` - -Prueba la funcionalidad usando: - -`$ ./script/test.py` diff --git a/docs-translations/es/development/build-system-overview.md b/docs-translations/es/development/build-system-overview.md deleted file mode 100644 index 1e6a42da84bf0..0000000000000 --- a/docs-translations/es/development/build-system-overview.md +++ /dev/null @@ -1,35 +0,0 @@ -#Repaso del Sistema de construcción -Electron utiliza `gyp` para la generación de proyectos y` ninja` para la contrucción. Las Configuraciones del proyecto se pueden encontrar en los archivos `.gypi` y `.gyp `. - -#Archivos Gyp -los siguientes archivos `gyp` contienen las principales reglas para la contrucción en electron: - - * `atom.gyp` define en si como se compila en Electron. - * `common.gypi` ajusta las configuraciones de generación de Node para construir junto con Chromium. - * `vendor/brightray/brightray.gyp` define cómo se construye `brightray` e incluye las configuraciones predeterminadas para linkear con Chromium. - * `vendor/brightray/brightray.gypi` incluye configuraciones de generación generales sobre la construcción. - -#Construir un componente -Desde Chromium es un proyecto bastante largo, la etapa de enlace final puede tomar pocos minutos, lo que hace que sea difícil para el desarrollo. Con el fin de resolver esto, Chromium introdujo el "componente de construcción", que se basa en construir cada componente como una libreria compartida por separado, haciendo que se enlace muy rápido, pero sacrificando el tamaño del archivo y el rendimiento. - -En Electron tomamos un enfoque muy similar: para versiones de `Debug` (depuración), el binario será linkeado a una versión de la libreria compartida de los componentes de Chromium para lograr un tiempo de enlace rápido; para versiones de `Release` (lanzamiento), el binario será linkeado a las versiones de las librerias estáticas, por lo que puede tener es posible tener un mejor tamaño binario y rendimiento. - -#Bootstrapping minimo (minimo arranque) -Todos los binarios pre-compilados de Chromium (`libchromiumcontent`) son descargados al ejecutar el script de arranque. Por defecto ambas librerias estáticas y librerias compartidas se descargarán y el tamaño final debe estar entre 800 MB y 2 GB dependiendo de la plataforma. - -Por defecto, `libchromiumcontent` se descarga de Amazon Web Services. Si se establece la variable de entorno `LIBCHROMIUMCONTENT_MIRROR`, el bootstrap script se descargará de ella. `libchromiumcontent-qiniu-mirror` es un espejo para el` libchromiumcontent`. Si tiene problemas para acceder a AWS, puede cambiar la dirección de descarga a la misma a través de `exportación LIBCHROMIUMCONTENT_MIRROR = http: // 7xk3d2.dl1.z0.glb.clouddn.com /` - -Si sólo desea construir en Electron rápidamente para pruebas o desarrollo, puede descargar sólo las versiones de librerias compartidas pasando el parámetro `--dev`: - -`$ ./script/bootstrap.py --dev` -`$ ./script/build.py -c D` - -#generación de proyecto de dos frases -Los enlaces de Electron con diferentes conjuntos de librerias en versiones `Release` y `Debug`. `gyp`, sin embargo, no es compatible con la configuración de los diferentes ajustes de enlace para diferentes configuraciones. - -Para evitar que Electron utilice una variable de `gyp` `libchromiumcontent_component` para controlar qué configuraciones de enlace usar y sólo generar un objetivo cuando se ejecute `gyp`. - -#Nombres de destino -A diferencia de la mayoría de los proyectos que utilizan `Release` y `Debug` como nombres de destino, Electron utiliza `R` y `D` en su lugar. Esto se debe a `gyp` bloquea aleatoriamente si sólo hay una configuración de `Release` o `Debug` definidas, y Electron sólo tiene que generar un objetivo a la vez como se ha indicado anteriormente. - -Esto sólo afecta a los desarrolladores, si usted está construyendo Electron para rebranding no se ven afectados. diff --git a/docs-translations/es/development/coding-style.md b/docs-translations/es/development/coding-style.md deleted file mode 100644 index e2f364d8b9c24..0000000000000 --- a/docs-translations/es/development/coding-style.md +++ /dev/null @@ -1,37 +0,0 @@ -# Guía de estilo de código - -Esta es la guía de estilo de código para Electron. - -## C++ y Python - -Para C++ y Python, nosotros seguimos la [guía de estilo](http://www.chromium.org/developers/coding-style) de Chromium. -Además hay un script `script/cpplint.py` para verificar si todos los archivos -siguen el estilo. - -La versión de Python que estamos usando ahora es Python 2.7. - -El código C++ usa muchas abstracciones y tipos de Chromium, por eso -se recomienda familiarizarse con ellos. Un buen lugar para iniciar es -el documento de Chromium sobre [Abstracciones importantes y estructras de datos](https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures). El documento menciona algunos tipos especiales, tipos por alcance (que -automaticamente liberan su memoria cuando salen de su alcance), mecanismos de -registro de eventos, etcétera. - -## CoffeeScript - -Para CoffeeScript, nosotros seguimos la [guía de estilo](https://github.com/styleguide/javascript) de Github y también las -siguientes reglas: - -* Los archivos **NO** deberían terminar con una nueva línea, por que se busca - seguir los estilos que usa Google. -* Los nombres de los archivos debén estar concatenados con `-` en vez de `_`, - por ejemplo `nombre-de-archivo.coffee` en vez de `nombre_de_archivo.coffee`, - esto es por que en [github/atom](https://github.com/github/atom) - los nombres de los módulos usualmente estan en la forma `nombre-de-modulo`. - Esta regla aplica únicamente a los archivos `.coffee`. - -## Nombres de las API - -Al crear una nueva API, nosotros deberíamos preferir usar metodos `get` y `set` -en vez de usar el estilo de jQuery que utiliza una sola función. Por ejemplo, -se prefiere `.getText()` y `.setText()` por sobre `.text([text])`. Hay una -[discusión](https://github.com/electron/electron/issues/46) sobre esto. diff --git a/docs-translations/es/development/source-code-directory-structure.md b/docs-translations/es/development/source-code-directory-structure.md deleted file mode 100644 index cc738d2412773..0000000000000 --- a/docs-translations/es/development/source-code-directory-structure.md +++ /dev/null @@ -1,62 +0,0 @@ -# Estructura de los directorios del código fuente - -El código fuente de electron es separado en pocas partes, en su mayoría -siguiendo las especificaciones para separar archivos que usa Chromium. - -Quizá necesites familiarizarte con la [arquitectura multiprocesos](http://dev.chromium.org/developers/design-documents/multi-process-architecture) de Chromium para comprender mejor el código fuente. - -## Estructura del código fuente - -``` -Electron -├──atom - Código fuente de Electron. -| ├── app - Código de arranque. -| ├── browser - La interfaz incluyendo la ventana principal, UI, -| | y todas las cosas del proceso principal. Este le habla al renderizador -| | para manejar las páginas web. -| | ├── lib - Código Javascript para inicializar el proceso principal. -| | ├── ui - Implementaciones de UI para distintas plataformas. -| | | ├── cocoa - Código fuente específico para Cocoa. -| | | ├── gtk - Código fuente específico para GTK+. -| | | └── win - Código fuente específico para Windows GUI. -| | ├── default_app - La página por defecto para mostrar cuando Electron -| | | es iniciado sin proveer una app. -| | ├── api - La implementación de las APIs para el proceso principal. -| | | └── lib - Código Javascript parte de la implementación de la API. -| | ├── net - Código relacionado a la red. -| | ├── mac - Código fuente de Objective-C específico para Mac. -| | └── resources - Iconos, archivos específicos de plataforma, etc. -| ├── renderer - Código que se ejecuta en el proceso de renderizado. -| | ├── lib - Código Javascript del proceso de inicio del renderizador. -| | └── api - La implementación de las APIs para el proceso de renderizado. -| | └── lib - Código Javascript parte de la implementación de la API. -| └── common - Código que se utiliza en ambos procesos, el principal y el de -| renderizado. Incluye algunas funciones de utilidad y código para integrar -| el ciclo de mensajes de Node en el ciclo de mensajes de Chromium. -| ├── lib - Código Javascript común para la inicialización. -| └── api - La implementación de APIs comunes, y los fundamentos de -| los módulos integrados de Electron. -| └── lib - Código Javascript parte de la implementación de la API. -├── chromium_src - Código fuente copiado de Chromium. -├── docs - Documentación. -├── spec - Pruebas automaticas. -├── atom.gyp - Reglas de compilado de Electron. -└── common.gypi - Configuración específica para compilar y reglas - de empaquetado para otros componentes como `node` y `breakpad`. -``` - -## Estructura de otros directorios - -* **script** - Scripts usados para propositos de desarrollo - como compilar, empaquetar, realizar pruebas, etc. -* **tools** - Scripts de ayuda usados por los archivos gyp, contrario a la - carpeta `scripts`, estos scripts nunca deberían ser llamados por los usuarios. -* **vendor** - Código fuente de dependencias externas, no usamos `third_party` - como nombre por que se podría confundir con el mismo directorio - en las carpetas del código fuente de Chromium. -* **node_modules** - Módulos de node usados para la compilación. -* **out** - Directorio temporal de salida usado por `ninja`. -* **dist** - Directorio temporal creado por `script/create-dist.py` cuando - se esta creando una distribución. -* **external_binaries** - Binarios descargados de frameworks externos que no - soportan la compilación con `gyp`. diff --git a/docs-translations/es/styleguide.md b/docs-translations/es/styleguide.md deleted file mode 100644 index e7138aeb8464f..0000000000000 --- a/docs-translations/es/styleguide.md +++ /dev/null @@ -1,100 +0,0 @@ -# Gúia de estilo de Electron - -Encuentra el apartado correcto para cada tarea: [leer la documentación de Electron](#reading-electron-documentation) -o [escribir documentación para Electron](#writing-electron-documentation). - -## Escribir Documentación para Electron - -Estas son las maneras en las que construimos la documentación de Electron. - -- Máximo un título `h1` por página. -- Utilizar `bash` en lugar de `cmd` en los bloques de código (por el resaltado - de sintaxis). -- Los títulos `h1` en el documento deben corresponder al nombre del objeto - (ej. `browser-window` → `BrowserWindow`). - - Archivos separados por guiones, mas sin embargo, es correcto. -- No subtítulos seguidos por otros subtítulos, añadir por lo menos un enunciado - de descripción. -- Métodos de cabecera son delimitados con apóstrofes: `código`. -- Cabeceras de Eventos son delimitados con 'comillas' simples. -- No generar listas de mas de dos niveles (debido al renderizador de Markdown - desafortunadamente). -- Agregar títulos de sección: Eventos, Métodos de Clases y Métodos de Instancia. -- Utilizar 'deberá' en lugar de 'debería' al describir resultados. -- Eventos y Métodos son cabeceras `h3`. -- Argumentos opcionales escritos como `function (required[, optional])`. -- Argumentos opcionales son denotados cuando se llaman en listas. -- Delimitador de línea de 80-columnas. -- Métodos específicos de Plataformas son denotados en itálicas seguidas por la cabecera del método. - - ```### `method(foo, bar)` _macOS_``` -- Preferir 'en el ___ proceso' en lugar de 'sobre el' - -### Traducciones de la Documentación - -Traducciones de documentos de Electron se encuentran dentro del folder -`docs-translations`. - -Para agregar otro set (o un set parcial): - -- Crear un subdirectorio nombrado igual a la abreviación del lenguaje. -- Dentro de ese subdirectorio, duplicar el directorio de `docs`, manteniendo los - mismos nombres de directorios y archivos. -- Traducir los archivos. -- Actualizar el `README.md` dentro del subdirectorio del lenguaje apuntando a - los archivos que has traducido. -- Agregar un enlace al folder de tu traducción en la sección principal Electron -[README](https://github.com/electron/electron#documentation-translations). - -## Leyendo la Documentación de Electron - -Estos son algunos consejos para entender la sintaxis de la documentación de -Electron. - -### Métodos - -Un ejemplo de la documentación del [método](https://developer.mozilla.org/en-US/docs/Glossary/Method): - ---- - -`methodName(required[, optional]))` - -* `require` String, **required** -* `optional` Integer - ---- - -El nombre del método es seguido por los argumentos que recibe. Argumentos -opcionales son denotados por corchetes rodeados por el argumento opcional y la -coma requerida si el argumento opcional fuera seguido por otro argumento. - -Debajo del método se encuentra más información detallada de cada uno de los -argumentos. El tipo de argumento es denotado por los tipos comúnes: -[`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) -o un tipo personalizado como el [`webContent`](api/web-content.md) de Electron. - -### Eventos - -Un ejemplo de documentación del [evento](https://developer.mozilla.org/en-US/docs/Web/API/Event): - ---- - -Event: 'wake-up' - -Returns: - -* `time` String - ---- - -El evento es una cadena que es utilizada luego de un método observador `.on`. Si -regresa un valor, él y su tipo son denotados abajo. Si se estaba a la escucha y -respondió a este evento se debería ver así: - -```javascript -Alarm.on('wake-up', function(time) { - console.log(time) -}) -``` diff --git a/docs-translations/es/tutorial/application-distribution.md b/docs-translations/es/tutorial/application-distribution.md deleted file mode 100644 index 9061a6feb3e94..0000000000000 --- a/docs-translations/es/tutorial/application-distribution.md +++ /dev/null @@ -1,120 +0,0 @@ -# Distribución de la Aplicación - -Para distribuir tu aplicación con Electron, el directorio que contiene la -aplicación deberá llamarse `app`, y ser colocado debajo del directorio de -recursos de Electron (en macOS es `Electron.app/Contents/Resources/`, en Linux y -Windows es `resources/`), de esta forma: - -En macOS: - -```text -electron/Electron.app/Contents/Resources/app/ -├── package.json -├── main.js -└── index.html -``` - -En Windows y Linux: - -```text -electron/resources/app -├── package.json -├── main.js -└── index.html -``` - -Luego ejecutar `Electron.app` (o `electron` en Linux, `electron.exe` en Windows), -y Electron será iniciado como tu aplicación. El directorio `electron` será -entonces tu distribución que recibirán los usuarios finales. - -## Empaquetando tu aplicación en un archivo - -Además de distribuir tu aplicación al copiar todos los archivos de código fuente, -también puedes empaquetar tu aplicación como un archivo [asar](https://github.com/atom/asar) -y de esta forma evitar exponer del código fuente de tu aplicación a los usuarios. - -Para utilizar un archivo `asar` en reemplazo del directorio `app`, debes de -renombrar el archivo a `app.asar`, y colocarlo por debajo el directorio de recursos -de Electron (ver en seguida), Electron intentará leer el archivo y arrancar desde el. - -En macOS: - -```text -electron/Electron.app/Contents/Resources/ -└── app.asar -``` - -En Windows y Linux: - -```text -electron/resources/ -└── app.asar -``` - -Más detalles en [Empaquetado de Aplicaciones](application-packaging.md). - -## Redefinición con Binarios Descargados - -Luego de empaquetar tu aplicación en Electron, querrás redefinir Electron antes -de distribuirlo a los usuarios. - -### Windows - -Puedes renombrar `electron.exe` a cualquier nombre que desees, y editar su ícono -y otra información con herramientas como [rcedit](https://github.com/atom/rcedit). - -### macOS - -Puedes renombrar `Electron.app` a cualquier nombre que desees, y tendrás que -renombrar los campos `CFBundleDisplayName`, `CFBundleIdentifier` y `CFBundleName` -en los siguientes archivos: - -* `Electron.app/Contents/Info.plist` -* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` - -También puedes renombrar el helper de la aplicación para evitar que aparezca -como `Electron Helper` en el Monitor de Actividades. Pero asegurate de renombrar -el nombre de archivo del ejecutable. - -La estructura de una aplicación renombrada será: - -``` -MyApp.app/Contents -├── Info.plist -├── MacOS/ -│   └── MyApp -└── Frameworks/ - ├── MyApp Helper EH.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper EH - ├── MyApp Helper NP.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper NP - └── MyApp Helper.app - ├── Info.plist - └── MacOS/ -    └── MyApp Helper -``` - -### Linux - -Puedes renombrar el ejectuable `electron` a cualquier nombre que desees. - -## Redefinición mediante la recompilación de Electron desde el código fuente - -También es posible redefinir Electron cambiando el nombre del producto y -compilandolo desde sus fuentes. Para realizar esto necesitas modificar el -archivo `atom.gyp` y realizar una compilación desde cero. - -### grunt-build-atom-shell - -La modificación a mano del código de Electron y su compilación puede resultar -complicada, por lo cual se ha generado una tarea Grunt para manejar esto de -forma automaticamente: -[grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell). - -Esta tarea se encargará de modificar el archivo `.gyp`, compilar el código desde -las fuentes, y luego reconstruir los módulos nativos de la aplicación para que -coincidan con el nuevo nombre del ejecutable. diff --git a/docs-translations/es/tutorial/application-packaging.md b/docs-translations/es/tutorial/application-packaging.md deleted file mode 100644 index 0e46a44d2b486..0000000000000 --- a/docs-translations/es/tutorial/application-packaging.md +++ /dev/null @@ -1,157 +0,0 @@ -# Empaquetamiento de aplicaciones - -Para proteger los recursos y el código fuente de tu aplicación, puedes optar por empaquetar -tu aplicación en un paquete [asar][asar]. - -## Generando un archivo `asar` - -Un paquete [asar][asar] es un formato sencillo similar a tar, este formato concatena todos los archivos en uno, -Electron puede leer el contenido sin desempaquetar todos los archivos. - -A continuación, los pasos para empaquetar tu aplicación con `asar`: - -### 1. Instalar asar - -```bash -$ npm install -g asar -``` - -### 2. Empaquetar utilizando `asar pack` - -```bash -$ asar pack your-app app.asar -``` - -## Utilizando los paquetes `asar` - -En Electron existen dos tipos de APIs: las APIs de Node, provistas por Node.js, -y las APIs Web, provistas por Chromium. Ambas APIs soportan la lectura de paquetes `asar`. - -### API Node - -Con parches especiales en Electron, las APIs de Node como `fs.readFile` and `require` -tratan los paquetes `asar` como directorios virtuales, y el contenido es accesible como si se tratara -de archivos normales en el sistema de archivos. - -Por ejemplo, supongamos que tenemos un paquete `example.asar` bajo `/path/to`: - -```bash -$ asar list /path/to/example.asar -/app.js -/file.txt -/dir/module.js -/static/index.html -/static/main.css -/static/jquery.min.js -``` - -Leer un archivo de nuestro paquete `asar`: - -```javascript -var fs = require('fs'); -fs.readFileSync('/path/to/example.asar/file.txt'); -``` - -Listar todos los archivos de la raíz: - -```javascript -var fs = require('fs'); -fs.readdirSync('/path/to/example.asar'); -``` - -Utilizar un módulo que se encuentra dentro del archivo: - -```javascript -require('/path/to/example.asar/dir/module.js'); -``` - -También puedes mostrar una página web contenida en un `asar` utilizando `BrowserWindow`. - -```javascript -var BrowserWindow = require('browser-window'); -var win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('file:///path/to/example.asar/static/index.html'); -``` - -### API Web - -En una págin web, los archivos que se encuentran en el paquete son accesibles a través del protocolo `file:`. -Al igual que la API Node, los paquetes `asar` son tratados como directorios. - -Por ejemplo, para obtener un archivo con `$.get`: - -```html - -``` - -### Utilizando un paquete `asar` como un archivo normal - -En algunas situaciones necesitaremos acceder al paquete `asar` como archivo, por ejemplo, -si necesitáramos verificar la integridad del archivo con un checksum. -Para casos así es posible utilizar el módulo `original-fs`, que provee la API `fs` original: - -```javascript -var originalFs = require('original-fs'); -originalFs.readFileSync('/path/to/example.asar'); -``` - -## Limitaciones de la API Node: - -A pesar de que hemos intentado que los paquetes `asar` funcionen como directorios de la mejor forma posible, -aún existen limitaciones debido a la naturaleza de bajo nivel de la API Node. - -### Los paquetes son de sólo lectura - -Los paquetes `asar` no pueden ser modificados, por lo cual todas las funciones que modifiquen archivos -no funcionarán. - -## Los directorios del paquete no pueden establecerse como working directories - -A pesar de que los paquetes `asar` son manejados virtualmente como directorios, -estos directorios no existen en el sistema de archivos, por lo cual no es posible establecerlos -como working directory, el uso de la opción `cwd` en algunas APIs podría causar errores. - -### Desempaquetamiento adicional en algunas APIs - -La mayoría de las APIs `fs` pueden leer u obtener información sobre un archivo en un paquete `asar` sin -la necesidad de desempaquetarlo, pero algunas APIs requieren la ruta real. En estos casos Electron extraerá -el archivo a una ruta temporal. Esto agrega un overhead a algunas APIs. - -Las APIs que requieren el desempaquetamiento adicional son: - -* `child_process.execFile` -* `fs.open` -* `fs.openSync` -* `process.dlopen` - Utilizado por `require` en los módulos nativos - -### Información falsa en `fs.stat` - -El objeto `Stats` retornado por `fs.stat` y otras funciones relacionadas, -no es preciso, ya que los archivos del paquete `asar` no existen en el sistema de archivos. -La utilización del objeto `Stats` sólo es recomendable para obtener el tamaño del archivo y/o -comprobar el tipo de archivo. - - -## Agregando archivos al paquete `asar` - -Como se menciona arriba, algunas APIs de Node desempaquetarán archivos cuando exista una llamada -que los referencie, además de los problemas de rendimiento que esto podría ocasionar, también -podría accionar alertas falsas en software antivirus. - -Para lidiar con esto, puedes desempaquetar algunos archivos utilizando la opción `--unpack`. -A continuación, un ejemplo que excluye las librerías compartidas de los módulos nativos: - -```bash -$ asar pack app app.asar --unpack *.node -``` - -Después de ejecutar este comando, además del archivo `app.asar`, también se creará -un directorio `app.asar.unpacked`, que contendrá los archivos desempaquetados. -Este directorio deberá copiarse junto con el archivo `app.asar` a la hora de distribuir la aplicación. - -[asar]: https://github.com/atom/asar diff --git a/docs-translations/es/tutorial/debugging-main-process.md b/docs-translations/es/tutorial/debugging-main-process.md deleted file mode 100644 index 1a764036e37a6..0000000000000 --- a/docs-translations/es/tutorial/debugging-main-process.md +++ /dev/null @@ -1,45 +0,0 @@ -# Depurando el proceso principal - -Los devtools sólo pueden depurar las páginas web (el código del proceso renderer). -Para depurar el código del proceso principal, Electron provee dos opciones para la línea de comandos: `--debug` y `--debug-brk`. - -## Opciones para la línea de comandos - -### `--debug=[port]` - -Esta opción escuchará mensajes del protocolo de depuración V8 en `port`, por defecto `port` es `5858`. - -### `--debug-brk=[port]` - -Similar a `--debug` pero realiza una pausa en la primera línea del script. - -## Utilizando node-inspector para depuración - -__Nota:__ Electron utiliza node v0.11.13, esta versión aún no funciona bien con node-inspector, -el proceso principal podría fallar al inspeccionar el objeto `process`. - -### 1. Iniciar [node-inspector][node-inspector] - -```bash -$ node-inspector -``` - -### 2. Activar el modo de depuración en Electron - -Es posible iniciar Electron con la opción de depuración: - -```bash -$ electron --debug=5858 your/app -``` - -o, pausar el script en la primera línea: - -```bash -$ electron --debug-brk=5858 your/app -``` - -### 3. Cargar la interfaz del depurador - -Abre http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 en Chrome. - -[node-inspector]: https://github.com/node-inspector/node-inspector diff --git a/docs-translations/es/tutorial/desktop-environment-integration.md b/docs-translations/es/tutorial/desktop-environment-integration.md deleted file mode 100644 index 5b40c0619d772..0000000000000 --- a/docs-translations/es/tutorial/desktop-environment-integration.md +++ /dev/null @@ -1,171 +0,0 @@ -# Integración con el entorno de escritorio - -Los sistemas operativos proveen diferentes características para integrar aplicaciones -en sus entornos de escritorio. Por ejemplo, en Windows, las aplicaciones pueden agregar accesos directos -en la JumpList de la barra de tareas, y en Mac, las aplicaciones pueden agregar un menú personalizado en el dock. - -Esta guía explica cómo integrar tu aplicación en esos entornos de escritorio a través de las APIs de Electron. - -## Documentos recientes (Windows y macOS) - -Windows y macOS proveen un acceso sencillo a la lista de documentos recientes. - -__JumpList:__ - -![JumpList, Archivos recientes](http://i.msdn.microsoft.com/dynimg/IC420538.png) - -__Menú Dock:__ - - - -Para agregar un archivo a la lista de documentos recientes, puedes utilizar: -[app.addRecentDocument][addrecentdocument] API: - -```javascript -var app = require('app'); -app.addRecentDocument('/Users/USERNAME/Desktop/work.type'); -``` - -También puedes utilizar [app.clearRecentDocuments](clearrecentdocuments) para vaciar la lista de documentos recientes: - -```javascript -app.clearRecentDocuments(); -``` - -### Notas sobre Windows - -Para activar esta característica en Windows, tu aplicación debe registrar un handler -para el tipo de archivo que quieres utilizar, de lo contrario el archivo no aparecerá -en la JumpList, aún después de agregarlo. Puedes encontrar más información sobre el proceso de -registrar tu aplicación en [Application Registration][app-registration]. - -Cuando un usuario haga click en un archivo de la JumpList, una nueva instancia de tu aplicación -se iniciará, la ruta del archivo se agregará como un argumento de la línea de comandos. - -### Notas sobre macOS - -Cuando un archivo es solicitado desde el menú de documentos recientes, el evento `open-file` -del módulo `app` será emitido. - -## Menú dock personalizado (macOS) - -macOS permite a los desarrolladores definir un menú personalizado para el dock, -el cual usualmente contiene algunos accesos directos a las características más comunes -de tu aplicación: - -__Menú dock de Terminal.app:__ - - - -Para establecer tu menú dock, puedes utilizar la API `app.dock.setMenu`, la cual sólo está disponible para macOS: - -```javascript -var app = require('app'); -var Menu = require('menu'); -var dockMenu = Menu.buildFromTemplate([ - { label: 'New Window', click: function() { console.log('New Window'); } }, - { label: 'New Window with Settings', submenu: [ - { label: 'Basic' }, - { label: 'Pro'} - ]}, - { label: 'New Command...'} -]); -app.dock.setMenu(dockMenu); -``` - -## Tareas de usuario (Windows) - -En Windows puedes especificar acciones personalizadas en la categoría `Tasks` del JumpList, -tal como menciona MSDN: - - -> Las aplicaciones definen tareas basadas en las características del programa -> y las acciones clave que se esperan de un usuario. Las tareas deben ser -> libres de contexto, es decir, la aplicación no debe encontrarse en ejecución -> para que estas acciones funcionen. También deberían ser las acciones estadísticamente -> más comunes que un usuario normal realizaría en tu aplicación, como por ejemplo, -> redactar un mensaje de correo electrónico, crear un documento en el procesador de textos, -> ejecutar una aplicación en cierto modo, o ejecutar alguno de sus subcomandos. Una aplicación -> no debería popular el menú con características avanzadas que el usuario estándar no necesita -> ni con acciones que sólo se realizan una vez, como por ejemplo, el registro. No utilices -> las tareas para mostrar elementos promocionales como actualizaciones u ofertas especiales. -> -> Es recomendable que la lista de tareas sea estática. Debe mantenerse a pesar -> de los cambios de estado de la aplicación. Aunque exista la posibilidad de variar -> el contenido de la lista dinámicamente, debes considerar que podría ser confuso -> para un usuario que no espera que el destino de la lista cambie. - -__Tareas de Internet Explorer:__ - -![IE](http://i.msdn.microsoft.com/dynimg/IC420539.png) - -A diferencia del menú dock en macOS, el cual es un menú real, las tareas de usuario en Windows -funcionan como accesos directos de aplicación, que al ser clickeados, lanzan el programa -con argumentos específicos. - -Para establecer las tareas de usuario en tu aplicación, puedes utilizar: -[app.setUserTasks][setusertaskstasks] API: - -```javascript -var app = require('app'); -app.setUserTasks([ - { - program: process.execPath, - arguments: '--new-window', - iconPath: process.execPath, - iconIndex: 0, - title: 'New Window', - description: 'Create a new window' - } -]); -``` - -Para purgar la lista de tareas, puedes llamar a `app.setUserTasks` con un array vacío: - -```javascript -app.setUserTasks([]); -``` - -Las tareas de usuario aún serán visibles después de cerrar tu aplicación, por lo cual -el ícono y la ruta del programa deben existir hasta que la aplicación sea desinstalada. - -## Accesos directos en el lanzador Unity (Linux) - -En Unity, es posible agregar algunas entradas personalizadas, modificando el archivo `.desktop`, -ver [Adding shortcuts to a launcher][unity-launcher]. - -__Accesos directos de Audacious:__ - -![audacious](https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles?action=AttachFile&do=get&target=shortcuts.png) - -## Barra de progreso en la barra de tareas (Windows y Unity) - -En Windows, un botón en la barra de tareas puede utilizarse para mostrar una barra de progreso. Esto permite -que una ventana muestre la información de progreso al usuario, sin que el usuario tenga la ventana de la aplicación activa. - -El entorno de escritorio Unity también posee una característica similar que permite mostrar una barra de progreso en el lanzador. - -__Barra de progreso en un botón de la barra de herramientas:__ - -![Taskbar Progress Bar](https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png) - -__Barra de progreso en el lanzador Unity:__ - -![Unity Launcher](https://cloud.githubusercontent.com/assets/639601/5081747/4a0a589e-6f0f-11e4-803f-91594716a546.png) - -Para establecer la barra de progreso de una ventana, puedes utilizar -[BrowserWindow.setProgressBar][setprogressbar] API: - -```javascript -var window = new BrowserWindow({...}); -window.setProgressBar(0.5); -``` - -[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath -[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments -[setusertaskstasks]: ../api/app.md#appsetusertaskstasks -[setprogressbar]: ../api/browser-window.md#browserwindowsetprogressbarprogress -[setrepresentedfilename]: ../api/browser-window.md#browserwindowsetrepresentedfilenamefilename -[setdocumentedited]: ../api/browser-window.md#browserwindowsetdocumenteditededited -[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx -[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher diff --git a/docs-translations/es/tutorial/devtools-extension.md b/docs-translations/es/tutorial/devtools-extension.md deleted file mode 100644 index 495f56058d5f9..0000000000000 --- a/docs-translations/es/tutorial/devtools-extension.md +++ /dev/null @@ -1,49 +0,0 @@ -# Extensión DevTools - -Para facilitar la depuración, Electron provee un soporte básico para la extensión -[Chrome DevTools][devtools-extension]. - -Para la mayoría de las extensiones devtools, simplemente puedes descargar el código fuente -y utilizar `BrowserWindow.addDevToolsExtension` para cargarlas, las extensiones cargadas -serán recordadas para que no sea necesario llamar a la función cada vez que creas una ventana. - -Por ejemplo, para usar la extensión [React DevTools](https://github.com/facebook/react-devtools), primero debes descargar el código fuente: - -```bash -$ cd /some-directory -$ git clone --recursive https://github.com/facebook/react-devtools.git -``` - -Luego cargas la aplicación en Electron, abriendo devtools en cualquier ventana, -y ejecutando este código en la consola devtools: - -```javascript -require('remote').require('browser-window').addDevToolsExtension('/some-directory/react-devtools'); -``` - -Para remover una extensión, puedes utilizar `BrowserWindow.removeDevToolsExtension` -especificando el nombre, y esta ya no se cargará la siguiente vez que abras devtools: - -```javascript -require('remote').require('browser-window').removeDevToolsExtension('React Developer Tools'); -``` - -## Formato de las extensiones devtools - -Idealmente todas las extensiones devtools escritas para Chrome pueden ser cargadas por Electron, -pero para ello deben estar en un directorio plano, las extensiones empaquetadas como `crx` -no pueden ser cargadas por Chrome a no ser que halles una forma de extraerlas a un directorio. - -## Páginas en segundo plano (background) - -Electron no soporta la característica de páginas en segundo plano de las extensiones de Chrome, -las extensiones que utilizan esta característica podrían no funcionar. - -## APIs `chrome.*` - -Algunas extensiones utilizan las APIs `chrome.*`, hemos realizado un esfuerzo -para implementar esas APIs en Electron, sin embargo no han sido implementadas en su totalidad. - -Dado que no todas las funciones `chrome.*` han sido implementadas, si la extensión devtools está utilizando otras APIs más allá de `chrome.devtools.*`, es muy probable que no funcione. Puedes reportar fallos en el issue tracker para que podamos agregar soporte a esas APIs. - -[devtools-extension]: https://developer.chrome.com/extensions/devtools diff --git a/docs-translations/es/tutorial/online-offline-events.md b/docs-translations/es/tutorial/online-offline-events.md deleted file mode 100644 index 450702e2f84c8..0000000000000 --- a/docs-translations/es/tutorial/online-offline-events.md +++ /dev/null @@ -1,80 +0,0 @@ -# Detección del evento en línea/fuera de línea - -La detección de estos eventos puede ser implementada en el proceso renderer utilizando las APIs HTML5 estándar, -como en este ejemplo: - -_main.js_ - -```javascript -var app = require('app'); -var BrowserWindow = require('browser-window'); -var onlineStatusWindow; - -app.on('ready', function() { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` - -Existen casos en donde necesitas responder a estos eventos desde el proceso principal. -El proceso principal no posee un objeto `navigator`, por lo tanto no puede detectar estos eventos directamente. -Es posible reenviar el evento al proceso principal mediante la utilidad de intercomunicación entre procesos (ipc): - -_main.js_ - -```javascript -var app = require('app'); -var ipc = require('ipc'); -var BrowserWindow = require('browser-window'); -var onlineStatusWindow; - -app.on('ready', function() { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); -}); - -ipc.on('online-status-changed', function(event, status) { - console.log(status); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` diff --git a/docs-translations/es/tutorial/quick-start.md b/docs-translations/es/tutorial/quick-start.md deleted file mode 100644 index b54c1fc364276..0000000000000 --- a/docs-translations/es/tutorial/quick-start.md +++ /dev/null @@ -1,148 +0,0 @@ -## Introducción - -Electron permite la creación de aplicaciones de escritorio utilizando JavaScript puro, a través de un runtime con APIs nativas. Puedes verlo como una variante de io.js, enfocado a aplicaciones de escritorio, en vez de servidores web. - -Esto no significa que Electron sea un binding de librerías GUI para JavaScript. -Electron utiliza páginas web como su GUI, por lo cual puedes verlo como un navegador Chromium mínimo, -controlado por JavaScript. - -### El proceso principal (main process) - -En Electron, el proceso que ejecuta el script `main` del `package.json` se llama __el proceso principal__. -El script que corre en el proceso principal puede crear páginas para mostrar la GUI. - -### El proceso renderer (renderer process) - -Dado que Electron utiliza Chromium para mostrar las páginas web, -también es utilizada la arquitectura multiproceso de Chromium. -Cada página web en Electron se ejecuta en su propio proceso, -el cual es llamado __el proceso renderer__. - -En los navegadores normales, las páginas web usualmente se ejecutan en un entorno -sandbox y no tienen acceso a los recursos nativos. Los usuarios de Electron tienen el poder -de utilizar las APIs de io.js en las páginas web, permitiendo interacciones de bajo nivel con el sistema operativo. - -### Diferencias entre el proceso principal y el proceso renderer - -El proceso principal crea páginas web mediante instancias de `BrowserWindow`. Cada instancia de `BrowserWindow` ejecuta su propia página web y su propio proceso renderer. -Cuando una instancia de `BrowserWindow` es destruida, también su proceso renderer correspondiente acaba. - -El proceso principal gestiona las páginas web y sus correspondientes procesos renderer. -Cada proceso renderer es aislado y sólo considera relevante la página web que corre en él. - -En las páginas web, no está permitido llamar a APIs relacionadas a la GUI nativa -porque la gestión de los recursos GUI nativos es peligrosa, y tiende a que ocurran leaks de memoria. -Si deseas realizar operaciones GUI en una página web, el proceso renderer de la página web debe comunicarse -con el proceso principal, y solicitar a este que realice esas operaciones. - -En Electron, hemos proveído el módulo [ipc](../../../docs/api/ipc-renderer.md) para la comunicación -entre el proceso principal y el proceso renderer. Y también hay un módulo [remote](../../../docs/api/remote.md) -para comunicación al estilo RPC. - -## Escribe tu primera aplicación Electron - -Generalmente, una aplicación Electron tendrá la siguiente estructura: - -```text -your-app/ -├── package.json -├── main.js -└── index.html -``` - -El formato de `package.json` es exactamente el mismo que cualquier módulo Node, -y el script especificado en el campo `main` será el script de arranque de tu aplicación, -a ser ejecutado por el proceso principal. Un ejemplo de `package.json` podría verse así: - -```json -{ - "name" : "your-app", - "version" : "0.1.0", - "main" : "main.js" -} -``` - -El `main.js` debería crear las ventanas y gestionar los eventos del sistema, un ejemplo típico sería: - -```javascript -var app = require('app'); // Módulo para controlar el ciclo de vida de la aplicación. -var BrowserWindow = require('browser-window'); // Módulo para crear uan ventana de navegador. - -// Mantener una referencia global al objeto window, si no lo haces, esta ventana -// se cerrará automáticamente cuando el objeto JavaScript sea recolectado (garbage collected): -var mainWindow = null; - -// Salir de todas las ventanas cuando se cierren. -app.on('window-all-closed', function() { - // En macOS es común que las aplicaciones y su barra de menú - // se mantengan activas hasta que el usuario cierre la aplicación - // explícitamente utilizando Cmd + Q - if (process.platform != 'darwin') { - app.quit(); - } -}); - -// Este método será llamado cuando Electron haya finalizado la inicialización -// y esté listo para crear ventanas de navegador. -app.on('ready', function() { - // Crear la ventana. - mainWindow = new BrowserWindow({width: 800, height: 600}); - - // cargar el index.html de nuestra aplicación. - mainWindow.loadURL('file://' + __dirname + '/index.html'); - - // Desplegar devtools. - mainWindow.openDevTools(); - - // Evento emitido cuando se cierra la ventana. - mainWindow.on('closed', function() { - // Eliminar la referencia del objeto window. - // En el caso de soportar multiples ventanas, es usual almacenar - // los objetos window en un array, este es el momento en el que debes eliminar el elemento correspondiente. - mainWindow = null; - }); -}); -``` - -Finalmente el `index.html` es la página web que mostraremos: - -```html - - - - Hello World! - - -

Hello World!

- We are using io.js - and Electron . - - -``` - -## Ejecutar la aplicación - -Cuando termines de escribir tu aplicación, puedes distribuirla -siguiendo la [guía de distribución](./application-distribution-es.md) -y luego ejecutar la aplicación empaquetada. También puedes utilizar el binario de Electron -para ejecutar tu aplicación de forma directa. - -En Windows: - -```bash -$ .\electron\electron.exe your-app\ -``` - -En Linux: - -```bash -$ ./electron/electron your-app/ -``` - -En macOS: - -```bash -$ ./Electron.app/Contents/MacOS/Electron your-app/ -``` - -`Electron.app` es parte del paquete de release de Electron, puedes descargarlo [aquí](https://github.com/electron/electron/releases). diff --git a/docs-translations/es/tutorial/supported-platforms.md b/docs-translations/es/tutorial/supported-platforms.md deleted file mode 100644 index ff08a5e148352..0000000000000 --- a/docs-translations/es/tutorial/supported-platforms.md +++ /dev/null @@ -1,30 +0,0 @@ -# Plataformas soportadas - -Las siguientes plataformas son soportadas por Electron: - -### macOS - -Sólo se proveen binarios de 64 bit para macOS. -La versión mínima soportada es macOS 10.8. - -### Windows - -Windows 7 y posteriores son soportados, las versiones antiguas no son soportadas (y no funcionan). - -Se proveen binarios para las arquitecturas `x86` y `amd64` (x64). -Nota: La versión para `ARM` de Windows no está soportada aún. - -### Linux - -Los binarios preconstruidos para `ia32`(`i686`) y `x64`(`amd64`) son construidos sobre -Ubuntu 12.04, el binario para `arm` es construido sobre ARM v7 con la ABI hard-float -y NEON para Debian Wheezy. - -La posibilidad de que un binario preconstruido se ejecute en una distribución determinada -depende de las librerías contra las que fue enlazado Electron. -Por ahora sólo se garantiza la ejecución en Ubuntu 12.04, aunque también se ha verificado -el funcionamiento de los binarios preconstruidos en las siguientes plataformas: - -* Ubuntu 12.04 and later -* Fedora 21 -* Debian 8 diff --git a/docs-translations/es/tutorial/using-native-node-modules.md b/docs-translations/es/tutorial/using-native-node-modules.md deleted file mode 100644 index 78409049ad933..0000000000000 --- a/docs-translations/es/tutorial/using-native-node-modules.md +++ /dev/null @@ -1,57 +0,0 @@ -# Utilizando módulos Node nativos - -Los módulos Node nativos son soportados por Electron, pero dado que Electron -está utilizando una versión distinta de V8, debes especificar manualmente la -ubicación de las cabeceras de Electron a la hora de compilar módulos nativos. - -## Compatibilidad de módulos nativos - -A partir de Node v0.11.x han habido cambios vitales en la API de V8. -Es de esperar que los módulos escritos para Node v0.10.x no funcionen con Node v0.11.x. -Electron utiliza Node v.0.11.13 internamente, y por este motivo tiene el mismo problema. - -Para resolver esto, debes usar módulos que soporten Node v0.11.x, -[muchos módulos](https://www.npmjs.org/browse/depended/nan) soportan ambas versiones. -En el caso de los módulos antiguos que sólo soportan Node v0.10.x, debes usar el módulo -[nan](https://github.com/rvagg/nan) para portarlos a v0.11.x. - -## ¿Cómo instalar módulos nativos? - -### La forma fácil - -La forma más sencilla de recompilar módulos nativos es a través del paquete -[`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild), -el cual abstrae y maneja los pasos de descargar las cabeceras y compilar los módulos nativos: - -```sh -npm install --save-dev electron-rebuild - -# Ejecuta esto cada vez que ejecutes npm install -./node_modules/.bin/electron-rebuild -``` - -### La forma node-gyp - -Para compilar módulos Node con las cabeceras de Electron, debes indicar a `node-gyp` -desde dónde descargar las cabeceras y cuál versión usar: - -```bash -$ cd /path-to-module/ -$ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=https://atom.io/download/atom-shell -``` - -Los cambios en `HOME=~/.electron-gyp` fueron para especificar la ruta de las cabeceras. -La opción `--target=0.29.1` es la versión de Electron. La opción `--dist-url=...` especifica -dónde descargar las cabeceras. `--arch=x64` indica que el módulo será compilado para un sistema de 64bit. - -### La forma npm - -También puedes usar `npm` para instalar módulos, los pasos son exactamente igual a otros módulos Node, -con la excepción de que necesitas establecer algunas variables de entorno primero: - -```bash -export npm_config_disturl=https://atom.io/download/atom-shell -export npm_config_target=0.29.1 -export npm_config_arch=x64 -HOME=~/.electron-gyp npm install module-name -``` diff --git a/docs-translations/es/tutorial/using-pepper-flash-plugin.md b/docs-translations/es/tutorial/using-pepper-flash-plugin.md deleted file mode 100644 index 9015bafc643d5..0000000000000 --- a/docs-translations/es/tutorial/using-pepper-flash-plugin.md +++ /dev/null @@ -1,55 +0,0 @@ -# Utilizando el plugin Pepper Flash - -El plugin Pepper Flash es soportado ahora. Para utilizar pepper flash en Electron, debes especificar la ubicación del plugin manualmente y activarlo en tu aplicación. - -## Preparar una copia del plugin Flash - -En macOS y Linux, el detalle del plugin puede encontrarse accediendo a `chrome://plugins` en el navegador. Su ubicación y versión son útiles para el soporte. También puedes copiarlo a otro lugar. - -## Agrega la opción a Electron - -Puedes agregar la opción `--ppapi-flash-path` y `ppapi-flash-version` o utilizar el método `app.commandLine.appendSwitch` antes del evento ready de la aplicación. -También puedes agregar la opción `plugins` de `browser-window`. Por ejemplo, - -```javascript -var app = require('app'); -var BrowserWindow = require('browser-window'); - -// Keep a global reference of the window object, if you don't, the window will -// be closed automatically when the javascript object is GCed. -var mainWindow = null; - -// Quit when all windows are closed. -app.on('window-all-closed', function() { - if (process.platform != 'darwin') { - app.quit(); - } -}); - -// Specify flash path. -// On Windows, it might be /path/to/pepflashplayer.dll -// On macOS, /path/to/PepperFlashPlayer.plugin -// On Linux, /path/to/libpepflashplayer.so -app.commandLine.appendSwitch('ppapi-flash-path', '/path/to/libpepflashplayer.so'); - -// Specify flash version, for example, v17.0.0.169 -app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169'); - -app.on('ready', function() { - mainWindow = new BrowserWindow({ - 'width': 800, - 'height': 600, - 'web-preferences': { - 'plugins': true - } - }); - mainWindow.loadURL('file://' + __dirname + '/index.html'); - // Something else -}); -``` - -## Activar el plugin flash en una etiqueta `` -Agrega el atributo `plugins`. -```html - -``` diff --git a/docs-translations/es/tutorial/using-selenium-and-webdriver.md b/docs-translations/es/tutorial/using-selenium-and-webdriver.md deleted file mode 100644 index 919a889d38dd7..0000000000000 --- a/docs-translations/es/tutorial/using-selenium-and-webdriver.md +++ /dev/null @@ -1,72 +0,0 @@ -# Utilizando Selenium y WebDriver - -De [ChromeDriver - WebDriver for Chrome][chrome-driver]: - -> WebDriver es una herramienta de código abierto para automatizar el testing de aplicaciones web -> en varios navegadores. WebDriver provee funciones de navegación, entrada de usuario, -> ejecución de JavaScript, y más. ChromeDriver es un servidor standalone que implementa -> el protocolo de WebDriver para Chromium. Se encuentra en desarrollo por los miembros de -> Chromium y WebDriver. - -En la página de [lanzamientos](https://github.com/electron/electron/releases) de Electron encontrarás paquetes de `chromedriver`. - -## Ajustando parámetros con WebDriverJs - -[WebDriverJs](https://code.google.com/p/selenium/wiki/WebDriverJs) provee -un paquete Node para realizar testing con web driver, lo usaremos como ejemplo. - -### 1. Inicia chrome driver - -Primero necesitas descargar el binario `chromedriver` y ejecutarlo: - -```bash -$ ./chromedriver -Starting ChromeDriver (v2.10.291558) on port 9515 -Only local connections are allowed. -``` - -Recuerda el puerto `9515`, lo utilizaremos después. - -### 2. Instala WebDriverJS - -```bash -$ npm install selenium-webdriver -``` - -### 3. Conecta chrome driver - -El uso de `selenium-webdriver` junto con Electron es básicamente el mismo que el original, -excepto que necesitas especificar manualmente cómo se conectará el chrome driver -y dónde encontrará el binario de Electron: - -```javascript -var webdriver = require('selenium-webdriver'); - -var driver = new webdriver.Builder() - // El puerto "9515" es que abre chrome driver. - .usingServer('http://localhost:9515') - .withCapabilities({chromeOptions: { - // Aquí especificamos la ruta a Electron - binary: '/Path-to-Your-App.app/Contents/MacOS/Atom'}}) - .forBrowser('electron') - .build(); - -driver.get('http://www.google.com'); -driver.findElement(webdriver.By.name('q')).sendKeys('webdriver'); -driver.findElement(webdriver.By.name('btnG')).click(); -driver.wait(function() { - return driver.getTitle().then(function(title) { - return title === 'webdriver - Google Search'; - }); -}, 1000); - -driver.quit(); -``` - -## Workflow - -Para probar tu aplicación sin recompilar Electron, simplemente [copia](https://github.com/electron/electron/blob/master/docs/tutorial/application-distribution.md) las fuentes de tu aplicación en el directorio de recursos de Electron. - -[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/ - - diff --git a/docs-translations/fr-FR/README.md b/docs-translations/fr-FR/README.md deleted file mode 100644 index fc505bc770cb4..0000000000000 --- a/docs-translations/fr-FR/README.md +++ /dev/null @@ -1,91 +0,0 @@ -Vérifiez que vous utilisez la bonne version de la documentation. -Le numéro de version devrait faire partie de l'URL de la page. -Si ce n'est pas le cas, vous utilisez probablement la documentation d'une -branche de développement qui peut contenir des changements API qui ne sont pas -compatibles avec votre version d'Electron. Si c'est le cas, vous pouvez changer -de version sur la liste [versions disponibles](http://electron.atom.io/docs/), -ou, si vous utilisez l'interface de GitHub, ouvrez la liste déroulante "Switch -branches/tags" afin de sélectionner le tag de votre version. - -## FAQ - -Avant de créer un ticket, vérifiez que votre problème n'a pas déjà sa réponse -dans la FAQ : - -* [Electron FAQ](faq/electron-faq.md) - -## Guides - -* [Plateformes supportées](tutorial/supported-platforms.md) -* [Distribution de l'Application](tutorial/application-distribution.md) -* [Guide de Soumission Mac App Store](tutorial/mac-app-store-submission-guide.md) -* [Créer une archive](tutorial/application-packaging.md) -* [Utiliser Modules Natifs de Node](tutorial/using-native-node-modules.md) -* [Debugger Processus Principal](tutorial/debugging-main-process.md) -* [Utiliser Selenium et WebDriver](tutorial/using-selenium-and-webdriver.md) -* [Extension DevTools](tutorial/devtools-extension.md) -* [Utiliser le Plugin Pepper Flash](tutorial/using-pepper-flash-plugin.md) -* [Utiliser le Plugin Widevine CDM](tutorial/using-widevine-cdm-plugin.md) - -## Tutoriels - -* [Démarrage Rapide](tutorial/quick-start.md) -* [Intégration Environnement de Bureau](tutorial/desktop-environment-integration.md) -* [Détection des Evènements En ligne/Hors ligne](tutorial/online-offline-events.md) - -## Références API - -* [Synopsis](api/synopsis.md) -* [L'objet Process](api/process.md) -* [Commandes Chromes Supportées](api/chrome-command-line-switches.md) -* [Variables d'Environnement](api/environment-variables.md) - -### Eléments DOM Personnalisés: - -* [Objet `File`](api/file-object.md) -* [Tag ``](api/web-view-tag.md) -* [Fonction `window.open`](api/window-open.md) - -### Modules pour le Processus Principal : - -* [app](api/app.md) -* [autoUpdater](api/auto-updater.md) -* [BrowserWindow](api/browser-window.md) -* [contentTracing](api/content-tracing.md) -* [dialog](api/dialog.md) -* [globalShortcut](api/global-shortcut.md) -* [ipcMain](api/ipc-main.md) -* [Menu](api/menu.md) -* [MenuItem](api/menu-item.md) -* [powerMonitor](api/power-monitor.md) -* [powerSaveBlocker](api/power-save-blocker.md) -* [protocol](api/protocol.md) -* [session](api/session.md) -* [webContents](api/web-contents.md) -* [Tray](api/tray.md) - -### Modules pour le Processus d'Affichage (Page Web) : - -* [desktopCapturer](api/desktop-capturer.md) -* [ipcRenderer](api/ipc-renderer.md) -* [remote](api/remote.md) -* [webFrame](api/web-frame.md) - -### Modules pour les deux Processus : - -* [clipboard](api/clipboard.md) -* [crashReporter](api/crash-reporter.md) -* [nativeImage](api/native-image.md) -* [screen](api/screen.md) -* [shell](api/shell.md) - -## Développement - -* [Style de Code](development/coding-style.md) -* [Hiérarchie du Code Source](development/source-code-directory-structure.md) -* [Différences Techniques par rapport à NW.js (anciennement node-webkit)](development/atom-shell-vs-node-webkit.md) -* [Aperçu du Système de Build](development/build-system-overview.md) -* [Instructions de Build (macOS)](development/build-instructions-osx.md) -* [Instructions de Build (Windows)](development/build-instructions-windows.md) -* [Instructions de Build (Linux)](development/build-instructions-linux.md) -* [Installer un Serveur de Symbol dans le debugger](development/setting-up-symbol-server.md) diff --git a/docs-translations/fr-FR/faq/electron-faq.md b/docs-translations/fr-FR/faq/electron-faq.md deleted file mode 100644 index 1a82bce680096..0000000000000 --- a/docs-translations/fr-FR/faq/electron-faq.md +++ /dev/null @@ -1,129 +0,0 @@ -# Electron FAQ - -## Quand est mise à jour la version de Chrome utilisée par Electron ? - -La version de Chrome qu'utilise Electron est en général mise à jour une ou deux -semaines après la sortie d'une nouvelle version stable de Chrome. - -Etant donné que nous n'utilisons que les versions stables de Chrome, si un fix -important est en beta ou en dev, nous l'intégrerons à la version que nous -utilisons. - -## Quand est mise à jour la version de Node.js utilisée par Electron ? - -Quand une nouvelle version de Node.js sort, nous attendons en général un mois -avant de mettre à jour celle que nous utilisons dans Electron. Ceci afin -d'éviter les bugs introduits par les nouvelles versions, ce qui arrive très -souvent. - -Les nouvelles fonctionnalités de Node.js arrivant la plupart du temps via V8, -et Electron utilisant le V8 du navigateur Chrome, la nouvelle fonctionnalité -JavaScript de la nouvelle version de Node.js est bien souvent déjà dans -Electron. - -## La fenêtre/barre d'état de mon application disparait après quelques minutes. - -Cela se produit quand la variable qui est utilisée pour stocker la fenêtre/barre -d'état est libérée par le ramasse-miettes. - -Nous vous recommandons de lire les articles suivants quand vous rencontrez le -problème : - -* [Management de la Mémoire][memory-management] (Anglais) -* [Portée d'une Variable][variable-scope] (Anglais) - -Si vous voulez corriger rapidement le problème, vous pouvez rendre les variables -globales en changeant votre code de ça : - -```javascript -app.on('ready', function() { - var tray = new Tray('/path/to/icon.png'); -}) -``` - -à ça : - -```javascript -var tray = null; -app.on('ready', function() { - tray = new Tray('/path/to/icon.png'); -}) -``` - -## Je n'arrive pas à utiliser jQuery/RequireJS/Meteor/AngularJS dans Electron. - -A cause de l'intégration de Node.js dans Electron, certains mots-clés sont -insérés dans la DOM, comme `module`, `exports`, `require`. Ceci pose des -problèmes pour certaines bibliothèques qui utilisent les mêmes mots-clés. - -Pour résoudre ce problème, vous pouvez désactiver l'intégration de node dans -Electron : - -```javascript -// Dans le processus principal. -var mainWindow = new BrowserWindow({ - webPreferences: { - nodeIntegration: false - } -}); -``` - -Mais si vous voulez garder la possibilité d'utiliser Node.js et les APIs -Electron, vous devez renommer les mots-clés dans la page avant d'inclure -d'autres bibliothèques : - -```html - - - - -``` - -## `require('electron').xxx` is undefined. - -Lors de l'utilisation des modules d'Electron, vous pouvez avoir une erreur : - -``` -> require('electron').webFrame.setZoomFactor(1.0); -Uncaught TypeError: Cannot read property 'setZoomLevel' of undefined -``` - -Ceci se produit quand vous avez le [module npm `electron`][electron-module] -d'installé, soit en local ou en global, ce qui a pour effet d'écraser les -modules de base d'Electron. - -Vous vérifiez que vous utilisez les bons modules, vous pouvez afficher le -chemin du module `electron` : - -```javascript -console.log(require.resolve('electron')); -``` - -et vérifier si il est de la forme : - -``` -"/path/to/Electron.app/Contents/Resources/atom.asar/renderer/api/lib/exports/electron.js" -``` - -S'il est de la forme `node_modules/electron/index.js`, vous devez supprimer le -module npm `electron`, ou le renommer. - -```bash -npm uninstall electron -npm uninstall -g electron -``` - -Si vous utilisez le module de base mais que vous continuez d'avoir -l'erreur, ça vient probablement du fait que vous utilisez le module dans le -mauvais processus. Par exemple `electron.app` peut uniquement être utilisé -dans le processus principal, tandis que `electron.webFrame` est uniquement -disponible dans le processus d'affichage. - -[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 diff --git a/docs-translations/fr-FR/styleguide.md b/docs-translations/fr-FR/styleguide.md deleted file mode 100644 index 9dac1955aef58..0000000000000 --- a/docs-translations/fr-FR/styleguide.md +++ /dev/null @@ -1,101 +0,0 @@ -# Règles de style pour la documentation d'Electron - -Choisissez la section appropriée : [lire la documentation d'Electron](#reading-electron-documentation) -ou [écrire de la documentation pour Electron](#writing-electron-documentation). - -## Ecrire de la documentation pour Electron - -La documentation d'Electron a été écrite en suivant les règles ci-dessous : - -- Maximum un titre `h1` par page. -- Utilisation de `bash` au lieu de `cmd` dans les blocs de code (à cause de la - coloration syntaxique). -- Les titres `h1` devraient reprendre le nom de l'objet (i.e. `browser-window` → - `BrowserWindow`). - - Cependant, les traits d'union sont acceptés pour les noms de fichier. -- Pas de titre directement après un autre, ajoutez au minimum une ligne de - description entre les deux. -- Les entêtes des méthodes sont entre accents graves (backquotes) `code`. -- Les entêtes des évènements sont entre des apostrophes 'quotation'. -- Les listes ne doivent pas dépasser 2 niveaux (à cause du formattage du - markdown). -- Ajouter des titres de section: Evènements, Méthodes de classe, et Méthodes - d'instance. -- Utiliser 'will' au lieu de 'would' lors de la description du retour. -- Les évènements et méthodes sont des titres `h3`. -- Les arguments optionnels sont notés `function (required[, optional])`. -- Les arguments optionnels sont indiqués quand appelés dans la liste. -- La longueur des lignes ne dépasse pas 80 caractères. -- Les méthodes spécifiques à une plateforme sont notées en italique. - - ```### `method(foo, bar)` _macOS_``` -- Préférer 'in the ___ process' au lieu de 'on' - -### Traductions de la Documentation - -Les traductions de la documentation d'Electron sont dans le dossier -`docs-translations`. - -Pour ajouter une nouvelle langue (ou commencer) : - -- Créer un sous-dossier avec comme nom le code langage. -- A l'intérieur de ce dossier, dupliquer le dossier `docs`, en gardant le même - nom de dossiers et de fichiers. -- Traduire les fichiers. -- Mettre à jour le `README.md` à l'intérieur du dossier de langue en mettant les - liens vers les fichiers traduits. -- Ajouter un lien vers le nouveau dossier de langue dans le [README](https://github.com/electron/electron#documentation-translations) - principal d'Electron. - -## Lire la documentation d'Electron - -Quelques indications pour comprendre la syntaxe de la documentation d'Electron. - -### Méthodes - -Un exemple de la documentation d'une [méthode](https://developer.mozilla.org/en-US/docs/Glossary/Method) -(Anglais) - ---- - -`methodName(required[, optional]))` - -* `require` String (**required**) -* `optional` Integer - ---- - -Le nom de la méthode est suivi des arguments de celle-ci. Les arguments -optionnels sont notés entre crochets, avec une virgule si ceux-ci suivent un -autre argument. - -En-dessous de la méthode, chaque argument est détaillé avec son type. -Celui-ci peut être un type générique : -[`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) -ou un type personnalisé comme le [`webContent`](api/web-content.md) d'Electron. - -### Evènements - -Un exemple d'une documentation d'un [évènement](https://developer.mozilla.org/en-US/docs/Web/API/Event) -(Anglais) ---- - -Event: 'wake-up' - -Returns: - -* `time` String - ---- - -L'évènement est une chaine utilisée après un listener `.on`. Si il retourne une -valeur, elle est écrite en dessous ainsi que son type. Si vous voulez écouter et -répondre à l'évènement wake-up, ça donne quelque chose comme : - -```javascript -Alarm.on('wake-up', function(time) { - console.log(time) -}) -``` diff --git a/docs-translations/jp/README.md b/docs-translations/jp/README.md deleted file mode 100644 index a2d18109cf60e..0000000000000 --- a/docs-translations/jp/README.md +++ /dev/null @@ -1,96 +0,0 @@ -使用している Electron のバージョンに応じたドキュメントを使うように確認してください。 -ドキュメントのバージョン番号はページの URL の一部になっています。 -そうでない場合、おそらくご使用の Electron のバージョンと互換性のない API 変更を含んだ development ブランチのドキュメントを使っているものと思われます。 -その場合、atom.io の [available versions](http://electron.atom.io/docs/) リストにある別のバージョンのドキュメントに切り替えることができます。また GitHub で閲覧している場合、"Switch branches/tags" ドロップダウンを開いて、バージョンに対応したタグを選ぶこともできます。 - -_リンクになっていないリストは未翻訳のものです。_ -## FAQ - -頻繁に聞かれる質問がありますので、issueを作成する前にこれをチェックしてください。 - -* [Electron FAQ](faq/electron-faq.md) - -## ガイド - -* [サポートするプラットフォーム](tutorial/supported-platforms.md) -* [セキュリティ](tutorial/security.md) -* [Electronのバージョン管理](tutorial/electron-versioning.md) -* [アプリケーションの配布](tutorial/application-distribution.md) -* [Mac App Store 提出ガイド](tutorial/mac-app-store-submission-guide.md) -* Windows Store Guide (tutorial/windows-store-guide.md) -* [アプリケーションのパッケージ化](tutorial/application-packaging.md) -* [ネイティブのNodeモジュールを使用する](tutorial/using-native-node-modules.md) -* [メインプロセスのデバッグ](tutorial/debugging-main-process.md) -* [Selenium と WebDriverを使用する](tutorial/using-selenium-and-webdriver.md) -* [DevTools エクステンション](tutorial/devtools-extension.md) -* [Pepper Flashプラグインを使用する](tutorial/using-pepper-flash-plugin.md) -* [Widevine CDMプラグインを使用する](tutorial/using-widevine-cdm-plugin.md) -* [継続的インテグレーションシステムによるテスト(Travis, Jenkins)](tutorial/testing-on-headless-ci.md) - - -# チュートリアル - -* [クイックスタート](tutorial/quick-start.md) -* [デスクトップ環境の統合](tutorial/desktop-environment-integration.md) -* [オンライン/オフライン イベントの検知](tutorial/online-offline-events.md) - -## API リファレンス - -* [概要](api/synopsis.md) -* [Process Object](api/process.md) -* [サポートしているChromeコマンドラインスイッチ](api/chrome-command-line-switches.md) -* [環境変数](api/environment-variables.md) - -### カスタムDOM要素: - -* [`File` Object](api/file-object.md) -* [`` タグ](api/web-view-tag.md) -* [`window.open` 関数](api/window-open.md) - -### Main Processのモジュール: - -* [app](api/app.md) -* [autoUpdater](api/auto-updater.md) -* BrowserWindow (api/browser-window.md) - * [フレームの無いウィンドウ](api/frameless-window.md) -* [contentTracing](api/content-tracing.md) -* [dialog](api/dialog.md) -* [globalShortcut](api/global-shortcut.md) -* [ipcMain](api/ipc-main.md) -* [Menu](api/menu.md) -* [MenuItem](api/menu-item.md) -* [powerMonitor](api/power-monitor.md) -* [powerSaveBlocker](api/power-save-blocker.md) -* [protocol](api/protocol.md) -* [session](api/session.md) -* [systemPreferences](api/system-preferences.md) -* [Tray](api/tray.md) -* webContents (api/web-contents.md) - -### Renderer Processのモジュール (Web Page): - -* [desktopCapturer](api/desktop-capturer.md) -* [ipcRenderer](api/ipc-renderer.md) -* [remote](api/remote.md) -* [webFrame](api/web-frame.md) - -### 両方のProcessのモジュール : - -* [clipboard](api/clipboard.md) -* [crashReporter](api/crash-reporter.md) -* [nativeImage](api/native-image.md) -* [screen](api/screen.md) -* [shell](api/shell.md) - -## 開発 - - -* [コーディング規約](development/coding-style.md) -* Source Code Directory Structure (development/source-code-directory-structure.md) -* [NW.js(node-webkit) との技術的違い](development/atom-shell-vs-node-webkit.md) -* Build System Overview (development/build-system-overview.md) -* [ビルド方法(macOS)](development/build-instructions-osx.md) -* Build Instructions (Windows) (development/build-instructions-windows.md) -* Build Instructions (Linux) (development/build-instructions-linux.md) -* Debug Instructions (Windows) (development/debug-instructions-windows.md) -* Setting Up Symbol Server in debugger (development/setting-up-symbol-server.md) diff --git a/docs-translations/jp/api/accelerator.md b/docs-translations/jp/api/accelerator.md deleted file mode 100644 index 032747ddf60e4..0000000000000 --- a/docs-translations/jp/api/accelerator.md +++ /dev/null @@ -1,43 +0,0 @@ -# Accelerator - -acceleratorは、キーボードショートカットを示す文字列です。複数の修飾語句とキーコードを `+` 文字で結合します。 - -例: - -* `Command+A` -* `Ctrl+Shift+Z` - -## プラットフォームの留意点 - - -macOSでは`Command` キー、LinuxとWindowsでは`Control` キーを意味する`CommandOrControl`はいくつかのacceleratorを定義しますが、LinuxとWindowsでは、`Command` キーは何の効果もありません。 - - `Super` キーは、WindowsとLinuxでは `Windows` キーに、macOSでは、`Cmd` キーに関連付けられます。 - -## 提供されている修飾語句 - -* `Command` (または、短く `Cmd`) -* `Control` (または、短く `Ctrl`) -* `CommandOrControl` (または、短く `CmdOrCtrl`) -* `Alt` -* `Shift` -* `Super` - -## 提供されているキーコード - -* `0` to `9` -* `A` to `Z` -* `F1` to `F24` -* `~`, `!`, `@`, `#`, `$`などの記号 -* `Plus` -* `Space` -* `Backspace` -* `Delete` -* `Insert` -* `Return` (またはエイリアスで `Enter`) -* `Up`と `Down`,`Left`、 `Right` -* `Home` と `End` -* `PageUp` と `PageDown` -* `Escape` (または、短く `Esc`) -* `VolumeUp`と `VolumeDown` 、 `VolumeMute` -* `MediaNextTrack`と `MediaPreviousTrack`、 `MediaStop` 、 `MediaPlayPause` diff --git a/docs-translations/jp/api/app.md b/docs-translations/jp/api/app.md deleted file mode 100644 index 2adac343033ab..0000000000000 --- a/docs-translations/jp/api/app.md +++ /dev/null @@ -1,443 +0,0 @@ -# app - - `app` モジュールは、アプリケーションのライフサイクルコントロールを担います。 - -次の例は、最後のウィンドウが閉じたときにアプリケーションを終了させる方法を示しています。 - -```javascript -const app = require('electron').app; -app.on('window-all-closed', function() { - app.quit(); -}); -``` - -## イベント - -`app` オブジェクトは次のイベントを出力します。 - -### イベント: 'will-finish-launching' - -アプリケーションの基礎起動が終わったときに出力されます。Windows と Linuxでは、 `will-finish-launching` イベントと`ready`イベントは同じです。macOSでは、`NSApplication`の `applicationWillFinishLaunching` 通知をに相当します。通常、`open-file`と`open-url` 用のリスナーの設定、クラッシュレポートの開始、自動アップデートをします。 - -ほとんどの場合、 `ready` イベントハンドラーですべてをするべきです。 - -### イベント: 'ready' - -Electronの初期化が終わった時に出力します。 - -### イベント: 'window-all-closed' - -全てのウィンドウを閉じたときに出力します。 - -このイベントは、アプリケーションが終了する予定ではないときのみ出力します。ユーザーが `Cmd + Q`を押したり、開発者が`app.quit()`をコールすると、Electronは最初にすべてのウィンドウをクローズしようとし、`will-quit`イベントを出力します。この場合、`window-all-closed`イベントは出力されません。 - -### イベント: 'before-quit' - -戻り値: - -* `event` Event - -アプリケーションがウィンドウをクローズし始める前に出力します。`event.preventDefault()`をコールすると、アプリケーションを終了させる既定の挙動を止めることができます。 - -### イベント: 'will-quit' - -戻り値: - -* `event` Event - -全てのウィンドウが閉じて、アプリケーションを終了するときに出力します。`event.preventDefault()`をコールすると、アプリケーションを終了させる既定の挙動を止めることができます。 - -詳細は、`will-quit`イベント と `window-all-closed` イベントの違いは、`window-all-closed` イベントの説明を見てください。 - -### イベント: 'quit' - -戻り値: - -* `event` Event -* `exitCode` Integer - -アプリケーションが終了したときに出力されます。 - -### イベント: 'open-file' _macOS_ - -戻り値: - -* `event` Event -* `path` String - -アプリケーションでファイルを開こうとしたときに出力します。アプリケーションがすでに起動し、OSがファイルを開くアプリケーションを再使用したいとき、`open-file`イベントは出力します。ファイルがdockにドロップアウトされ、アプリケーションがまだ起動していないときにも`open-file` は出力します。このケースを処理するために、アプリケーションの起動のかなり早い段階で、`open-file` イベントをリッスンして確認します(まだ `ready` イベントが出力する前に)。 - -このイベントをハンドルしたいときには `event.preventDefault()` をコールすべきです。 - -Windowsでは、ファイルパスを取得するために、 `process.argv` をパースする必要があります。 - -### イベント: 'open-url' _macOS_ - -戻り値: - -* `event` Event -* `url` String - -アプリケーションでURLを開こうとしたときに出力されます。URLスキーマーは、アプリケーションが開くように登録しなければなりません。 - -このイベントをハンドルしたい場合は、`event.preventDefault()`をコールすべきです。 - -### イベント: 'activate' _macOS_ - -戻り値: - -* `event` Event -* `hasVisibleWindows` Boolean - -アプリケーションがアクティブになったときに出力されます。通常は、アプリケーションのドックアイコンをクリックしたときに発生します。 - -### イベント: 'browser-window-blur' - -戻り値: - -* `event` Event -* `window` BrowserWindow - -[browserWindow](browser-window.md) からフォーカスが外れたときに出力されます。 - -### イベント: 'browser-window-focus' - -戻り値: - -* `event` Event -* `window` BrowserWindow - -[browserWindow](browser-window.md) にフォーカスが当たったとき出力されます。 - -### イベント: 'browser-window-created' - -戻り値: - -* `event` Event -* `window` BrowserWindow - -新しい [browserWindow](browser-window.md) が作成されたときに出力されます。 - -### イベント: 'certificate-error' - -戻り値: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `url` URL -* `error` String - The error code -* `certificate` Object - * `data` Buffer - PEM encoded data - * `issuerName` String -* `callback` Function - - `url` の `certificate` 検証に失敗したときに発生します。証明書を信頼するために`event.preventDefault()` と `callback(true)`をコールして既定の動作を止める必要があります。 - -```javascript -session.on('certificate-error', function(event, webContents, url, error, certificate, callback) { - if (url == "https://github.com") { - // Verification logic. - event.preventDefault(); - callback(true); - } else { - callback(false); - } -}); -``` - -### イベント: 'select-client-certificate' - -戻り値: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `url` URL -* `certificateList` [Objects] - * `data` Buffer - PEM encoded data - * `issuerName` String - Issuer's Common Name -* `callback` Function - -クライアント証明書が要求されたときに出力されます。 - -`url` は、クライアント証明書を要求するナビゲーションエントリーに対応し、`callback` リストからエントリをフィルターしてコールするのに必要です。`event.preventDefault()` を使用して、アプリケーションの証明書ストアから最初の証明書を使用するのを止めることができます。 - -```javascript -app.on('select-client-certificate', function(event, webContents, url, list, callback) { - event.preventDefault(); - callback(list[0]); -}) -``` - -### イベント: 'login' - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `request` Object - * `method` String - * `url` URL - * `referrer` URL -* `authInfo` Object - * `isProxy` Boolean - * `scheme` String - * `host` String - * `port` Integer - * `realm` String -* `callback` Function - -`webContents` がベーシック認証をしようとしたときに出力されます。 - -既定の動作ではすべての認証をキャンセルしたり、`event.preventDefault()` と `callback(username, password)` とを証明書でコールし既定の動作をとめてオーバーライドします。 - -```javascript -app.on('login', function(event, webContents, request, authInfo, callback) { - event.preventDefault(); - callback('username', 'secret'); -}) -``` - -### イベント: 'gpu-process-crashed' - -gpu プロセスがクラッシュしたときに出力されます。 - -## メソッド - -`app` オブジェクトは次のメソッドを持ちます。 - -**Note:** いくつかのメソッドは、特定のオペレーティングシステム向けに提供され、そのようにラベルで表示します。 - -### `app.quit()` - -全てのウィンドウを閉じようとします。`before-quit`イベントは、最初に出力されます。すべてのウィンドウを閉じることに成功したら、`will-quit`イベントが出力され、既定では、アプリケーションが終了します。 - -このメソッドは、全ての`beforeunload`と`unload`イベントハンドラは正確に発生することを保証されます。`beforeunload` イベントハンドラで、`false`を返すことでウィンドウの終了をキャンセルすることができます。 - -### `app.exit(exitCode)` - -* `exitCode` Integer - -`exitCode`で今すぐ終了します。 - -全てのウィンドウは、ユーザーに確認することなく、すぐに閉じ、`before-quit`と`will-quit` イベントは出力されません。 - -### `app.getAppPath()` - -減殺のアプリケーションディレクトリを戻します。 - -### `app.getPath(name)` - -* `name` String - -`name`に関連した特定のディレクトリやファイルへのパスを返します。失敗したら、`Error`をスローします。 - -`name`で次のパスをリクエストできます。 - -* `home` ユーザーのホームディレクトリ -* `appData` 既定で示すユーザーごとのアプリケーションディレクトリ - * `%APPDATA%` Windows上 - * `$XDG_CONFIG_HOME` or `~/.config` Linux上 - * `~/Library/Application Support` macOS上 -* `userData` アプリの設定ファイルを格納するディレクトリで、既定では`appData` ディレクトリ配下のアプリ名ディレクトリです -* `temp` 一時ディレクトリ -* `exe` 現在の実行ファイル -* `module` `libchromiumcontent` ライブラリ -* `desktop` 現在のユーザーのデスクトップディレクトリ -* `documents` ユーザーの "My Documents"用ディレクトリ -* `downloads` ユーザーのダウンロード用ディレクトリ -* `music` ユーザーのミュージック用ディレクトリ -* `pictures` ユーザーのピクチャー用ディレクトリ -* `videos` ユーザーのビデオ用ディレクトリ - -### `app.setPath(name, path)` - -* `name` String -* `path` String - -`name`に関連した特定のディレクトリやファイルへの`path` を上書きします。存在しないパスを指定した場合、このメソッドがディレクトリを作成します。失敗したら、`Error`をスローします。 - -`app.getPath`で、`name` で定義されたパスを上書きできます。 - -既定では、webページのクッキーとキャッシュは`userData`ディレクトリ配下に格納できます。ロケーションを変更したい場合、 `app` モジュールの `ready` イベントが出力される前に`userData`パスを上書きする必要があります。 - -### `app.getVersion()` - -ロードしたアプリケーションのバージョンを戻します。アプリケーションの `package.json`ファイルにversionが無ければ、現在のバンドルまたは実行ファイルのバージョンになります。 - -### `app.getName()` - -現在のアプリケーション名を戻し、`package.json` ファイルのnameです。 - -通常、 `package.json`の`name` フィールドは、短い小文字名で、npm module spec と一致します。通常、`productName`で、アプリケーションの大文字正式名を指定し、Electronでは`name`をそれで上書きます。 - -### `app.getLocale()` - -現在のアプリケーションのロケールを戻します。 - -### `app.addRecentDocument(path)` _macOS_ _Windows_ - -* `path` String - -最近のドキュメント一覧に`path`を追加します。 - -この一覧はOSが管理しています。Windowsではタスクバーからこの一覧を見れ、macOSではdockメニューから見れます。 - -### `app.clearRecentDocuments()` _macOS_ _Windows_ - -最近のドキュメント一覧をクリアします。 - -### `app.setUserTasks(tasks)` _Windows_ - -* `tasks` Array - `Task` オブジェクトの配列 - -Windowsのジャンプリストの[Tasks][tasks]カテゴリに`tasks`を追加します。 - -`tasks` は`Task`オブジェクトの配列で、次のフォーマットになります。 - -`Task` Object: - -* `program` String - 実行するプログラムのパスで、通常はプログラムが開く`process.execPath`を指定します -* `arguments` String - `program` を実行するときのコマンドライン引数です -* `title` String - ジャンプリストに表示される文字列です -* `description` String - タスクの説明 -* `iconPath` String - ジャンプリストに表示するアイコンの絶対パスで、アイコンを含む任意のリソースファイルです。通常、プログラムのアイコンを表示する`process.execPath`を指定します。 -* `iconIndex` Integer - アイコンファイルのアイコンインデックスです。アイコンファイルに2つ以上のアイコンが含まれている場合、この値でアイコンを指定します。1つしかアイコンファイルに含まれていない場合は、この値は0です。 - -### `app.allowNTLMCredentialsForAllDomains(allow)` - -* `allow` Boolean - -HTTP NTLMまたはNegotiate認証用の照明を常に送信するかどうかを動的に設定できます。通常、Electronはローカルインターネットサイト(例えば、あなたと同じドメイン名のとき)に該当するURL用のNTLM/Kerberos証明書のみ送信します。しかし、この検知はコーポレートネットワークの設定が悪いときには、頻繁に失敗するので、この挙動を共通に行うことを選べば、全てのURLで有効にできます。 - -### `app.makeSingleInstance(callback)` - -* `callback` Function - -このメソッドは、アプリケーションをシングルインスタンスアプリケーションにします。アプリの実行を複数のインスタンスで実行することを許可せず、アプリケーション実行をシングルインスタンスのみにすることを保証し、ほかのインスタンスにはこのインスタンスの存在を知らせ終了さえます。 - -2つ目のインスタンスが起動したとき、`callback` は、`callback(argv, workingDirectory)` でコールします。`argv` は、2つ目のインスタンスのコマンドライン引数の配列で、`workingDirectory` は現在のワーキングディレクトリです。通常、アプリケーションはメインのウィンドウにフォーカスをあて最小化させないことで対応します。 - -The `callback` は、 `app`の`ready` イベントの出力後に実行することを保証します。 - -プロセスがアプリケーションのプライマリインスタンスでアプリがロードし続けるなら、このメソッドは `false`を戻します。プロセスがほかのインスタンスにパラメーターを送信し、`true`を戻すと、直ちに終了します。 - -macOSは、ユーザーがFinderで2つ目のアプリインスタンスを開いたり、`open-file` 、 `open-url`イベントが出力しようとすると、システムが自動的にシングルインスタンスを強制します。しかし、コマンドラインでアプリを開始するとシステムのシングルインスタンスメカニズムは無視されるので、シングルインスタンスを強制するためには、このメソッドを使う必要があります。 - -2つ目のインスタンスを起動するとき、メインのインスタンスのウィンドウをアクティブにする例 - -```js -var myWindow = null; - -var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { - // Someone tried to run a second instance, we should focus our window - if (myWindow) { - if (myWindow.isMinimized()) myWindow.restore(); - myWindow.focus(); - } - return true; -}); - -if (shouldQuit) { - app.quit(); - return; -} - -// Create myWindow, load the rest of the app, etc... -app.on('ready', function() { -}); -``` - -### `app.setAppUserModelId(id)` _Windows_ - -* `id` String - -[Application User Model ID][app-user-model-id] を `id`に変更します。 - -### `app.isAeroGlassEnabled()` _Windows_ - -[DWM composition](https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx)(Aero Glass) が有効なら、このメソッドは`true`を戻し、有効でなければ`false`を戻します。透明なウィンドウを作成する必要があるか、またはできないとき(DWM compositionが無効なとき用明なウィンドウは正しく動作しません)、このAPIを使うことができます。 - -使用例: - -```js -let browserOptions = {width: 1000, height: 800}; - -// Make the window transparent only if the platform supports it. -if (process.platform !== 'win32' || app.isAeroGlassEnabled()) { - browserOptions.transparent = true; - browserOptions.frame = false; -} - -// Create the window. -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'); -} -``` - -### `app.commandLine.appendSwitch(switch[, value])` - -Chromiumのコマンドラインにスイッチ( `value`をオプションにし)を追加します。 - -**Note:** これは、`process.argv`に影響せず、開発者が、Chromiumのローレベルな挙動をコントロールするのに使用します。 - -### `app.commandLine.appendArgument(value)` - -Chromiumのコマンドダインに引数を追加します。引数は正しく引用符で囲まれます。 - -**Note:** `process.argv`に影響しません。 - -### `app.dock.bounce([type])` _macOS_ - -* `type` String (optional) - `critical` または `informational`を指定できます。既定では、 `informational`です。 - -`critical`を渡すと、アプリケーションがアクティブ、もしくはリクエストがキャンセルされるまでは、dockアイコンは、バウンスします。 - -`informational` を渡すと、1秒dockアイコンはバウンスします。しかし、アプリケーションがアクティブ、もしくはリクエストがキャンセルされるまでは、リクエストは残ります。 - -リクエストを示すIDを戻します。 - -### `app.dock.cancelBounce(id)` _macOS_ - -* `id` Integer - -`id`のバウンスをキャンセルします。 - -### `app.dock.setBadge(text)` _macOS_ - -* `text` String - -dockのバッジエリアで表示する文字列を設定します。 - -### `app.dock.getBadge()` _macOS_ - -dockのバッジ文字列を戻します。 - -### `app.dock.hide()` _macOS_ - -dock アイコンを隠します。 - -### `app.dock.show()` _macOS_ - -dock アイコンを表示します。 - -### `app.dock.setMenu(menu)` _macOS_ - -* `menu` Menu - -アプリケーションの[dock menu][dock-menu]を設定します。 - -### `app.dock.setIcon(image)` _macOS_ - -* `image` [NativeImage](native-image.md) - -dock アイコンに紐づいた`image`を設定します。 - -[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 -[tasks]:http://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 diff --git a/docs-translations/jp/api/auto-updater.md b/docs-translations/jp/api/auto-updater.md deleted file mode 100644 index 92f1fce21971e..0000000000000 --- a/docs-translations/jp/api/auto-updater.md +++ /dev/null @@ -1,85 +0,0 @@ -# autoUpdater - -このモジュールは、`Squirrel`オートアップデートフレームワークのインターフェイスを提供します。 - -## プラットフォーム留意点 - -`autoUpdater`は、異なるプラットフォーム用に統一したAPIを提供していますが、それぞれのプラットフォーム上で、まだ多少の差があります。 - -### macOS - -macOSでは、 `autoUpdater` モジュールは、[Squirrel.Mac][squirrel-mac]上に構築されていて、動作させるのに特別な設定が不要であることを意味します。サーバーサイドの要件は、[Server Support][server-support]を読んでください。 - -### Windows - -Windowsでは、auto-updaterを使う前に、ユーザーのPCにアプリをインストールする必要があるので、Windows インストーラーを生成するために[grunt-electron-installer][installer]モジュールを使用することをお勧めします。 - -Squirrelで生成されたインストーラーは、`com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`のフォーマット(例えば、`com.squirrel.slack.Slack` と `com.squirrel.code.Code`)で[Application User Model ID][app-user-model-id]とショートカットアイコンを作成します。`app.setAppUserModelId`APIで同じIDを使う必要があります。同じIDでないと、Windowsはタスクバーに適切にピン止めすることができません。 - -サーバーサイドのセットアップは、macOSと異なります。詳細は、[Squirrel.Windows][squirrel-windows] を参照してください。 - -### Linux - -Linuxでは、auot-updater用のサポートがビルトインされていないので、アプリをアップデートするためにディストリビューションのパッケージマネジャーを使用することをお勧めします。 - -## イベント - -`autoUpdater` オブジェクトは次のイベントを出力します。 - -### イベント: 'error' - -戻り値: - -* `error` Error - -アップデート中にエラーがあった場合に出力されます。 - -### イベント: 'checking-for-update' - -アップデートを開始したかチェックしたときに出力されます。 - -### イベント: 'update-available' - -アップデートが提供されているときに出力されます。アップデートは自動的にダウンロードされます。 - -### イベント: 'update-not-available' - -アップデートが提供されていないときに出力されます。 - -### イベント: 'update-downloaded' - -戻り値: - -* `event` Event -* `releaseNotes` String -* `releaseName` String -* `releaseDate` Date -* `updateURL` String - -アップデートをダウンロードしたときに出力されます。 - -Windowsでは、`releaseName` のみ提供されます。 - -## メソッド - -`autoUpdater` オブジェクトは次のメソッドを持っています。 - -### `autoUpdater.setFeedURL(url)` - -* `url` String - - `url`を設定し、自動アップデートを初期化します。 `url`は一度設定すると変更できません。 - -### `autoUpdater.checkForUpdates()` - -アップデートがあるかどうかサーバーに問い合わせます。APIを使う前に、`setFeedURL`をコールしなければなりません。 - -### `autoUpdater.quitAndInstall()` - -ダウンロード後、アプリを再起動して、アップデートをインストールします。`update-downloaded`が出力された後のみ、コールすべきです。 - -[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/atom/grunt-electron-installer -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx diff --git a/docs-translations/jp/api/chrome-command-line-switches.md b/docs-translations/jp/api/chrome-command-line-switches.md deleted file mode 100644 index b041cf3baffb4..0000000000000 --- a/docs-translations/jp/api/chrome-command-line-switches.md +++ /dev/null @@ -1,137 +0,0 @@ -#サポートしているChromeコマンドラインスイッチ - -> Electronでサポートされているコマンドラインスイッチ - -アプリケーションのメインスクリプトで[app.commandLine.appendSwitch][append-switch]を使うことで、[app][app]モジュールの[ready][ready]イベントが発行される前にコマンドラインスイッチを追加できます。 - -```javascript -const {app} = require('electron'); -app.commandLine.appendSwitch('remote-debugging-port', '8315'); -app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1'); - -app.on('ready', () => { - // Your code here -}); -``` - - -## --ignore-connections-limit=`domains` - -`domains`で指定されたリストは接続数制限を無視します。リストは`,`で区切られます。 - -## --disable-http-cache - -HTTPリクエストのディスクキャッシュの無効化。 - -## --disable-http2 - -HTTP/2 と SPDY/3.1 プロトコルを無効にします。 - -## --remote-debugging-port=`port` - -`port`で指定したHTTP越しのリモートデバッグの有効化。 - -## --js-flags=`flags` - -JSエンジンに渡されるフラグの指定。メインプロセスで`flags`を有効化したいのなら、Electron開始時に渡される必要があります。 - -```bash -$ electron --js-flags="--harmony_proxies --harmony_collections" your-app -``` - -## --proxy-server=`address:port` - -システム設定を上書きし、指定したプロキシサーバーを使用します。HTTPS、WebSocketリクエストを含むHTTPプロトコルのリクエストのみに影響します。全てのプロキシサーバーがHTTPSとWebSocketリクエストに対応しているわけではないことに注意してください。 - -## --proxy-bypass-list=`hosts` - -プロキシを使用しないサーバーをセミコロンで区切って指定します。 -このフラグは、`--proxy-server`と同時に使われるときのみに影響します。 - -例: - -```javascript -app.commandLine.appendSwitch('proxy-bypass-list', ';*.google.com;*foo.com;1.2.3.4:5678') -``` - -ローカルアドレス(`localhost`や`127.0.0.1`など)、`google.com`サブドメイン、`foo.com` サフィックスを含むホスト、`1.2.3.4:5678`を除いてすべてのホストでプロキシサーバーが使われます。 - -## --proxy-pac-url=`url` - -`url`で指定したPACスクリプトが使われます。 - -## --no-proxy-server - -プロキシサーバーを使わず、常に直接接続します。ほかのプロキシサーバーフラグを上書きします。 - -## --host-rules=`rules` - -ホスト名がどのようにマップされているかを制御するコンマで分割された`rules`一覧 - -例: - -* `MAP * 127.0.0.1` 全てのホスト名を127.0.0.1にマッピングするよう強制します。 -* `MAP *.google.com proxy` すべてのgoogle.comサブドメインを "proxy"で解決するよう強制します。 -* `MAP test.com [::1]:77` "test.com"をIPv6ループバックで解決するよう強制します。結果ポートのをソケットアドレス77番にするよう強制します。 -* `MAP * baz, EXCLUDE www.google.com` 全てを"baz"に再マッピングし、 "www.google.com"は除外します。 - -これらのマッピングは、ネットリクエスト(直接接続で、TCP接続とホスト解決とHTTPプロキシ接続での`CONNECT`、`SOCKS`プロキシ接続でのエンドポイントホスト)でエンドポイントホストに適用されます。 - -## --host-resolver-rules=`rules` - -`--host-rules`のようですが、`rules` はホスト解決のみに適用されます。 - -## --ignore-certificate-errors - -証明書関連エラーを無視します。 - -## --ppapi-flash-path=`path` - -pepper flash pluginの`path`を設定します。 - -## --ppapi-flash-version=`version` - -pepper flash pluginの`version`を設定します。 - -## --log-net-log=`path` - -ネットログイベントを保存し、`path`に書き込みを有効化します。 - -## --ssl-version-fallback-min=`version` - -TLSフォールバックを許可する最小のSSL/TLSバージョン ("tls1"や"tls1.1" 、 "tls1.2")を設定します。 - -## --cipher-suite-blacklist=`cipher_suites` - -無効にするために、SSL暗号スイートのカンマ区切りのリストを指定します。 - -## --disable-renderer-backgrounding - -不可視のページのレンダラープロセスの優先度を下げることからChromiumを防ぎます。 - -このフラグは、グローバルですべてのレンダラープロセスに有効で、一つのウィンドウだけで無効化したい場合、[無音を再生する][play-silent-audio]というハックで対応します。 - -## --enable-logging - -コンソールにChromiumのログを出力します。 - -ユーザーのアプリが読み込まれる前に解析されるため、`app.commandLine.appendSwitch`では使用できませんが、`ELECTRON_ENABLE_LOGGING`を環境変数に設定すると同じ効果を得ることができます。 - -## --v=`log_level` - -標準のloggingレベルを設定します。0が既定です。通常、V-loggingレベルには正の値が使用されます。 - -`--enable-logging` が渡された時だけ、このスイッチは動作します。 - -## --vmodule=`pattern` - -`--v`で付与された値を上書きするために、モジュール毎の最大V-loggingレベルを付与します。例えば、 `my_module=2,foo*=3` は、`my_module.*` と `foo*.*`のソースファイル全てのロギングレベルを変更します。 - -前方または後方スラッシュを含む任意のパターンは、全体のパス名だけでなく、モジュールに対してもテストとされます。例えば、`*/foo/bar/*=2`は`foo/bar`ディレクトリ下のソースファイルですべてのコードのロギングレベルを変更します。 - -このスイッチは、`--enable-logging`が渡された時のみ動作します。 - -[app]: app.md -[append-switch]: app.md#appcommandlineappendswitchswitch-value -[ready]: app.md#event-ready -[play-silent-audio]: https://github.com/atom/atom/pull/9485/files diff --git a/docs-translations/jp/api/clipboard.md b/docs-translations/jp/api/clipboard.md deleted file mode 100644 index 88a7fe4c1b4f2..0000000000000 --- a/docs-translations/jp/api/clipboard.md +++ /dev/null @@ -1,103 +0,0 @@ -# clipboard - -`clipboard`モジュールは、コピーとペースト操作を実行するメソッドを提供します。次の例は、クリップボードに文字列を書き込む方法を示しています: - -```javascript -const clipboard = require('electron').clipboard; -clipboard.writeText('Example String'); -``` - -X Windowsシステム上では、セレクションクリップボードがあります。それを操作するために、それぞれのメソッドで、`selection`を通す必要があります。 - -```javascript -clipboard.writeText('Example String', 'selection'); -console.log(clipboard.readText('selection')); -``` - -## メソッド - -`clipboard`モジュールには、次のメソッドがあります: - -**Note:** 実験的APIには、そのようにマークしてあり、将来的には削除される可能性があります。 - -### `clipboard.readText([type])` - -* `type` String (optional) - -プレーンテキストとしてクリップボードの内容を返します。 - -### `clipboard.writeText(text[, type])` - -* `text` String -* `type` String (optional) - -プレーンテキストとしてクリップボードに`text`を書き込みます。 - -### `clipboard.readHTML([type])` - -* `type` String (optional) - -HTMLマークアップとして、クリップボードの内容を返します。 - -### `clipboard.writeHTML(markup[, type])` - -* `markup` String -* `type` String (optional) - -クリップボードにHTMLマークアップとして書き込みます。 - -### `clipboard.readImage([type])` - -* `type` String (optional) - -[NativeImage](native-image.md)としてクリップボードの内容を返します。 - -### `clipboard.writeImage(image[, type])` - -* `image` [NativeImage](native-image.md) -* `type` String (optional) - -`image` としてクリップボードに書き込みます。 - -### `clipboard.clear([type])` - -* `type` String (optional) - -クリップボードの内容をクリアします。 - -### `clipboard.availableFormats([type])` - -* `type` String (optional) - -`type`のクリップボードがサポートしているフォーマット配列を返します。 - -### `clipboard.has(data[, type])` _実験_ - -* `data` String -* `type` String (optional) - -`data`で指定したフォーマットをクリップボードがサポートしているかどうかを返します。 - -```javascript -console.log(clipboard.has('

selection

')); -``` - -### `clipboard.read(data[, type])` _実験_ - -* `data` String -* `type` String (optional) - -クリップボードから`data`を読み込みます。 - -### `clipboard.write(data[, type])` - -* `data` Object - * `text` String - * `html` String - * `image` [NativeImage](native-image.md) -* `type` String (optional) - -```javascript -clipboard.write({text: 'test', html: "test"}); -``` -クリップボードに`data`を書き込みます。 diff --git a/docs-translations/jp/api/content-tracing.md b/docs-translations/jp/api/content-tracing.md deleted file mode 100644 index f7142a5001b7c..0000000000000 --- a/docs-translations/jp/api/content-tracing.md +++ /dev/null @@ -1,129 +0,0 @@ -# contentTracing - -`content-tracing`モジュールは、Chromiumコンテンツモジュールによって生成されるトーレスデータを収集するのに使われます。このモジュールはウェブインターフェイスを含んでいないので、Chromeブラウザーで `chrome://tracing/`を開いて、結果を表示するために生成されたファイルを読み込む必要があります。 - -```javascript -const contentTracing = require('electron').contentTracing; - -const options = { - categoryFilter: '*', - traceOptions: 'record-until-full,enable-sampling' -} - -contentTracing.startRecording(options, function() { - console.log('Tracing started'); - - setTimeout(function() { - contentTracing.stopRecording('', function(path) { - console.log('Tracing data recorded to ' + path); - }); - }, 5000); -}); -``` - -## メソッド - -`content-tracing`モジュールは次のメソッドを持っています。 - -### `contentTracing.getCategories(callback)` - -* `callback` Function - -カテゴリグループ一式を取得します。新しいコードパスに到達しているとしてカテゴリグループを変更できます。 - -一度、全ての子プロセスが`getCategories`リクエストを認識すると、カテゴリグループの配列で`callback`が呼び出されます。 - -### `contentTracing.startRecording(options, callback)` - -* `options` Object - * `categoryFilter` String - * `traceOptions` String -* `callback` Function - -全てのプロセスで記録を開始します。 - -EnableRecordingリクエストを受信するとすぐに、子プロセス上でただちに非同期にローカルに記録を始めます。全ての子プロセスが`startRecording`リクエストを認識すると、`callback`が呼び出されます。 - -`categoryFilter`はどのカテゴリグループをトレースすべきかをフィルタリングします。フィルターは、マッチしたカテゴリーを含むカテゴリグループを除外する`-`プレフィックスをオプションうぃ持っています。同じリストでの、対象カテゴリパターンと、除外カテゴリーパターンの両方を持つことはサポートしていません。 - -例: - -* `test_MyTest*`, -* `test_MyTest*,test_OtherStuff`, -* `"-excluded_category1,-excluded_category2` - -`traceOptions` は、どの種類のトレースを有効にするかを制御し、コンマ区切りのリストです。 - -取りうるオプション: - -* `record-until-full` -* `record-continuously` -* `trace-to-console` -* `enable-sampling` -* `enable-systrace` - -最初の3つのオプションは、トレースの記録モードで、そのため相互排他的です。`traceOptions`文字列に1つ以上のトレース記録モードが現れると、最後のモードが優先されます。トレース記録モードが指定されていない場合、記録モードは、`record-until-full`です。 - -適用される`traceOptions`からオプションをパースする前に、トレースオプションは最初に既定のオプションにリセットされます(`record_mode`は、`record-until-full`を設定し、 `enable_sampling`と `enable_systrace` は `false`に設定します)。 - -### `contentTracing.stopRecording(resultFilePath, callback)` - -* `resultFilePath` String -* `callback` Function - -全てのプロセスで記録を止めます。 - -子プロセスは基本的にトレースデータをキャッシュし、まれにフラッシュし、メインプロセスにトレースデータを送り返します。IPC越しにトレースデータを送信するのは高コストな操作なので、トレースのランタイムオーバーヘッドを最小限にするのに役立ちます。トレースが終了すると、保留されているトレースデータのフラッシュをするためにすべての子プロセスに非道に問い合わせすべきです。 - - -一度、すべての子プロセスが`stopRecording` リクエストを認識すると、トレースデータを含んだファイルで`callback`が呼び出されます。 - -トレースデータは`resultFilePath`が空でなければ、そこに書き込まれ、空の場合は一時ファイルに書き込まれます。実際のファイルパスは`null`でなければ `callback` に通します。 - -### `contentTracing.startMonitoring(options, callback)` - -* `options` Object - * `categoryFilter` String - * `traceOptions` String -* `callback` Function - -全てのプロセス上で監視を開始します。 - -`startMonitoring`リクエスト受信するとすぐに、子プロセス上でローカルに非同期にただちに監視を始めます。 - -全ての子プロセスが`startMonitoring`リクエストを認識すると、`callback`がコールされます。 - -### `contentTracing.stopMonitoring(callback)` - -* `callback` Function - -全てのプロセス上で監視を止めます。 - -全ての子プロセスが`stopMonitoring`リクエスト認識すると、`callback`がコールされます。 - -### `contentTracing.captureMonitoringSnapshot(resultFilePath, callback)` - -* `resultFilePath` String -* `callback` Function - -現在の監視トレースデータを取得します。子プロセスは基本的にトレースデータをキャッシュし、まれにフラッシュし、メインプロセスにトレースデータを送り返します。IPC越しにトレースデータを送信するのは高コストな操作なので、トレースによる不必要なランタイムオーバーヘッドを避けるます。トレースが終了するために、保留されているトレースデータのフラッシュをするためにすべての子プロセスに非道に問い合わせすべきです。 - -全ての子プロセスが`captureMonitoringSnapshot`リクエストを認識すると、トレースデータを含んだファイルで`callback`が呼び出されます。 - -### `contentTracing.getTraceBufferUsage(callback)` - -* `callback` Function - -プロセスのトレースバッファのプロセス間で最大使用量をフルの状態の何%かで取得します。TraceBufferUsage値が設定されていると、 `callback`がコールされます。 - -### `contentTracing.setWatchEvent(categoryName, eventName, callback)` - -* `categoryName` String -* `eventName` String -* `callback` Function - -プロセス上でイベント発生すると、その度に`callback`がコールされます。 - -### `contentTracing.cancelWatchEvent()` - -イベントウオッチをキャンセルします。トレースが有効になっていると、監視イベントのコールバックとの競合状態になる可能性があります。 diff --git a/docs-translations/jp/api/crash-reporter.md b/docs-translations/jp/api/crash-reporter.md deleted file mode 100644 index a1fb21f511122..0000000000000 --- a/docs-translations/jp/api/crash-reporter.md +++ /dev/null @@ -1,66 +0,0 @@ -# crashReporter - -`crash-reporter`モジュールはアプリのクラッシュレポートを送信することができます。 - -リモートサーバーに自動的にクラッシュレポートを登録する例です。 - -```javascript -const crashReporter = require('electron').crashReporter; - -crashReporter.start({ - productName: 'YourName', - companyName: 'YourCompany', - submitURL: 'https://your-domain.com/url-to-submit', - autoSubmit: true -}); -``` - -## メソッド - -`crash-reporter`モジュールは次のメソッドを持ちます: - -### `crashReporter.start(options)` - -`options` Object, properties: - -* `productName` String, デフォルト: Electron. -* `companyName` String (**必須**) -* `submitURL` String, (**必須**) - * クラッシュレポートがPOSTで送信されるURL -* `autoSubmit` Boolean, デフォルト: `true`. - * ユーザーの判断なくクラッシュレポートを送信します -* `ignoreSystemCrashHandler` Boolean, デフォルト: `false`. -* `extra` Object - * あなたが定義できるオブジェクトは、レポートと一緒に送信されます。 - * 文字列プロパティのみが正しく送信されます。 - * オブジェクトのネストはサポートしていません。 - -他の`crashReporter`APIを使用する前にこのメソッドをコールする必要があります。 - -**Note:** macOSでは、Electronは、WindowsとLinux上の`breakpad` とは異なる、新しい`crashpad`クライアントを使用します。クラッシュ収集機能を有効にするために、メインプロセスや、クラッシュレポートを収集したいそれぞれのレンダラープロセスで、`crashpad`を初期化するために`crashReporter.start`APIをコールする必要があります。 - -### `crashReporter.getLastCrashReport()` - -日付と最後のクラッシュレポートのIDを返します。もしなんのクラッシュレポートも送信されていないか、クラッシュレポーターが起動していない場合、`null`を返します。 - -### `crashReporter.getUploadedReports()` - -滑ってのアップロードされたクラッシュレポートが返されます。それぞれのレポートには日付とアップロードされたIDが含まれます。 - -## crash-reporter Payload - -クラッシュレポーターは`POST`で`submitURL` に次のデーターが送信されます。 - -* `ver` String - Electronのバージョン -* `platform` String - 例: 'win32'. -* `process_type` String - 例: 'renderer'. -* `guid` String - 例: '5e1286fc-da97-479e-918b-6bfb0c3d1c72' -* `_version` String - `package.json`でのバージョン -* `_productName` String - `crashReporter`でのプロダクト名 `オプション` - object. -* `prod` String - 基盤となる製品の名前。この場合は、Electronです。 -* `_companyName` String - `crashReporter`での会社名 `オプション` - object. -* `upload_file_minidump` File - ファイル形式のクラッシュレポート -* `crashReporter`での`extra`オブジェクトのすべてのレベル1のプロパティ - `オプション` object diff --git a/docs-translations/jp/api/desktop-capturer.md b/docs-translations/jp/api/desktop-capturer.md deleted file mode 100644 index c057ece4e529d..0000000000000 --- a/docs-translations/jp/api/desktop-capturer.md +++ /dev/null @@ -1,65 +0,0 @@ -# desktopCapturer - -`desktopCapturer`モジュールは`getUserMedia`でキャプチャーするのに使える利用可能なソースを取得するのに使われます。 - -```javascript -// In the renderer process. -var desktopCapturer = require('electron').desktopCapturer; - -desktopCapturer.getSources({types: ['window', 'screen']}, function(error, sources) { - if (error) throw error; - for (var i = 0; i < sources.length; ++i) { - if (sources[i].name == "Electron") { - navigator.webkitGetUserMedia({ - audio: false, - video: { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: sources[i].id, - minWidth: 1280, - maxWidth: 1280, - minHeight: 720, - maxHeight: 720 - } - } - }, gotStream, getUserMediaError); - return; - } - } -}); - -function gotStream(stream) { - document.querySelector('video').src = URL.createObjectURL(stream); -} - -function getUserMediaError(e) { - console.log('getUserMediaError'); -} -``` - -`navigator.webkitGetUserMedia`用の制限されたオブジェクトコールを作成し、`desktopCapturer`からソースを使用するのなら、`chromeMediaSource`は`"desktop"`を設定し、`audio`は`false`を設定しなければなりません。 - -全てのデスクトップから音とビデオをキャプチャーしたいなら、`chromeMediaSource``"screen"`、`audio` に `true`.を設定します。このメソッドを使うとき、`chromeMediaSourceId`は指定できません。 - -## メソッド - -`desktopCapturer`モジュールは次のメソッドを持ちます。 - -### `desktopCapturer.getSources(options, callback)` - -* `options` Object - * `types` Array - キャプチャーされるデスクトップソースの種類一覧の文字列配列で、 提供される種類は`screen` と `window`です。 - * `thumbnailSize` Object (オプション) - サムネイルがスケールすべきサイズの指定で、既定では`{width: 150, height: 150}` です。 -* `callback` Function - -全てのデスクトップソールを取得するためのリクエストを開始し、リクエストが完了すると、`callback`は`callback(error, sources)` でコールされます。 - -`sources`は、`Source`オブジェクトの配列で、それぞれの`Source`はキャプチャーしたスクリーンか、1つのウィンドウを示し、次のプロパティを持ちます。 - - -* `id` String - The id of the captured window or screen used in - `navigator.webkitGetUserMedia`で使われるキャプチャーしたウィンドウか画面のidです。`window:XX` か`screen:XX`のようなフォーマットで、`XX`はランダムに生成された数字です。 -* `name` String - キャプチャーする画面かウィンドウの説明名ソースが画面なら名前は`Entire Screen`で、`Screen `はウィンドウで、名前はウィンドウのタイトルです。 -* `thumbnail` [NativeImage](NativeImage.md) - サムネイル画像 - -**Note:** `source.thumbnail`のサイズはいつも`options`の`thumnbailSize`と同じ保証はありません。画面またはウィンドウのサイズに依存します。 diff --git a/docs-translations/jp/api/dialog.md b/docs-translations/jp/api/dialog.md deleted file mode 100644 index 48a17225bb580..0000000000000 --- a/docs-translations/jp/api/dialog.md +++ /dev/null @@ -1,88 +0,0 @@ -# dialog - -`dialog`モジュールは、ファイルやアラートを開くようなネイティブシステムダイアログを表示するためのAPIを提供します。そのため、ネイティブアプリケーションのようにウェブアプリケーションに同じユーザー体験を提供できます。 - -複数のファイルやディレクトリを選択するためのダイアログを表示する例です: - -```javascript -var win = ...; // BrowserWindow in which to show the dialog -const dialog = require('electron').dialog; -console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', 'multiSelections' ]})); -``` - -**Note for macOS**: シートとしてダイアログを表示したい場合、唯一しなければならないことは、`browserWindow`パラメーターを参照する`BrowserWindow`を提供することです。 - -## メソッド - -`dialog`モジュールは次のメソッドを持っています: - -### `dialog.showOpenDialog([browserWindow, ]options[, callback])` - -* `browserWindow` BrowserWindow (オプション) -* `options` Object - * `title` String - * `defaultPath` String - * `filters` Array - * `properties` Array - ダイアログが使うべき機能を含め、`openFile`と`openDirectory`、`multiSelections`、`createDirectory`を含められます。 -* `callback` Function (オプション) - -成功したら、このメソッドはユーザーが選択したファイルパスの配列を返し、さうでなければ`undefined`を返します。 - -ユーザーが選択できる種類を制限したいときに、`filters`で表示したり選択できるファイル種別の配列を指定します。 - -```javascript -{ - filters: [ - { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, - { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] }, - { name: 'Custom File Type', extensions: ['as'] }, - { name: 'All Files', extensions: ['*'] } - ] -} -``` - -`extensions`配列は、ワイルドカードやドットなしで拡張子を指定すべきです(例えば、`'png'`は良いですが、`'.png'` と `'*.png'`はダメです)。すべてのファイルを表示するために、`'*'`ワイルドカードを使用します(それいがいのワイルドカードはサポートしていません)。 - -`callback`を通すと、APIは非同期に読み出し、結果は`callback(filenames)`経由で通します。 - -**Note:** WindowsとLinuxでは、オープンダイアログがファイル選択とディレクトリ選択の両方を選択することはできません。プラットフォーム上で `properties`に`['openFile', 'openDirectory']`を設定すると、ディレクトリ選択が表示されます。 - -### `dialog.showSaveDialog([browserWindow, ]options[, callback])` - -* `browserWindow` BrowserWindow (オプション) -* `options` Object - * `title` String - * `defaultPath` String - * `filters` Array -* `callback` Function (オプション) - -成功すると、このメソッドはユーザーが選択したファイルのパスが返され、そうでなければ`undefined`が返されます。 - -`filters`が表示できるファイル種別配列を指定します。例えば、`dialog.showOpenDialog`を参照してください。 - -`callback`を通すと、APIは非同期でコールされ、結果は`callback(filename)`経由で通します。 - -### `dialog.showMessageBox([browserWindow, ]options[, callback])` - -* `browserWindow` BrowserWindow (オプション) -* `options` Object - * `type` String - `"none"`と `"info"`、 `"error"`、 `"question"`、`"warning"`を設定できます。Windowsでは、 "icon"オプションを使用してアイコンを設定しない限り、"question"は"info"として同じアイコンを表示します。 - * `buttons` Array - ボタン用のテキスト配列。 - * `defaultId` Integer - メッセージボックスを開くとき、既定で選択されるボタン配列でのボタンインデックスです - * `title` String - メッセージボックスのタイトルで、いくつかのプラットフォームでは表示されません。 - * `message` String - メッセージボックスのコンテンツ。 - * `detail` String - メッセージの外部情報 - * `icon` [NativeImage](native-image.md) - * `cancelId` Integer - ダイアログのボタンをクリックする代わりにユーザーがダイアログをキャンセルしたときに返す値です。既定では、ラベルの "cancel"や"no"を持つボタンのインデックスまたは、そのようなボタンが無ければ0を返します。macOSやWindowsでは、 すでに指定されているかどうかは関係なく、"Cancel"ボタンのインデックスはいつでも `cancelId`が使われます。 - * `noLink` Boolean - Windowsでは、Electronは、 ("Cancel" または "Yes"のような)共通ボタンである`buttons`の一つを見つけようとし、ダイアログ内のコマンドリンクとして表示します。この挙動が気に入らない場合は、 `noLink` を `true`に設定できます。 -* `callback` Function - -メッセージボックスを表示し、メッセージボックスが閉じるまでプロセスをブロックします。クリックされたボタンのインデックスを返します。 - -`callback`が通されると、APIは非同期にコールし、結果は`callback(response)`経由で通されます。 - -### `dialog.showErrorBox(title, content)` - -エラーメッセージを表示するモデルダイアログを表示します。 - - `app`モジュールが`ready`イベントを出力する前に、このAPIは安全にコールできます。スタートアップの早い段階でエラーを報告するのに通常は使われます。Linuxで、アプリの`ready`イベントの前にコールすると、メッセージは標準エラーに出力され、GUIダイアログは表示されません。 diff --git a/docs-translations/jp/api/download-item.md b/docs-translations/jp/api/download-item.md deleted file mode 100644 index 1be61b2f98a5f..0000000000000 --- a/docs-translations/jp/api/download-item.md +++ /dev/null @@ -1,92 +0,0 @@ -# DownloadItem - -`DownloadItem`は、Electronでアイテムのダウンロードを示すEventEmitterです。 `Session`モジュールの`will-download`イベントで使用され、ダウンロードしたアイテムをコントロールすることができます。 - -```javascript -// In the main process. -win.webContents.session.on('will-download', function(event, item, webContents) { - // Set the save path, making Electron not to prompt a save dialog. - item.setSavePath('/tmp/save.pdf'); - console.log(item.getMimeType()); - console.log(item.getFilename()); - console.log(item.getTotalBytes()); - item.on('updated', function() { - console.log('Received bytes: ' + item.getReceivedBytes()); - }); - item.on('done', function(e, state) { - if (state == "completed") { - console.log("Download successfully"); - } else { - console.log("Download is cancelled or interrupted that can't be resumed"); - } - }); -``` - -## イベント - -### イベント: 'updated' - -`downloadItem`が更新されたときに出力されます。 - -### イベント: 'done' - -* `event` Event -* `state` String - * `completed` - ダウンロードが成功で完了 - * `cancelled` - ダウンロードをキャンセル - * `interrupted` - ファイルサーバーとの接続が切れてエラー - -ダウンロードが終了状態になったときに出力されます。終了状態には、ダウンロードの完了、ダウンロードのキャンセル(`downloadItem.cancel()`経由)、レジュームできないダウンロードの中断などです。 - -## メソッド - -`downloadItem`オブジェクトは次のメソッドを持ちます: - -### `downloadItem.setSavePath(path)` - -* `path` String - ダウンロードアイテムの保存ファイルパスを設定します。 - -APIはセッションの`will-download`コールバック関数のみで提供されます。API経由で保存パスを設定しなかった場合、Electronは保存パスを決めるための元のルーチン(通常は保存ダイアログ)を使用します。 - -### `downloadItem.pause()` - -ダウンロードをポーズします。 - -### `downloadItem.resume()` - -ポーズしたダウンロードを再開します。 - -### `downloadItem.cancel()` - -ダウンロード操作をキャンセルします。 - -### `downloadItem.getURL()` - -どのURLからアイテムをダウンロードするのかを示す`String`を返します。 - -### `downloadItem.getMimeType()` - -mimeタイプを示す`String`を返します。 - -### `downloadItem.hasUserGesture()` - -ダウンロードがユーザージェスチャーを持っているかどうかを示す`Boolean`を返します。 - -### `downloadItem.getFilename()` - -ダウンロードアイテムのファイル名を示す`String`を返します。 - -**Note:** ファイル名はローカルディスクに実際に保存するものといつも同じとは限りません。ダウンロード保存ダイアログでユーザーがファイル名を変更していると、保存するファイルの実際の名前は異なります。 - -### `downloadItem.getTotalBytes()` - -ダウンロードアイテムの合計バイトサイズを示す`Integer`を返します。 -サイズが不明な場合、0を返します。 - -### `downloadItem.getReceivedBytes()` - -ダウンロードしたアイテムの受信バイト数を示す`Integer`を返します。 - -### `downloadItem.getContentDisposition()` - -レスポンスヘッダーからContent-Dispositionを示す`String`を返します。 diff --git a/docs-translations/jp/api/environment-variables.md b/docs-translations/jp/api/environment-variables.md deleted file mode 100644 index 75c0ab0c2a9ad..0000000000000 --- a/docs-translations/jp/api/environment-variables.md +++ /dev/null @@ -1,51 +0,0 @@ -# 環境変数 - -> アプリケーションの設定や動作を、コードの変更なしで制御します。 - -コマンドラインやアプリのコードよりも早く初期化されるために、Electronのいくつかの挙動は環境変数がコントロールしています。 - -POSIX shellでの例: - -```bash -$ export ELECTRON_ENABLE_LOGGING=true -$ electron -``` - -Windows コンソール上: - -```powershell -> set ELECTRON_ENABLE_LOGGING=true -> electron -``` - -## `ELECTRON_RUN_AS_NODE` - -通常のNode.jsプロセスでプロセスを開始します。 - -## `ELECTRON_ENABLE_LOGGING` - -Chromeのインターナルログをコンソールに出力します。 - - -## `ELECTRON_LOG_ASAR_READS` - -ASARファイルからElectronが読み込んだとき、システム`tmpdir`へ読み込みオフセットとファイルのパスを記録します。ファイルの順序を最適化するために、得られたファイルはASARモジュールに提供されます。 - -## `ELECTRON_ENABLE_STACK_DUMPING` - -Electronがクラッシュしたとき、コンソールにスタックとレースを出力します。 -`crashReporter`が開始していないと、この環境変数は動作しません。 - -## `ELECTRON_DEFAULT_ERROR_MODE` _Windows_ - -Electronがクラッシュしたとき、Windowsのクラッシュダイアログを表示します。 -`crashReporter`が開始していないと、この環境変数は動作しません。 - -## `ELECTRON_NO_ATTACH_CONSOLE` _Windows_ - -現在のコンソールセッションにはアタッチできません。 - -## `ELECTRON_FORCE_WINDOW_MENU_BAR` _Linux_ - -Linuxでグローバルメニューバーを使用できません。 - diff --git a/docs-translations/jp/api/file-object.md b/docs-translations/jp/api/file-object.md deleted file mode 100644 index ec2724cff1d2f..0000000000000 --- a/docs-translations/jp/api/file-object.md +++ /dev/null @@ -1,29 +0,0 @@ -# `File` object - -> ファイルシステム上のファイルを扱うには、HTML5のFile APIを使用します。 - -DOMのファイルインターフェイスにより、ユーザーはHTML 5 ファイルAPIで直接、ネイティブファイルで作業できるように、ネイティブファイル周りの抽象化を提供します。Electronは、ファイルシステム上のファイルの実際のパスを公開する`File`インターフェイスの`path`属性を追加します。 - -アプリ上にドラッグしたファイルの実際のパスを取得する例: - -```html -
- Drag your file here -
- - -``` diff --git a/docs-translations/jp/api/frameless-window.md b/docs-translations/jp/api/frameless-window.md deleted file mode 100644 index 518e2680cf96a..0000000000000 --- a/docs-translations/jp/api/frameless-window.md +++ /dev/null @@ -1,73 +0,0 @@ -# Frameless Window - -フレームの無いウィンドウは、ウェブページの一部ではなく、ツールバーのようなウィンドウのパーツで、[chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome)ではないウィンドウです。 オプションとして[`BrowserWindow`](browser-window.md)クラスがあります。 - -## フレームの無いウィンドウを作成する - -フレームの無いウィンドウを作成するために、[BrowserWindow](browser-window.md)の `options`で、`frame` を `false`に設定する必要があります。 - -```javascript -const BrowserWindow = require('electron').BrowserWindow; -var win = new BrowserWindow({ width: 800, height: 600, frame: false }); -``` - -### macOSでの別の方法 - -macOS 10.10 Yosemite以降では、Chrome無しのウィンドウを指定する方法があります。`frame`を`false`に設定しタイトルバーとウィンドウコントロールの両方を無効にする代わりに、タイトルバーを隠しコンテンツをフルウィンドウサイズに広げたいけど、標準的なウィンドウ操作用にウィンドウコントロール("トラフィックライト")を維持したいかもしれません。新しい`titleBarStyle`オプションを指定することで、そうできます。 - -```javascript -var win = new BrowserWindow({ 'titleBarStyle': 'hidden' }); -``` - -## 透明なウィンドウ - - `transparent`オプションを`true`に設定すると、フレームの無い透明なウィンドウを作成できます。 - -```javascript -var win = new BrowserWindow({ transparent: true, frame: false }); -``` - -### 制限 - -* 透明領域をクリックすることはできません。この問題を解決するためにウィンドウの輪郭を設定するAPIを導入しようとしています。詳細は、[our issue](https://github.com/electron/electron/issues/1335) を参照してください。 -* 透明なウィンドウはサイズ変更できません。いくつかのプラットフォーム上では、`resizable`の`true`設定は、いくつかのプラットフォーム上で、動作を停止する透明ウィンドウを作成するかもしれません。 -* `blur`フィルターはウェブページのみに適用され、ウィンドウの下のコンテンツ(例えば、ユーザーのシステム上でほかのアプリケーションを開く)に、ぼやける効果を適用する方法はありません。 -* Windows オペレーティングシステム上では、DMMが無効のとき透明なウィンドウは動作しません。 -* Linuxユーザーは、GPUを無効化するためにコマンドラインで`--enable-transparent-visuals --disable-gpu`を設定でき、透明ウィンドウを作成するためにARGBを許可でき、これは、 [いくつかのNVidiaドライバー上でアルファチャンネルが動作しない](https://code.google.com/p/chromium/issues/detail?id=369209) という上流のバグ原因になります。 -* Macでは、透明なウィンドウでネイティブのウィンドウシャドーを表示できません。 - -## ドラッグ可能領域 - -既定では、フレーム無しウィンドウはドラッグできません。(OSの標準的なタイトルバーのような)ドラッグできる領域をElectronに指定するには、CSSで`-webkit-app-region: drag`を指定する必要があり、アプリはドラッグできる領域からドラッグできない領域を除外するために、`-webkit-app-region: no-drag`を使えます。現在のところ長方形領域のみサポートしています。 - -ウィンドウ全体をドラッグできるようにするには、`body`のスタイルに`-webkit-app-region: drag`を追加します。 - -```html - - -``` - -ウィンドウ全体度ドラッグできるようにするには、ボタンをドラッグできないように指定する必要があり、そうしなければユーザーがそれをクリックする可能性があります。 - -```css -button { - -webkit-app-region: no-drag; -} -``` - -カスタムタイトルバーをドラッグできるように設定すると、タイトルバーのすべてのボタンをドラッグできないようにする必要があります。 - -## テキスト選択 - -フレームの無いウィンドウでは、ドラッグを可能にする動作とテキスト選択がぶつかるかもしれません。例えば、タイトルバーをドラッグしたとき、うっかりタイトルバーのテキストを選択してしまうかもしれません。これを防ぐために、次の例のようにドラッグできる領域内のテキスト選択を無効にする必要があります。 - -```css -.titlebar { - -webkit-user-select: none; - -webkit-app-region: drag; -} -``` - -## コンテキストメニュー - -いくつかのプラットフォームでは、ドラッグ可能な領域は、クライアントフレーム無しとして扱われるので、その上で右クリックすると、システムメニューがポップアップします。コンテキストメニューをすべてのプラットフォームで正しく動作するようにするためには、ドラッグ可能領域でカスタムコンテキストメニューを使用しないでください。 diff --git a/docs-translations/jp/api/global-shortcut.md b/docs-translations/jp/api/global-shortcut.md deleted file mode 100644 index 922cbd66e8290..0000000000000 --- a/docs-translations/jp/api/global-shortcut.md +++ /dev/null @@ -1,64 +0,0 @@ -# globalShortcut - -さまざまなショートカットの動作をカスタマイズするために、オペレーティングシステムのグローバルのキーボードショートカットを`globalShortcut`モジュールは登録したり、解除したりできます。 - -**Note:** ショートカットはグローバルです。アプリがキーボードフォーカスを持っていなくても動作します。`app`モジュールの `ready`イベントが出力されるまでは使うべきではありません。 - -```javascript -const electron = require('electron'); -const app = electron.app; -const globalShortcut = electron.globalShortcut; - -app.on('ready', function() { - // Register a 'ctrl+x' shortcut listener. - var ret = globalShortcut.register('ctrl+x', function() { - console.log('ctrl+x is pressed'); - }); - - if (!ret) { - console.log('registration failed'); - } - - // Check whether a shortcut is registered. - console.log(globalShortcut.isRegistered('ctrl+x')); -}); - -app.on('will-quit', function() { - // Unregister a shortcut. - globalShortcut.unregister('ctrl+x'); - - // Unregister all shortcuts. - globalShortcut.unregisterAll(); -}); -``` - -## メソッド - -`globalShortcut`モジュールは次のメソッドを持ちます: - -### `globalShortcut.register(accelerator, callback)` - -* `accelerator` [Accelerator](accelerator.md) -* `callback` Function - -`accelerator`のグローバルショートカットを登録します。`callback`は、ユーザーが登録しているショートカットを押したときにコールされます。 - -ほかのアプリケーションがすでにacceleratorを使用している時、この呼び出しは静かに失敗します。アプリケーション間でグローバルショートカットの争いをしてほしくないので、オペレーティングシステムはこの挙動を採用しています。 - -### `globalShortcut.isRegistered(accelerator)` - -* `accelerator` [Accelerator](accelerator.md) - -このアプリケーションが`accelerator`に登録されているかどうかを返します。 - -acceleratorがすでにほかのアプリケーションで取得していると、このコールは、`false`を返します。アプリケーション間でグローバルショートカットの争いをしてほしくないので、オペレーティングシステムはこの挙動を採用しています。 - -### `globalShortcut.unregister(accelerator)` - -* `accelerator` [Accelerator](accelerator.md) - -Unregisters the global shortcut of `accelerator`のグローバルショートカットを解除します。 - -### `globalShortcut.unregisterAll()` - -全てのグローバルショートカットを解除します。 diff --git a/docs-translations/jp/api/ipc-main.md b/docs-translations/jp/api/ipc-main.md deleted file mode 100644 index 054440c762e2d..0000000000000 --- a/docs-translations/jp/api/ipc-main.md +++ /dev/null @@ -1,79 +0,0 @@ -# ipcMain - -`ipcMain`モジュールは[EventEmitter](https://nodejs.org/api/events.html)クラスのインスタンスです。メインプロセスで使うと、レンダラ―プロセス(ウェブページ)から非同期、同期敵にメッセージ送信できます。レンダラ―から送信されたメッセージはこのモジュールに出力されます。 - -## メッセージ送信 - -メインプロレスからレンダラ―プロセスへメッセージ送信を可能にします。さらなる情報は、[webContents.send](web-contents.md#webcontentssendchannel-arg1-arg2-) を参照してください。 - -* メッセージを送信するとき、イベント名は`channel`です。 -* 同期的にメッセージを返信するために、`event.returnValue`を設定する必要があります。 -* 送信者に非同期に戻して送信するために、 `event.sender.send(...)`を使えます。 - -レンダラーとメインプロセス間でメッセージの送信とハンドリングをする例です: - -```javascript -// In main process. -const ipcMain = require('electron').ipcMain; -ipcMain.on('asynchronous-message', function(event, arg) { - console.log(arg); // prints "ping" - event.sender.send('asynchronous-reply', 'pong'); -}); - -ipcMain.on('synchronous-message', function(event, arg) { - console.log(arg); // prints "ping" - event.returnValue = 'pong'; -}); -``` - -```javascript -// In renderer process (web page). -const ipcRenderer = require('electron').ipcRenderer; -console.log(ipcRenderer.sendSync('synchronous-message', 'ping')); // prints "pong" - -ipcRenderer.on('asynchronous-reply', function(event, arg) { - console.log(arg); // prints "pong" -}); -ipcRenderer.send('asynchronous-message', 'ping'); -``` - -## メッセージ受信 - -`ipcMain`モジュールが持つイベント受信用のメソッドです。 - -### `ipcMain.on(channel, callback)` - -* `channel` String - イベント名 -* `callback` Function - -イベントが発生すると、`callback`が`event`と任意の引数でコールされます。 - -### `ipcMain.removeListener(channel, callback)` - -* `channel` String - イベント名 -* `callback` Function - 使用したのと同じ関数への参照です - `ipcMain.on(channel, callback)` - -一度メッセージを受信すると、もうコールバックをアクティブにしたくなく、何らかの理由でメッセージ送信を単に止めるには、この関数が指定したチャンネルのコールバックハンドラーを削除します。 - -### `ipcMain.removeAllListeners(channel)` - -* `channel` String - The event name. - -このipcチャンネルの *全ての* ハンドラーを削除します。 - -### `ipcMain.once(channel, callback)` - -ハンドラーの実行のために`ipcMain.on()`の代わりにこれを使うと、一度だけ発生することを意味し、`callback`の一回のコールの後にアクティブにしないのと同じです。 - -## IPC Event - -`callback`に渡される`event`オブジェクトには次のメソッドがあります。 - -### `event.returnValue` - -値にこれを設定すると同期メッセージを返します。 - -### `event.sender` - -送信したメッセージ`webContents`を返すと、非同期にメッセージを返信するために`event.sender.send`をコールできます。さらなる情報は、[webContents.send](web-contents.md#webcontentssendchannel-arg1-arg2-) を見てください。 diff --git a/docs-translations/jp/api/ipc-renderer.md b/docs-translations/jp/api/ipc-renderer.md deleted file mode 100644 index edbd862ffaa60..0000000000000 --- a/docs-translations/jp/api/ipc-renderer.md +++ /dev/null @@ -1,66 +0,0 @@ -# ipcRenderer - -`ipcRenderer`モジュールは[EventEmitter](https://nodejs.org/api/events.html) クラスのインスタンスです。レンダープロセス(ウェブページ)からメインプロセスに同期、非同期にメッセージを送信できるメソッドを提供します。メインプロセスから返答を受け取ることもできます。 - - -コード例は [ipcMain](ipc-main.md) をみてください。 - -## メッセージの受信 - -`ipcRenderer`モジュールは、イベントを受信するための次のメソッドを持ちます: - -### `ipcRenderer.on(channel, callback)` - -* `channel` String - イベント名 -* `callback` Function - -イベントが発生したとき、任意の引数と `event`オブジェクトで`callback`をコールします。 - -### `ipcRenderer.removeListener(channel, callback)` - -* `channel` String - イベント名 -* `callback` Function - 使用したのと同じ関数への参照 - `ipcRenderer.on(channel, callback)` - -一度メッセージを受信すると、もうコールバックをアクティブにしたくなく、何らかの理由でメッセージ送信を単に止めるには、この関数が指定したチャンネルのコールバックハンドラーを削除します。 - -### `ipcRenderer.removeAllListeners(channel)` - -* `channel` String - The event name. - -このipcチャンネルの *全ての* ハンドラーを削除します。 - -### `ipcMain.once(channel, callback)` - -ハンドラーの実行のために`ipcMain.on()`の代わりにこれを使うと、一度だけ発生することを意味し、`callback`の一回のコールの後にアクティブにしないのと同じです。 - -## メッセージ送信 - -`ipcRenderer`モジュールは、イベントを送信するための次のメソッドを持ちます: - -### `ipcRenderer.send(channel[, arg1][, arg2][, ...])` - -* `channel` String - イベント名 -* `arg` (optional) - -`channel` - -`channel`経由でメインプロセスに非同期にイベントを送信し、任意の引数を送信できます。メインプロセスは`ipcMain`で`channel`を受信することでハンドルします。 - -### `ipcRenderer.sendSync(channel[, arg1][, arg2][, ...])` - -* `channel` String - イベント名 -* `arg` (optional) - -`channel`経由でメインプロセスに同期的にイベントを送信し、任意の引数を送信できます。 - -メインプロセスは`ipcMain`で`channel`を受信することでハンドルし、 `event.returnValue`を設定してリプライします。 - -__Note:__ 同期的なメッセージ送信をすると全てのレンダラ―プロセスがブロックされるので、何をしているか理解できない限り、これを使うべきではありません。 - -### `ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])` - -* `channel` String - イベント名. -* `arg` (optional) - -`ipcRenderer.send`のようですが、メインプロセスの代わりにホストに``エレメントにイベントを送信します。 diff --git a/docs-translations/jp/api/menu-item.md b/docs-translations/jp/api/menu-item.md deleted file mode 100644 index 4c42f73d7e4bf..0000000000000 --- a/docs-translations/jp/api/menu-item.md +++ /dev/null @@ -1,50 +0,0 @@ -# MenuItem - -`menu-item`モジュールは、アプリケーションまたはコンテキスト[`メニュー`](menu.md)に項目を追加することができます。 - -具体例は、 [`menu`](menu.md) を見てください。 - -## クラス: MenuItem - -次のメソッドで、新しい`MenuItem`を作成します。 - -### new MenuItem(options) - -* `options` Object - * `click` Function - メニューアイテムがクリックされたとき、`click(menuItem, browserWindow)`がコールされます。 - * `role` String - 指定されたとき、メニューアイテムの動作が定義され、`click`プロパティは無視されます。 - * `type` String - `normal`と `separator`、`submenu`、`checkbox`、`radio`を指定できます。 - * `label` String - * `sublabel` String - * `accelerator` [Accelerator](accelerator.md) - * `icon` [NativeImage](native-image.md) - * `enabled` Boolean - * `visible` Boolean - * `checked` Boolean - * `submenu` Menu - メニューアイテムを省略できる`type: 'submenu'`を指定したとき、`submenu`種類のメニューアイテムを指定すべきです。値が`Menu`でないとき、`Menu.buildFromTemplate`を使用して自動的に変換されます。 - * `id` String - 1つのメニュー内で一意です。定義されていたら、position属性によってアイテムへの参照として使用できます。 - * `position` String - このフィールドは、指定されたメニュー内の特定の位置を細かく定義できます。 - -メニューアイテムを作成するとき、適切な動作がある場合は、メニューでベストな自然な体験を提供するために、手動で実装する代わりに`role`を指定することを推奨します。 - -`role` プロパティは次の値を持ちます: - -* `undo` -* `redo` -* `cut` -* `copy` -* `paste` -* `selectall` -* `minimize` - 現在のウィンドウの最小化 -* `close` - 現在のウィンドウを閉じます - -macOSでは、`role`は次の追加の値を取れます: - -* `about` - `orderFrontStandardAboutPanel`動作に紐づけられます -* `hide` - `hide`動作に紐づけられます -* `hideothers` - `hideOtherApplications`動作に紐づけられます -* `unhide` - `unhideAllApplications`動作に紐づけられます -* `front` - `arrangeInFront`動作に紐づけられます -* `window` - サブメニューは "Window"メニューです。 -* `help` - サブメニューは "Help"メニューです。 -* `services` - サブメニューは "Services"メニューです。 diff --git a/docs-translations/jp/api/menu.md b/docs-translations/jp/api/menu.md deleted file mode 100644 index d39573b29ee8c..0000000000000 --- a/docs-translations/jp/api/menu.md +++ /dev/null @@ -1,337 +0,0 @@ -# Menu - -`menu`クラスは、アプリケーションのメニューと[コンテキストメニュー](https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/PopupGuide/ContextMenus)として使えるネイティブメニューを作成するのに使われます。このモジュールは、`remote`モジュール経由でレンダラープロセスで使用できるメインプロセスのモジュールです。 - -個々のメニューは複数の[menu items](menu-item.md)で成り立ち、個々のメニューアイテムはサブメニューを持てます。 - -以下は、ユーザーはページを右クリックした時、[remote](remote.md)モジュールを作成するために、(レンダラープロセス)ウェブページで動的にメニューを作成して、表示します。 - -```html - - -``` - -シンプルなテンプレートAPIでレンダラープロセスでアプリケーションメニューを作成する例です。 - -```javascript -var 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: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.reload(); - } - }, - { - label: 'Toggle Full Screen', - accelerator: (function() { - if (process.platform == 'darwin') - return 'Ctrl+Command+F'; - else - return 'F11'; - })(), - click: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); - } - }, - { - label: 'Toggle Developer Tools', - accelerator: (function() { - if (process.platform == 'darwin') - return 'Alt+Command+I'; - else - return 'Ctrl+Shift+I'; - })(), - click: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.toggleDevTools(); - } - }, - ] - }, - { - label: 'Window', - role: 'window', - submenu: [ - { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize' - }, - { - label: 'Close', - accelerator: 'CmdOrCtrl+W', - role: 'close' - }, - ] - }, - { - label: 'Help', - role: 'help', - submenu: [ - { - label: 'Learn More', - click: function() { require('electron').shell.openExternal('http://electron.atom.io') } - }, - ] - }, -]; - -if (process.platform == 'darwin') { - var name = require('electron').remote.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: function() { app.quit(); } - }, - ] - }); - // Window menu. - template[3].submenu.push( - { - type: 'separator' - }, - { - label: 'Bring All to Front', - role: 'front' - } - ); -} - -var menu = Menu.buildFromTemplate(template); -Menu.setApplicationMenu(menu); -``` - -## クラス: Menu - -### `new Menu()` - -新しいメニューを作成します。 - -## メソッド - -`menu`クラスーは次のメソッドを持ちます。 - -### `Menu.setApplicationMenu(menu)` - -* `menu` Menu - -macOSで、アプリケーションメニューとして`menu`を設定します。WindowsとLinuxでは、`menu`はそれぞれのウィンドウの上のメニューとして設定されます。 - -### `Menu.sendActionToFirstResponder(action)` _macOS_ - -* `action` String - -アプリケーションの最初のレスポンダーに`action`が送信されます。規定のCocoaメニュー動作をエミュレートするために使われ、通常は`MenuItem`の`role`プロパティーを使います。 - -### `Menu.buildFromTemplate(template)` - -* `template` Array - -一般的に、`template`は、[MenuItem](menu-item.md)を組み立てるための `options`配列です。使用方法は下のように参照します。 - -ほかのフィールドに`template`の項目を設定でき、メニューアイテムを構成するプロパティです。 - -### `Menu.popup([browserWindow, x, y, positioningItem])` - -* `browserWindow` BrowserWindow (オプション) - 既定では`null`です。 -* `x` Number (オプション) - 既定では -1です。 -* `y` Number (**必須** `x` が使われている場合) - 既定では -1です。 -* `positioningItem` Number (オプション) _macOS_ - 既定では -1です。 - -メニューアイテムのインデックスを指定した座標にマウスカーソルを配置します。 - -`browserWindow`でコンテキストメニューとしてメニューをポップアップします。メニューを表示する場所をオプションで`x, y`座標を指定でき、指定しなければ現在のマウスカーソル位置に表示します。 - -### `Menu.append(menuItem)` - -* `menuItem` MenuItem - -メニューに`menuItem`を追加します。 - -### `Menu.insert(pos, menuItem)` - -* `pos` Integer -* `menuItem` MenuItem - -メニューの`pos`位置に`menuItem`を追加します。 - -### `Menu.items()` - -メニューのアイテムを収容した配列を取得します。 - -## macOS アプリケーションメニューの注意事項 - -macOSは、WindowsとLinuxのアプリケーションのメニューとは完全に異なるスタイルを持ち、よりネイティブのようにアプリメニューを作成するのに幾つかの注意事項があります。 - -### 標準的なメニュー - -macOSでは、`Services`と`Windows`メニューのように定義された標準的な多くのメニューがあります。標準的なメニューを作成するために、メニューの`role`に次のどれかを設定する必要があり、Electronはそれを受けて標準的なメニューを作成します。 - -* `window` -* `help` -* `services` - -### 標準的なメニューアイテムの動作 - -`About xxx`と`Hide xxx`、`Hide Others`のようないくつかのメニューアイテム用にmacOSは標準的な動作を提供します。メニューアイテムの動作に標準的な動作を設定するために、メニューアイテムの`role`属性を設定すべきです。 - -### メインのメニュー名 - -macOSでは、設定したラベルに関係なく、アプリケーションの最初のアイテムのラベルはいつもアプリの名前です。変更するために、アプリにバンドルされている`Info.plist`ファイルを修正してアプリの名前を変更する必要があります。詳細は、 [About Information Property List Files][AboutInformationPropertyListFiles] を見てください。 - -## メニューアイテムの位置 - -`position`を使用することができ、`Menu.buildFromTemplate`でメニューを構築するときに`id`がアイテムを配置する方法をコントロールします。 - -`MenuItem`の`position`属性は、`[placement]=[id]`をもち、 `placement`は`before`や `after`、 `endof`の一つが設定され、`id`はメニューの設定されているアイテムで一意のIDです。 - -* `before` - IDから参照したアイテムの前にアイテムを挿入します。参照するアイテムが存在しないのなら、メニューの最後にアイテムが挿入されます。 -* `after` - IDから参照したアイテムの後にアイテムを挿入します。参照するアイテムが存在しないのなら、メニューの最後にアイテムが挿入されます。 -* `endof` -IDから参照したアイテムを含む論理グループの最後にアイテムを挿入します(グループはアイテムを分けるために作成されます)。参照するアイテムが存在しないのなら、付与されたIDで新しい分離グループが作成され、そのグループのあとにアイテムが挿入されます。 - -アイテムが配置されたとき、新しいアイテムが配置されるまで、すべての配置されていないアイテムがその後に挿入されます。同じ場所にメニューアイテムのグループを配置したいのなら、最初にアイテムで場所を指定する必要があります。 - -### 具体例 - -テンプレート: - -```javascript -[ - {label: '4', id: '4'}, - {label: '5', id: '5'}, - {label: '1', id: '1', position: 'before=4'}, - {label: '2', id: '2'}, - {label: '3', id: '3'} -] -``` - -メニュー: - -``` -- 1 -- 2 -- 3 -- 4 -- 5 -``` - -テンプレート: - -```javascript -[ - {label: 'a', position: 'endof=letters'}, - {label: '1', position: 'endof=numbers'}, - {label: 'b', position: 'endof=letters'}, - {label: '2', position: 'endof=numbers'}, - {label: 'c', position: 'endof=letters'}, - {label: '3', position: 'endof=numbers'} -] -``` - -メニュー: - -``` -- --- -- a -- b -- c -- --- -- 1 -- 2 -- 3 -``` - -[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html diff --git a/docs-translations/jp/api/native-image.md b/docs-translations/jp/api/native-image.md deleted file mode 100644 index 1c0c2ff9c6dc6..0000000000000 --- a/docs-translations/jp/api/native-image.md +++ /dev/null @@ -1,147 +0,0 @@ -# nativeImage - -Electronでは、画像を取得するAPI用に、ファイルパスまたは`nativeImage`インスタンスを渡します。`null`を渡すと、空のイメージが使われます。 - -例えば、トレイを作成したり、ウィンドウアイコンを設定する時、`String`としてイメージファイルパスを渡します: - -```javascript -var appIcon = new Tray('/Users/somebody/images/icon.png'); -var window = new BrowserWindow({icon: '/Users/somebody/images/window.png'}); -``` - -もしくは、`nativeImage`を返すクリップボードからイメージを読み込みます: - -```javascript -var image = clipboard.readImage(); -var appIcon = new Tray(image); -``` - -## 対応しているフォーマット - -今のところ、`PNG` と `JPEG`の画像フォーマットに対応しています。透明や可逆圧縮に対応しているので、`PNG` を推奨します。 - -Windowsでは、ファイルパスから`ICO`アイコンをロードできます。 - -## 高解像度画像 - -高DPIに対応しているプラットフォームで、高解像度としてマークするためにイメージの基本ファイル名の後に`@2x`を追加できます。 - -例えば、`icon.png`は一般的な解像度の通常の画像で、`icon@2x.png`は、倍のDPI密度を持つ高解像度画像として扱われます。 - - -同時に異なるDPI密度をディスプレイで対応したい場合、同じフォルダーに異なるサイズの画像を置き、DPIサフィックスなしでファイル名を使用します。 - -例: - -```text -images/ -├── icon.png -├── icon@2x.png -└── icon@3x.png -``` - - -```javascript -var appIcon = new Tray('/Users/somebody/images/icon.png'); -``` - -次のDPIサフィックスに対応しています: - -* `@1x` -* `@1.25x` -* `@1.33x` -* `@1.4x` -* `@1.5x` -* `@1.8x` -* `@2x` -* `@2.5x` -* `@3x` -* `@4x` -* `@5x` - -## テンプレート画像 - -テンプレート画像は、黒とクリアな色(とアルファチャンネル)で成り立ちます。テンプレート画像は画像単体での使用は想定しておらず、通常は最終的にほしい画像を生成するためにほかのコンテンツと合成します。 - -もっとも一般的なケースは、ライトとダークなメニュバー両方に切り替え可能なメニュバーアイコン用にテンプレート画像を使います。 - - -**Note:** テンプレート画像は、macOSでのみサポートしています。 - -テンプレート画像として画像をマークするために、ファイル名の最後に`Template`をつけます。 - -例: - -* `xxxTemplate.png` -* `xxxTemplate@2x.png` - -## メソッド - -`nativeImage`クラスは次のメソッドを持ちます: - -### `nativeImage.createEmpty()` - -空の`nativeImage` インスタンスを生成します。 - -### `nativeImage.createFromPath(path)` - -* `path` String - -`path`で指定したファイルから新しい`nativeImage`を生成します。 - -### `nativeImage.createFromBuffer(buffer[, scaleFactor])` - -* `buffer` [Buffer][buffer] -* `scaleFactor` Double (optional) - - `buffer`から新しい`nativeImage`インスタンスを生成します。既定では、`scaleFactor`は1.0です。 - -### `nativeImage.createFromDataURL(dataURL)` - -* `dataURL` String - -`dataURL`から新しい `nativeImage`インスタンスを生成します。 - -## インスタンスメソッド - -`nativeImage`のインスタンス上で提供されるメソッド: - -```javascript -const nativeImage = require('electron').nativeImage; - -var image = nativeImage.createFromPath('/Users/somebody/images/icon.png'); -``` - -### `image.toPNG()` - -`PNG`エンコードされた画像を含む[Buffer][buffer]を返します。 - -### `image.toJPEG(quality)` - -* `quality` Integer (**required**) - Between 0 - 100. - -`JPEG`エンコードされた画像を含む[Buffer][buffer]を返します。 - -### `image.toDataURL()` - -画像のURLデータを返します。 - -### `image.isEmpty()` - -画像が空かどうかをブーリアン値で返します。 - -### `image.getSize()` - -画像サイズを返します。 - -[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer - -### `image.setTemplateImage(option)` - -* `option` Boolean - -テンプレート画像としてマークします。 - -### `image.isTemplateImage()` - -イメージがテンプレート画像かどうかをブーリアン値で返します。 diff --git a/docs-translations/jp/api/power-monitor.md b/docs-translations/jp/api/power-monitor.md deleted file mode 100644 index 776d61445cea5..0000000000000 --- a/docs-translations/jp/api/power-monitor.md +++ /dev/null @@ -1,33 +0,0 @@ -# powerMonitor - -`power-monitor`モジュールは、パワー状態の変更の監視に使われます。メインプロセスでみ使用することができます。`app`モジュールの`ready`が出力されるまで、このモジュールを使うべきではありません。 - -例: - -```javascript -app.on('ready', function() { - require('electron').powerMonitor.on('suspend', function() { - console.log('The system is going to sleep'); - }); -}); -``` - -## イベント - -`power-monitor`モジュールは次のイベントを出力します。: - -### イベント: 'suspend' - -システムがサスペンドのときに出力されます。 - -### イベント: 'resume' - -システムがレジュームのときに出力されます。 - -### イベント: 'on-ac' - -システムがACパワーに変わったときに出力されます。 - -### イベント: 'on-battery' - -システムがバッテリーパワーに変わったときに出力されます。 diff --git a/docs-translations/jp/api/power-save-blocker.md b/docs-translations/jp/api/power-save-blocker.md deleted file mode 100644 index f0b358e2e5d9f..0000000000000 --- a/docs-translations/jp/api/power-save-blocker.md +++ /dev/null @@ -1,42 +0,0 @@ -# powerSaveBlocker - -`powerSaveBlocker`モジュールは、省電力(スリープ)モードからシステムをブロックするのに使用され、それ故にアプリがシステムと画面をアクティブに維持することができます。 - -例: - -```javascript -const powerSaveBlocker = require('electron').powerSaveBlocker; - -var id = powerSaveBlocker.start('prevent-display-sleep'); -console.log(powerSaveBlocker.isStarted(id)); - -powerSaveBlocker.stop(id); -``` - -## メソッド - -`powerSaveBlocker`モジュールは次のメソッドを持ちます: - -### `powerSaveBlocker.start(type)` - -* `type` String - パワーセーブのブロック種類です。 - * `prevent-app-suspension` - アプリケーションがサスペンドになるのを防ぎます。システムのアクティブ状態を維持できますが、画面をオフにすることができます。使用例:ファイルのダウンロードまたは音楽の再生 - * `prevent-display-sleep`- ディスプレイがスリープになるのを防ぎます。システムと画面のアクティブ状態を維持できます。使用例:ビデオ再生 - -省電力モードに入るのを防止するシステムを開始します。パワーセーブブロッカーを確認する数字を返します。 - -**Note:** `prevent-display-sleep`は`prevent-app-suspension`より高い優先権を持ちます。最も優先権が高いタイプのみが影響します。言い換えれば。`prevent-display-sleep`はいつも`prevent-app-suspension`より高い優先権をもちます。 - -例えば、APIが`prevent-app-suspension`を要求するAをコールし、ほかのAPIが`prevent-display-sleep`を要求するBをコールすると、`prevent-display-sleep`はBのリクエストが止まるまで使われ、そのあと`prevent-app-suspension`が使われます。 - -### `powerSaveBlocker.stop(id)` - -* `id` Integer - `powerSaveBlocker.start`によって、パワーセーブブロッカーIDが返されます。 - -指定したパワーセーブブロッカーを停止します。 - -### `powerSaveBlocker.isStarted(id)` - -* `id` Integer - `powerSaveBlocker.start`によって、パワーセーブブロッカーIDが返されます。 - -`powerSaveBlocker`が開始したかどうかのブーリアン値を返します。 diff --git a/docs-translations/jp/api/process.md b/docs-translations/jp/api/process.md deleted file mode 100644 index 23301494a37ec..0000000000000 --- a/docs-translations/jp/api/process.md +++ /dev/null @@ -1,100 +0,0 @@ -# process - -> processオブジェクトの拡張。 - -Electronの`process`オブジェクトは次のようなAPIで拡張されています。 - -## イベント - -### イベント: 'loaded' - -このイベントはElectronが内部の初期化スクリプトをロードし、ウェブページまたはメインスクリプトのロードが始まるときに発行されます。 - -Node統合がオフになっているとき、削除したNodeグローバルシンボルをグローバルスコープへ戻すために、プリロードスクリプトで使用できます。 - -```js -// preload.js -var _setImmediate = setImmediate; -var _clearImmediate = clearImmediate; -process.once('loaded', function() { - global.setImmediate = _setImmediate; - global.clearImmediate = _clearImmediate; -}); -``` - -## プロパティ - -### `process.noAsar` - -これを`true`に設定すると、Nodeのビルトインモジュールで、`asar`アーカイブのサポートを無効にできます。 - -### `process.type` - -現在のプロセスのタイプで、`"browser"`(例: メインプロセス) または `"renderer"`の値をとります。 - -### `process.versions.electron` - -Electronのバージョン文字列です。 - -### `process.versions.chrome` - -Chromeのバージョン文字列です。 - -### `process.resourcesPath` - -リソースディレクトリのパスです。 - -### `process.mas` - -Mac app Store用のビルドでは値は`true`になります。ほかのビルドの場合は`undefined`です。 - -### `process.windowsStore` - -Windows Store App (appx)として動作中の場合は、値は`true`になります。それ以外では`undefined`です。 - -### `process.defaultApp` - -アプリがdefault appのパラメータとして渡されて起動された場合は、値は`true`になります。 - -訳注: [issue #4690](https://github.com/electron/electron/issues/4690)が参考になります。 - - -## メソッド - -`process`オブジェクトは次のメソッドを持ちます。 - - -### `process.crash()` - -このプロセスのメインスレッドをクラッシュさせます。 - -### `process.hang()` - -このプロセスのメインスレッドをハングさせます。 - -### `process.setFdLimit(maxDescriptors)` _macOS_ _Linux_ - -* `maxDescriptors` Integer - -ファイルデスクリプタの最大数のソフトリミットを、`maxDescriptors`かOSのハードリミットの、どちらか低い方に設定します。 - -### `process.getProcessMemoryInfo()` - -本プロセスのメモリ使用統計に関する情報を得ることのできるオブジェクトを返します。全ての報告値はキロバイト単位であることに注意してください。 - -* `workingSetSize` - 実際の物理メモリに固定されているメモリサイズです。 -* `peakWorkingSetSize` - これまでに実際の物理メモリに固定された最大のメモリサイズです。 -* `privateBytes` - JS heapやHTML contentなど、他のプロセスに共有されていないメモリサイズです。 -* `sharedBytes` - プロセス間で共有されているメモリサイズです。例えばElectronそのものにより使用されたメモリがこれに当たります。 - -### `process.getSystemMemoryInfo()` - -システム全体で使用されているメモリ使用統計に関する情報を得ることのできるオブジェクトを返します。全ての報告値はキロバイト単位であることに注意してください。 - -* `total` - システムで使用可能な全ての物理メモリのサイズ(KB)です。 -* `free` - アプリケーションやディスクキャッシュで使用されていないメモリのサイズです。 - -Windows / Linux用: - -* `swapTotal` - システムで使用可能なスワップメモリの総サイズです。 -* `swapFree` - システムで使用可能なスワップメモリの空きサイズです。 diff --git a/docs-translations/jp/api/protocol.md b/docs-translations/jp/api/protocol.md deleted file mode 100644 index 9f341b2f97423..0000000000000 --- a/docs-translations/jp/api/protocol.md +++ /dev/null @@ -1,175 +0,0 @@ -# protocol - -`protocol`モジュールはカスタムプロトコルを登録したり、または既存のプロトコルをインターセプタ―することができます。 - -`file://`プロトコルの同様の効果をもつプロトコルを実装した例です。 - -```javascript -const electron = require('electron'); -const app = electron.app; -const path = require('path'); - -app.on('ready', function() { - var protocol = electron.protocol; - protocol.registerFileProtocol('atom', function(request, callback) { - var url = request.url.substr(7); - callback({path: path.normalize(__dirname + '/' + url)}); - }, function (error) { - if (error) - console.error('Failed to register protocol') - }); -}); -``` - -**Note:** このモジュールは、`app`モジュールで`ready`イベントが出力された後のみ使うことができます。 - -## メソッド - -`protocol`モジュールは、次のメソッドを持ちます。 - -### `protocol.registerStandardSchemes(schemes)` - -* `schemes` Array - 標準的なスキーマーを登録するためのカスタムスキーマー - -標準的な`scheme`は、RFC 3986で策定している[generic URI syntax](https://tools.ietf.org/html/rfc3986#section-3)に準拠しています。これには`file:` と `filesystem:`を含んでいます。 - -### `protocol.registerServiceWorkerSchemes(schemes)` - -* `schemes` Array - サービスワーカーをハンドルするために登録されたカスタムスキーマー - -### `protocol.registerFileProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -レスポンスとしてファイルを送信する`scheme`のプロトコルを登録します。`scheme`で`request`が生成された時、`handler`は`handler(request, callback)`で呼び出されます。`scheme` 登録が成功したり、`completion(error)`が失敗したときに、`completion` は`completion(null)`で呼び出されます。 - -* `request` Object - * `url` String - * `referrer` String - * `method` String - * `uploadData` Array (オプション) -* `callback` Function - -`uploadData` は `data` オブジェクトの配列です: - -* `data` Object - * `bytes` Buffer - 送信するコンテンツ - * `file` String - アップロードするファイルパス - -`request`をハンドルするために、`callback`はファイルパスまたは`path`プロパティを持つオブジェクトで呼び出すべきです。例えば、`callback(filePath)` または`callback({path: filePath})`です。 - -何もなし、数字、`error`プロパティを持つオブジェクトで、`callback`が呼び出された時、 `request`は指定した`error`番号で失敗します。使用できる提供されているエラー番号は、[net error list][net-error]を参照してください。 - -既定では、`scheme`は、`file:`のような一般的なURIの構文に続くプロトコルと違う解析がされ、`http:`のように扱われます。なので、恐らく標準的なスキーマーのように扱われるスキーマーを持つために、`protocol.registerStandardSchemes` を呼び出したくなります。 - -### `protocol.registerBufferProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -レスポンスとして`Buffer`を送信する`scheme`プロトコルを登録します。 - - `callback`は、`Buffer`オブジェクトまたは、`data`と`mimeType`、 `charset`プロパティを持つオブジェクトのどちらかで呼ばれる必要があることを除いて、この使用方法は、`registerFileProtocol`と同じです。 - -例: - -```javascript -protocol.registerBufferProtocol('atom', function(request, callback) { - callback({mimeType: 'text/html', data: new Buffer('
Response
')}); -}, function (error) { - if (error) - console.error('Failed to register protocol') -}); -``` - -### `protocol.registerStringProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -レスポンスとして`String`を送信する`scheme`プロトコルを登録します。 - -`callback`は、`String`または`data`と `mimeType`、`chart`プロパティを持つオブジェクトを呼び出す必要があることを除いて、使用方法は`registerFileProtocol`と同じです。 - -### `protocol.registerHttpProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -レスポンスとしてHTTPリクエストを送信する`scheme`プロトコルを登録します。 - -`callback`は、`url`と`method`、`referrer`、`uploadData`、`session`プロパティを持つオブジェクトを呼び出す必要があることを除いて、使用方法は`registerFileProtocol`と同じです。 - -* `redirectRequest` Object - * `url` String - * `method` String - * `session` Object (オプション) - * `uploadData` Object (オプション) - -既定では、HTTPリクエストは現在のセッションを再利用します。別のセッションでリクエストをしたい場合、`session` に `null`を設定する必要があります。 - -POSTリクエストは`uploadData`オブジェクトを提供する必要があります。 -* `uploadData` object - * `contentType` String - コンテンツのMIMEタイプ - * `data` String - 送信されるコンテンツ - -### `protocol.unregisterProtocol(scheme[, completion])` - -* `scheme` String -* `completion` Function (optional) - -`scheme`のカスタムプロトコルを解除します。 - -### `protocol.isProtocolHandled(scheme, callback)` - -* `scheme` String -* `callback` Function - -`scheme`のハンドラーがあるかないかを示すブーリアン値で`callback`がコールされます。 - -### `protocol.interceptFileProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`scheme`プロトコルをインターセプタ―し、レスポンスとしてファイルを送信するプロトコルの新しいハンドラーとして`handler`を使います。 - -### `protocol.interceptStringProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`scheme`プロトコルをインターセプタ―し、レスポンスとして`String`を送信するプロトコルの新しいハンドラーとして`handler`を使います。 - -### `protocol.interceptBufferProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`scheme`プロトコルをインターセプタ―し、レスポンスとして`Buffer`を送信するプロトコルの新しいハンドラーとして`handler`を使います。 - -### `protocol.interceptHttpProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`scheme`プロトコルをインターセプタ―し、レスポンスとして新しいHTTPリクエストを送信するプロトコルの新しいハンドラーとして`handler`を使います。 - -### `protocol.uninterceptProtocol(scheme[, completion])` - -* `scheme` String -* `completion` Function - -インターセプタ―したインストールされた`scheme`を削除し、オリジナルハンドラーをリストアします。 - - -[net-error]: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h diff --git a/docs-translations/jp/api/remote.md b/docs-translations/jp/api/remote.md deleted file mode 100644 index 0d4ec0d389efa..0000000000000 --- a/docs-translations/jp/api/remote.md +++ /dev/null @@ -1,124 +0,0 @@ -# remote - - `remote`モジュールは、レンダラープロセス(ウェブページ)とメインプロセス間でインタープロセスコミュニケーション(IPC)をする簡単な方法を提供します。 - -Electronでは、GUI関連モジュール(`dialog`や`menu`など)はメインプロセスのみに提供されており、レンダラープロセスには提供されていません。レンダラープロセスからそれらを使うために、`ipc`モジュールはメインプロセスにインタープロセスメッセージを送信するのに必要です。`remote`モジュールで、Javaの[RMI][rmi]と同じように、はっきりとインタープロセスメッセージを送信しなくてもメインプロセスオブジェクトのメソッドを呼び出せます。 - -レンダラープロセスからブラウザーウィンドウを作成する例: - -```javascript -const remote = require('electron').remote; -const BrowserWindow = remote.BrowserWindow; - -var win = new BrowserWindow({ width: 800, height: 600 }); -win.loadURL('https://github.com'); -``` - -**Note:** 逆には(メインプロセスからレンダラープロセスにアクセスする)、[webContents.executeJavascript](web-contents.md#webcontentsexecutejavascriptcode-usergesture)が使えます。 - -## Remote オブジェクト - -`remote`モジュールから返されるそれぞれのオブジェクト(関数含む)はメインプロセスでオブジェクトを示します(リモートオブジェクトまたはリモート関数と呼ばれます)。リモートプロジェクトのメソッドを実行したり、リモート関数をコールしたり、リモートコンストラクター(関数)で新しいオブジェクトを生成したりしたとき、実際に非同期にインタープロセスメッセージが送信されます。 - -上の例では、`BrowserWindow` と `win` はリモートオブジェクトで、`new BrowserWindow`はレンダラープロセスで `BrowserWindow`を作成しません。代わりに、メインプロセスで`BrowserWindow` オブジェクトが作成され、レンダラープロセスで対応するリモートオブジェクトを返し、すなわち`win`オブジェクトです。 - -リモート経由でのみアクセスできる [enumerable properties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)に注意してください。 - -## Remote オブジェクトのライフタイム - -Electronは、レンダラープロセスのリモートオブジェクトが生きている限り(言い換えれば、ガベージコレクションされません)、対応するメインプロセスのオブジェクトは解放されないことを確認してください。リモートオブジェクトがガベージコレクションされたとき、対応するメインプロセスのオブジェクトが間接参照されます。 - -レンダラープロセスでリモートオブジェクトがリークした場合(マップに格納されているが解放されない)、メインプロセスで対応するオブジェクトもリークするので、リモートオブジェクトがリークしないように細心の注意を払うべきです。 - -文字列や数字のようなプライマリ値は、コピーして送信します。 - -## メインプロセスにコールバックを通す - -メインプロセスのコードは、レンダラーからコールバックを受け取ることができます。例えば、`remote`モジュールです。この機能をとても慎重に使うべきです。 - -最初に、デッドロックを避けるために、メインプロセスに渡されたコールバックは非同期に呼び出されます。メインプロセスは、渡されたコールバックの戻り値を取得することを期待すべきではありません。 - -例えば、メインプロセスでコールされた`Array.map`で、レンダラープロセスから関数を使用することはできません。: - -```javascript -// main process mapNumbers.js -exports.withRendererCallback = function(mapper) { - return [1,2,3].map(mapper); -} - -exports.withLocalCallback = function() { - return exports.mapNumbers(function(x) { - return x + 1; - }); -} -``` - -```javascript -// renderer process -var mapNumbers = require("remote").require("./mapNumbers"); - -var withRendererCb = mapNumbers.withRendererCallback(function(x) { - return x + 1; -}) - -var withLocalCb = mapNumbers.withLocalCallback() - -console.log(withRendererCb, withLocalCb) // [true, true, true], [2, 3, 4] -``` - -見ることができるように、レンダラーコールバックの同期戻り値は予想されなかったとして、メインプロセスで生きている同一のコールバックの戻り値と一致しません。 - -第二に、メインプロセスに渡されるコールバックはメインプロセスがガベージコレクトするまで存続します。 - -例えば、次のコードは一目で無害なコードのように思えます。リモートオブジェクト上で`close`イベントのコールバックをインストールしています。 - -```javascript -remote.getCurrentWindow().on('close', function() { - // blabla... -}); -``` - -りかし、明確にアンインストールするまでメインプロセスによってコールバックは参照されることを覚えておいてください。アンインストールしない場合、ウィンドウをリロードするたびに、コールバックは再度インストールされ、それぞれの再起動時にコールバックあリークします。 - -さらに悪いことに、前にインストールされたコールバックのコンテキストは解放されるので、`close`イベントを出力されると、メインプロセスで例外が発生します。 - -この問題を避けるために、メインプロセスに渡されたレンダラーコールバックへの参照をクリーンアップを確認します。これにはイベントハンドラーのクリンアップも含まれ、存在しているレンダラープロセスから来るコールバックを確実にメインプロセスが守るように確認します。 - -## メインプロセスで組み込みモジュールにアクセスする - -メインプロセスの組み込みモジュールは、`remote`モジュールでゲッターとして追加されるので、`electron`モジュールのように直接それらを使用できます。 - -```javascript -const app = remote.app; -``` - -## メソッド - -`remote`モジュールは次のメソッドを持ちます。 - -### `remote.require(module)` - -* `module` String - -メインプロセスで、`require(module)`で返されるオブジェクトを返します。 - -### `remote.getCurrentWindow()` - -このウェブページに属する[`BrowserWindow`](browser-window.md) オブジェクトを返します。 - -### `remote.getCurrentWebContents()` - -このウェブページの[`WebContents`](web-contents.md) オブジェクトを返します。 - -### `remote.getGlobal(name)` - -* `name` String - -メインプロセスで、`name`のグローバル変数(例えば、`global[name]`)を返します。 - - -### `remote.process` - -メインプロセスで`process`オブジェクトを返します。これは`remote.getGlobal('process')`と同様ですが、キャッシュされます。 - -[rmi]: http://en.wikipedia.org/wiki/Java_remote_method_invocation diff --git a/docs-translations/jp/api/screen.md b/docs-translations/jp/api/screen.md deleted file mode 100644 index 6d06ee86f8631..0000000000000 --- a/docs-translations/jp/api/screen.md +++ /dev/null @@ -1,131 +0,0 @@ -# screen - -`screen`モジュールは、画面サイズ、ディスプレイ、カーソル位置などの情報を読み取ります。`app`モジュールの`ready`イベントが出力されるまで、このモジュールは使うべきではありません。 - -`screen`は [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter)です。 - -**Note:** レンダラ―/デベロッパーツールで、`window.screen`はDOMプロパティで予約されているので、`var screen = require('electron').screen`と書いても動作しません。下の例では、代わりに変数名で`electronScreen`を使用しています。 - -画面全体にウィンドウを作成する例: - -```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; - -var mainWindow; - -app.on('ready', function() { - var electronScreen = electron.screen; - var size = electronScreen.getPrimaryDisplay().workAreaSize; - mainWindow = new BrowserWindow({ width: size.width, height: size.height }); -}); -``` -外部ディスプレイにウィンドウを作成する別の例: - -```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; - -var mainWindow; - -app.on('ready', function() { - var electronScreen = electron.screen; - var displays = electronScreen.getAllDisplays(); - var externalDisplay = null; - for (var i in displays) { - if (displays[i].bounds.x != 0 || displays[i].bounds.y != 0) { - externalDisplay = displays[i]; - break; - } - } - - if (externalDisplay) { - mainWindow = new BrowserWindow({ - x: externalDisplay.bounds.x + 50, - y: externalDisplay.bounds.y + 50 - }); - } -}); -``` - -## `Display` オブジェクト - -`Display`オブジェクトはシステムに接続された物理ディスプレイを示します。ヘッドレスシステムでは、擬似`Display`があるかもしれませんし、`Display`はリモートや仮想ディスプレイに相当するかもしれません。 - -* `display` object - * `id` Integer - ディスプレイに紐づいた一意な識別子です。 - * `rotation` Integer - 0, 1, 2, 3を設定でき、それぞれは時計回りで、0, 90, 180, 270度の画面の回転を示します。 - * `scaleFactor` Number - 出力装置のピクセルスケールファクター - * `touchSupport` String - `available`, `unavailable`, `unknown`を設定できます。 - * `bounds` Object - * `size` Object - * `workArea` Object - * `workAreaSize` Object - -## イベント - -`screen`モジュールは次のイベントを出力します: - -### イベント: 'display-added' - -返り値: - -* `event` Event -* `newDisplay` Object - -`newDisplay`が追加されたときに出力されます。 - -### イベント: 'display-removed' - -返り値: - -* `event` Event -* `oldDisplay` Object - -`oldDisplay`が削除されたときに出力されます。 - -### イベント: 'display-metrics-changed' - -返り値: - -* `event` Event -* `display` Object -* `changedMetrics` Array - -`display`で1つ以上のメトリックが変わったときに出力されます。`changedMetrics`は変更を説明する文字列の配列です。変更内容には`bounds`と`workArea`, `scaleFactor`、 `rotation`があり得ます。 - -## メソッド - -`screen`モジュールは次のメソッドを持ちます: - -### `screen.getCursorScreenPoint()` - -現在のマウスの絶対位置を返します。 - -### `screen.getPrimaryDisplay()` - -プライマリディスプレイを返します。 - -### `screen.getAllDisplays()` - -現在利用可能なディスプレイの配列を返します。 - -### `screen.getDisplayNearestPoint(point)` - -* `point` Object - * `x` Integer - * `y` Integer - -指定したポイントに近いディスプレイを返します。 - -### `screen.getDisplayMatching(rect)` - -* `rect` Object - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -提供された範囲と、もっとも重複しているディスプレイを返します。 diff --git a/docs-translations/jp/api/session.md b/docs-translations/jp/api/session.md deleted file mode 100644 index a5d47d404a6dd..0000000000000 --- a/docs-translations/jp/api/session.md +++ /dev/null @@ -1,445 +0,0 @@ -# session - -`session`モジュールは、新しい`Session`オブジェクトを作成するのに使われます。 - -[`BrowserWindow`](browser-window.md)のプロパティである [`webContents`](web-contents.md)プロパティの`session`を使うことで既存ページの `session`にアクセスできます。 - -```javascript -const BrowserWindow = require('electron').BrowserWindow; - -var win = new BrowserWindow({ width: 800, height: 600 }); -win.loadURL("http://github.com"); - -var ses = win.webContents.session; -``` - -## メソッド - - `session`メソッドは次のメソッドを持ちます: - -### session.fromPartition(partition) - -* `partition` String - -`partition`文字列から新しい`Session`インスタンスを返します。 - -`partition`が`persist:`から始まっている場合、同じ`partition`のアプリ内のすべてのページに永続セッションを提供するのにページが使います。`persist:`プレフィックスが無い場合、ページはインメモリセッションを使います。`partition`が空の場合、アプリの既定のセッションを返します。 - -## プロパティ - -`session`モジュールは次のプロパティを持ちます: - -### session.defaultSession - -アプリの既定のセッションオブジェクトを返します。 - -## クラス: Session - -`session`モジュールで、`Session`オブジェクトを作成できます: - -```javascript -const session = require('electron').session; - -var ses = session.fromPartition('persist:name'); -``` - -### インスタンスイベント - -`Session`のインスタンス上で次のイベントが提供されます: - -#### イベント: 'will-download' - -* `event` Event -* `item` [DownloadItem](download-item.md) -* `webContents` [WebContents](web-contents.md) - -Electronが`webContents`で`item`をダウンロードしようとすると出力されます。 - -`event.preventDefault()` をコールするとダウンロードをキャンセルできます。 - -```javascript -session.defaultSession.on('will-download', function(event, item, webContents) { - event.preventDefault(); - require('request')(item.getURL(), function(data) { - require('fs').writeFileSync('/somewhere', data); - }); -}); -``` - -### インスタンスのメソッド - -`Session`のインスタンス上で次のメソッドが提供されています: - -#### `ses.cookies` - -`cookies`は、cookiesに問い合わせしたり、修正をできるようにします。例: - -```javascript -// Query all cookies. -session.defaultSession.cookies.get({}, function(error, cookies) { - console.log(cookies); -}); - -// Query all cookies associated with a specific url. -session.defaultSession.cookies.get({ url : "http://www.github.com" }, function(error, cookies) { - console.log(cookies); -}); - -// Set a cookie with the given cookie data; -// may overwrite equivalent cookies if they exist. -var cookie = { url : "http://www.github.com", name : "dummy_name", value : "dummy" }; -session.defaultSession.cookies.set(cookie, function(error) { - if (error) - console.error(error); -}); -``` - -#### `ses.cookies.get(filter, callback)` - -* `filter` Object - * `url` String (オプション) - `url`に関連付けられているcookiesを取得します。空の場合すべてのurlのcookiesを取得します - * `name` String (オプション) - `name`でcookiesをフィルタリングします - * `domain` String (オプション) - `domains`のドメインまたはサブドメインに一致するcookiesを取得します - * `path` String (オプション) - `path`に一致するパスのcookiesを取得します - * `secure` Boolean (オプション) - Secure プロパティでcookiesをフィルターします - * `session` Boolean (オプション) - Filters out `session`または永続cookiesを除外します -* `callback` Function - -`details`に一致するすべてのcookiesを取得するためにリクエストを送信し、完了時に`callback(error, cookies)`で`callback`がコールされます。 - -`cookies` は`cookie`オブジェクトの配列です。 - -* `cookie` Object - * `name` String - cookieの名前 - * `value` String - cookieの値 - * `domain` String - cookieのドメイン - * `hostOnly` String - cookieがホストのみのcookieかどうか - * `path` String - cookieのパス - * `secure` Boolean - cookieがセキュアとマークされているかどうか - * `httpOnly` Boolean - HTTPのみとしてcookieがマークされているかどうか - * `session` Boolean - cookieがセッションcookieまたは有効期限付きの永続cookieかどうか - * `expirationDate` Double (オプション) - - -cookieの有効期限をUNIX時間で何秒かを示します。セッションcookiesは提供されません。 - -#### `ses.cookies.set(details, callback)` - -* `details` Object - * `url` String - `url`に関連付けられているcookiesを取得します。 - * `name` String - cookieの名前。省略した場合、既定では空です。 - * `value` String - cookieの名前。省略した場合、既定では空です。 - * `domain` String - cookieのドメイン。省略した場合、既定では空です。 - * `path` String - cookieのパス。 省略した場合、既定では空です。 - * `secure` Boolean - cookieをセキュアとしてマークする必要があるかどうか。既定ではfalseです。 - * `session` Boolean - cookieをHTTPのみとしてマークする必要があるかどうか。既定ではfalseです。 - * `expirationDate` Double - cookieの有効期限をUNIX時間で何秒か。省略した場合、cookieはセッションcookieになります。 -* `callback` Function - -`details`でcookieを設定し、完了すると`callback(error)`で`callback`がコールされます。 - -#### `ses.cookies.remove(url, name, callback)` - -* `url` String - cookieに関連付けられているURL -* `name` String - 削除するcookieの名前 -* `callback` Function - -`url` と `name`と一致するcookiesを削除し、完了すると`callback`が、`callback()`でコールされます。 - -#### `ses.getCacheSize(callback)` - -* `callback` Function - * `size` Integer - 使用しているキャッシュサイズバイト数 - -現在のセッションのキャッシュサイズを返します。 - -#### `ses.clearCache(callback)` - -* `callback` Function - 操作が完了したら、コールされます。 - -セッションのHTTPキャッシュをクリアします。 - -#### `ses.clearStorageData([options, ]callback)` - -* `options` Object (オプション) - * `origin` String - `window.location.origin`の説明で、`scheme://host:port`に従う - * `storages` Array - クリアするストレージの種類で、次を含められます: - `appcache`、 `cookies`、 `filesystem`、 `indexdb`、 `local storage`、 - `shadercache`、 `websql`、 `serviceworkers` - * `quotas` Array - クリアするクォーターの種類で、次を含められます: - `temporary`, `persistent`, `syncable`. -* `callback` Function - 操作をするとコールされます。 - -ウェブストレージのデータをクリアします。 - -#### `ses.flushStorageData()` - -書き込まれていないDOMStorageデータをディスクに書き込みます。 - -#### `ses.setProxy(config, callback)` - -* `config` Object - * `pacScript` String - PACファイルに関連付けらえたURL - * `proxyRules` String - 使用するプロキシを指定するルール -* `callback` Function - 操作をするとコールされます。 - -プロキシ設定を設定します。 - -`pacScript` と `proxyRules`が一緒に渡されたら、`proxyRules`オプションは無視され、`pacScript`設定が適用されます。 - - `proxyRules`はつふぃのルールに従います。 - -``` -proxyRules = schemeProxies[";"] -schemeProxies = ["="] -urlScheme = "http" | "https" | "ftp" | "socks" -proxyURIList = [","] -proxyURL = ["://"][":"] -``` - -具体例: - -* `http=foopy:80;ftp=foopy2` - `http://`URLは`foopy:80`HTTPプロキシを使用し、`ftp://`URLは`foopy2:80` HTTPプロキシを使用します。 -* `foopy:80` - 全てのURLで`foopy:80`を使用します。 -* `foopy:80,bar,direct://` - 全てのURLで`foopy:80`HTTPプロキシを使用し、`foopy:80`が提供されていなければ`bar`を使用し、さらに使えない場合はプロキシを使いません。 -* `socks4://foopy` - 全てのURLでSOCKS `foopy:1080`プロキシを使います。 -* `http=foopy,socks5://bar.com` - http URLで`foopy`HTTPプロキシを使い、`foopy`が提供されていなければ、SOCKS5 proxy `bar.com`を使います。 -* `http=foopy,direct://` -  http URLで`foopy`HTTPプロキシを使い、`foopy`が提供されていなければ、プロキシを使いません。 -* `http=foopy;socks=foopy2` - http URLで`foopy`HTTPプロキシを使い、それ以外のすべてのURLで`socks4://foopy2`を使います。 - -### `ses.resolveProxy(url, callback)` - -* `url` URL -* `callback` Function - -`url`をプロキシ情報で解決します。リクエストが実行された時、`callback(proxy)`で `callback`がコールされます。 - -#### `ses.setDownloadPath(path)` - -* `path` String - ダウンロード場所 - -ダウンロードの保存ディレクトリを設定します。既定では、ダウンロードディレクトリは、個別のアプリフォルダー下の`Downloads`です。 - -#### `ses.enableNetworkEmulation(options)` - -* `options` Object - * `offline` Boolean - ネットワーク停止を再現するかどうか - * `latency` Double - RTT ms秒 - * `downloadThroughput` Double - Bpsでのダウンロード割合 - * `uploadThroughput` Double - Bpsでのアップロード割合 - -再現ネットワークは、`session`用の設定を付与します。 - -```javascript -// To emulate a GPRS connection with 50kbps throughput and 500 ms latency. -window.webContents.session.enableNetworkEmulation({ - latency: 500, - downloadThroughput: 6400, - uploadThroughput: 6400 -}); - -// To emulate a network outage. -window.webContents.session.enableNetworkEmulation({offline: true}); -``` - -#### `ses.disableNetworkEmulation()` - -`session`ですでに有効になっているネットワークエミュレーションを無効化します。オリジナルのネットワーク設定にリセットします。 - -#### `ses.setCertificateVerifyProc(proc)` - -* `proc` Function - -`session`の証明書検証ロジックを設定し、サーバー証明書確認がリクエストされた時、`proc(hostname, certificate, callback)`で`proc`がコールされます。`callback(true)`がコールされると証明書を受け入れ、`callback(false)`がコールされると拒否します。 - -Calling `setCertificateVerifyProc(null)`をコールして、既定の証明書検証ロジックに戻します。 - -```javascript -myWindow.webContents.session.setCertificateVerifyProc(function(hostname, cert, callback) { - if (hostname == 'github.com') - callback(true); - else - callback(false); -}); -``` - -#### `ses.webRequest` - -`webRequest`APIセットをインターセプトし、そのライフタイムの様々な段階でリクエストの内容を変更できます。 - -APIのイベントが発生したとき、それぞれのAPIはオプションで`filter`と `listener`を受け入れ、`listener(details)` で`listener`がコールされ、`details`はリクエストを説明するオブジェクトです。`listener`に`null`が渡されるとイベントの購読をやめます。 - -`filter`は`urls`プロパティを持つオブジェクトで、URLパターンにマッチしないリクエストを除外するのに使われるURLパターンの配列です。`filter`を省略した場合、全てのリクエストにマッチします。 - -いくつかのイベントで`callback`で`listener`に渡され、`listener`が動作するとき、`response`オブジェクトでコールされる必要があります。 - -```javascript -// Modify the user agent for all requests to the following urls. -var filter = { - urls: ["https://*.github.com/*", "*://electron.github.io"] -}; - -session.defaultSession.webRequest.onBeforeSendHeaders(filter, function(details, callback) { - details.requestHeaders['User-Agent'] = "MyAgent"; - callback({cancel: false, requestHeaders: details.requestHeaders}); -}); -``` - -#### `ses.webRequest.onBeforeRequest([filter, ]listener)` - -* `filter` Object -* `listener` Function - -リクエストが発生しようとしている時、`listener(details, callback)`で`listener` がコールされます。 - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `uploadData` Array (オプション) - * `callback` Function - -`uploadData`は `data`オブジェクトの配列です。 - -* `data` Object - * `bytes` Buffer - 送信されるコンテンツ - * `file` String - アップロードされるファイルパス - -`callback`は`response`オブジェクトでコールされる必要があります: - -* `response` Object - * `cancel` Boolean (オプション) - * `redirectURL` String (オプション) - オリジナルリクエストが送信もしくは完了するのを中断し、代わりに付与したURLにリダイレクトします。 - -#### `ses.webRequest.onBeforeSendHeaders([filter, ]listener)` - -* `filter` Object -* `listener` Function - -リクエストヘッダーが提供されれば、HTTPリクエストが送信される前に、`listener(details, callback)`で`listener`がコールされます。TCP接続がサーバーに対して行われた後に発生することがありますが、HTTPデータは送信前です。 - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `requestHeaders` Object -* `callback` Function - -The `callback` has to be called with an `response` object: - -* `response` Object - * `cancel` Boolean (オプション) - * `requestHeaders` Object (オプション) - 付与されると、リクエストはそれらのヘッダーで作成されます。 - -#### `ses.webRequest.onSendHeaders([filter, ]listener)` - -* `filter` Object -* `listener` Function - -サーバーにリクエストを送信しようする直前に`listener(details)`で、`listener` がコールされます。前回の`onBeforeSendHeaders`レスポンスの変更箇所は、このリスナーが起動した時点で表示されます。 - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `requestHeaders` Object - -#### `ses.webRequest.onHeadersReceived([filter,] listener)` - -* `filter` Object -* `listener` Function - -リクエストのHTTPレスポンスヘッダーを受信したとき、`listener`は`listener(details, callback)`でコールされます。 - -* `details` Object - * `id` String - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `statusLine` String - * `statusCode` Integer - * `responseHeaders` Object -* `callback` Function - -`callback`は`response`オブジェクトでコールされる必要があります: - -* `response` Object - * `cancel` Boolean - * `responseHeaders` Object (オプション) - 付与されていると、これらのヘッダーでサーバーはレスポンスしたと仮定します。 - -#### `ses.webRequest.onResponseStarted([filter, ]listener)` - -* `filter` Object -* `listener` Function - -レスポンスボディの最初のバイトを受信したとき、`listener` は`listener(details)` でコールされます。HTTPリクエストでは、ステータス行とレスポンスヘッダーを意味します。 - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `responseHeaders` Object - * `fromCache` Boolean -ディスクキャッシュから取得したレスポンスかどうかを示します - * `statusCode` Integer - * `statusLine` String - -#### `ses.webRequest.onBeforeRedirect([filter, ]listener)` - -* `filter` Object -* `listener` Function - -サーバーがリダイレクトを開始しはじめたとき、`listener(details)`で`listener` がコールされます。 - -* `details` Object - * `id` String - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `redirectURL` String - * `statusCode` Integer - * `ip` String (オプション) - 実際にリクエストが送信されるサーバーIPアドレス - * `fromCache` Boolean - * `responseHeaders` Object - -#### `ses.webRequest.onCompleted([filter, ]listener)` - -* `filter` Object -* `listener` Function - -リクエスト完了時、`listener`が`listener(details)`でコールされます。 - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `responseHeaders` Object - * `fromCache` Boolean - * `statusCode` Integer - * `statusLine` String - -#### `ses.webRequest.onErrorOccurred([filter, ]listener)` - -* `filter` Object -* `listener` Function - -エラー発生時、 `listener(details)` で`listener`がコールされます。 - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `fromCache` Boolean - * `error` String - エラーの説明 diff --git a/docs-translations/jp/api/shell.md b/docs-translations/jp/api/shell.md deleted file mode 100644 index 744b5747abdd6..0000000000000 --- a/docs-translations/jp/api/shell.md +++ /dev/null @@ -1,43 +0,0 @@ -# shell - -`shell`モジュールはデスクトップ統合に関係した機能を提供します。 - -ユーザーのデフォルトのブラウザでURLを開く例です: - -```javascript -const shell = require('electron').shell; - -shell.openExternal('https://github.com'); -``` - -## メソッド - -`shell`モジュールは次のメソッドを持ちます: - -### `shell.showItemInFolder(fullPath)` - -* `fullPath` String - -ファイルマネジャーでファイルを表示します。もし可能ならファイルを選択します。 - -### `shell.openItem(fullPath)` - -* `fullPath` String - -デスクトップの既定のやり方で指定したファイルを開きます。 - -### `shell.openExternal(url)` - -* `url` String - -デスクトップの既定のやり方で指定した外部のプロトコルURLで開きます。(例えば、mailto:URLでユーザーの既定メールエージェントを開きます) - -### `shell.moveItemToTrash(fullPath)` - -* `fullPath` String - -ゴミ箱へ指定したファイルを移動し、操作結果をブーリアン値を返します。 - -### `shell.beep()` - -ビープ音を再生します。 diff --git a/docs-translations/jp/api/synopsis.md b/docs-translations/jp/api/synopsis.md deleted file mode 100644 index fdbdb16059030..0000000000000 --- a/docs-translations/jp/api/synopsis.md +++ /dev/null @@ -1,65 +0,0 @@ -# 概要 - -> どうやってNode.jsとElectronのAPIを使うか。 - -Electron では全ての [Node.js のビルトインモジュール](http://nodejs.org/api/) 利用可能です。また、サードパーティの Node モジュール ([ネイティブモジュール](../tutorial/using-native-node-modules.md)も含む) も完全にサポートされています。 - -Electron はネイティブのデスクトップアプリケーション開発のための幾つかの追加のビルトインモジュールも提供しています。メインプロセスでだけ使えるモジュールもあれば、レンダラプロセス(ウェブページ)でだけ使えるモジュール、あるいはメインプロセス、レンダラプロセスどちらでも使えるモジュールもあります。 - -基本的なルールは:[GUI][gui]、または低レベルのシステムに関連するモジュールはメインモジュールでだけ利用できるべきです。これらのモジュールを使用できるようにするためには [メインプロセス対レンダラプロセス](../tutorial/quick-start.md#メインプロセス)スクリプトの概念を理解する必要があります。 - -メインプロセススクリプトは普通の Node.js スクリプトのようなものです: - -```javascript -const {app, BrowserWindow} = require('electron'); - -let win = null; - -app.on('ready', () => { - win = new BrowserWindow({width: 800, height: 600}); - win.loadURL('https://github.com'); -}); -``` - -レンダラプロセスは Node モジュールを使うための追加機能を除いて、通常のウェブページとなんら違いはありません: - -```html - - - - - - -``` - -アプリケーションを実行については、[アプリを実行する](../tutorial/quick-start.md#アプリを実行する)を参照してください。 - -## 分割代入 - -0.37の時点で、 、[分割代入][desctructuring-assignment]でビルトインモジュールの使用をより簡単にできます: - -```javascript -const {app, BrowserWindow} = require('electron'); -``` - -もし`electron`モジュール全体が必要であれば、requireして、それぞれのモジュールを`electron`からアクセスすることができます。 - -```javascript -const electron = require('electron'); -const {app, BrowserWindow} = electron; -``` - -これは、次のコードと同じ意味を持ちます。 - -```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; -``` - -[gui]: https://en.wikipedia.org/wiki/Graphical_user_interface -[desctructuring-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment -[issue-387]: https://github.com/electron/electron/issues/387 diff --git a/docs-translations/jp/api/system-preferences.md b/docs-translations/jp/api/system-preferences.md deleted file mode 100644 index aa78d2e880a47..0000000000000 --- a/docs-translations/jp/api/system-preferences.md +++ /dev/null @@ -1,93 +0,0 @@ -# systemPreferences - -> システムの環境設定を取得します。 - -```javascript -const {systemPreferences} = require('electron') -console.log(systemPreferences.isDarkMode()) -``` - -## メソッド - -### `systemPreferences.isDarkMode()` _macOS_ - -macOS がダークモードならば `true` を返し、通常モードなら `false` を返します。 - -### `systemPreferences.subscribeNotification(event, callback)` _macOS_ - -* `event` String -* `callback` Function - -macOS のネイティブな通知を購読します。 `callback` は `callback(event, userInfo)` として `event` の発生に対応して呼ばれます。`userInfo` は通知によって送られてくるユーザー情報のオブジェクトです。 - -この関数が返す `id` は `event`の購読をやめる際に使用します。 - -内部ではこの API は `NSDistributedNotificationCenter` を購読するので、`event` の例は以下のようなものがあります。 - -* `AppleInterfaceThemeChangedNotification` -* `AppleAquaColorVariantChanged` -* `AppleColorPreferencesChangedNotification` -* `AppleShowScrollBarsSettingChanged` - -### `systemPreferences.unsubscribeNotification(id)` _macOS_ - -* `id` Integer - -`id` の購読をやめます。 - -### `systemPreferences.subscribeLocalNotification(event, callback)` _macOS_ - -`subscribeNotification` と同じですが、 `NSNotificationCenter` を購読します。下記のような `event` を捕まえるために必要です。 - -* `NSUserDefaultsDidChangeNotification` - -### `systemPreferences.unsubscribeLocalNotification(id)` _macOS_ - -`unsubscribeNotification` と同じですが、`NSNotificationCenter` による購読をやめます。 - -### `systemPreferences.getUserDefault(key, type)` _macOS_ - -* `key` String -* `type` String - 右記の値を入れられます `string`, `boolean`, `integer`, `float`, `double`, - `url`, `array`, `dictionary` - -システム環境設定の `key` の値を取得します。 - -この API は macOS の `NSUserDefaults` から情報を取得します。よく使われる `key` 及び `type` には下記のものがあります。 - -* `AppleInterfaceStyle: string` -* `AppleAquaColorVariant: integer` -* `AppleHighlightColor: string` -* `AppleShowScrollBars: string` -* `NSNavRecentPlaces: array` -* `NSPreferredWebServices: dictionary` -* `NSUserDictionaryReplacementItems: array` - -### `systemPreferences.isAeroGlassEnabled()` _Windows_ -[DWM composition][dwm-composition] (Aero Glass) が有効だと `true` を返し、そうでないと `false` を返します。 - -使用例として、例えば透過ウィンドウを作成するかしないか決めるときに使います(DWM composition が無効だと透過ウィンドウは正常に動作しません) - -```javascript -const {BrowserWindow, systemPreferences} = require('electron') -let browserOptions = {width: 1000, height: 800} - -// プラットフォームがサポートしている場合に限り透過ウィンドウを作成します。 -if (process.platform !== 'win32' || systemPreferences.isAeroGlassEnabled()) { - browserOptions.transparent = true - browserOptions.frame = false -} - -// ウィンドウを作成 -let win = new BrowserWindow(browserOptions) - -// 分岐 -if (browserOptions.transparent) { - win.loadURL(`file://${__dirname}/index.html`) -} else { - // 透過がサポートされてないなら、通常のスタイルの html を表示する - win.loadURL(`file://${__dirname}/fallback.html`) -} -``` - -[dwm-composition]:https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx diff --git a/docs-translations/jp/api/tray.md b/docs-translations/jp/api/tray.md deleted file mode 100644 index a26f6c59741a4..0000000000000 --- a/docs-translations/jp/api/tray.md +++ /dev/null @@ -1,199 +0,0 @@ -# Tray - -`Tray`は、オペレーティングシステムの通知エリアでアイコンで表示され、通常コンテキストメニューが付随します。 - -```javascript -const electron = require('electron'); -const app = electron.app; -const Menu = electron.Menu; -const Tray = electron.Tray; - -var appIcon = null; -app.on('ready', function(){ - appIcon = new Tray('/path/to/my/icon'); - var contextMenu = Menu.buildFromTemplate([ - { label: 'Item1', type: 'radio' }, - { label: 'Item2', type: 'radio' }, - { label: 'Item3', type: 'radio', checked: true }, - { label: 'Item4', type: 'radio' } - ]); - appIcon.setToolTip('This is my application.'); - appIcon.setContextMenu(contextMenu); -}); - -``` - -__プラットフォームの制限:__ - -* Linuxでは、サポートしている場合アプリインディケーターが使われ、サポートされていなければ代わりに`GtkStatusIcon`が使われます。 -* アプリインディケーターを持っているLinuxディストリビューションでは、トレイアイコンを動作させるために`libappindicator1`をインストールする必要があります。 -* コンテキストメニューがあるときは、インディケーターのみが表示されます。 -* アプリインディケーターがLinuxで使われると、`click`イベントは無視されます。 - -すべてのプラットフォームで正確に同じ挙動を維持したい場合は、`click`イベントに依存せず、常にトレイアイコンにコンテキストメニューを付随させるようにします。 - -## クラス: Tray - -`Tray`は[EventEmitter][event-emitter]です。 - -### `new Tray(image)` - -* `image` [NativeImage](native-image.md) - -`image`で新しいトレイアイコンを作成します。 - -## イベント - -`Tray`モジュールは次のイベントを出力します。 - -**Note:** いくつかのイベントは、特定のオペレーティングシステム向けに提供され、そのようにラベルで表示します。 - -### イベント: 'click' - -* `event` Event - * `altKey` Boolean - * `shiftKey` Boolean - * `ctrlKey` Boolean - * `metaKey` Boolean -* `bounds` Object - トレイアイコンのバウンド - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -トレイアイコンがクリックされたときに出力されます。 - -__Note:__ `バウンド` 再生はmacOSとWindoesのみで実装されています。 - -### イベント: 'right-click' _macOS_ _Windows_ - -* `event` Event - * `altKey` Boolean - * `shiftKey` Boolean - * `ctrlKey` Boolean - * `metaKey` Boolean -* `bounds` Object - トレイアイコンのバウンド - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -トレイアイコンが右クリックされると出力されます。 - -### イベント: 'double-click' _macOS_ _Windows_ - -* `event` Event - * `altKey` Boolean - * `shiftKey` Boolean - * `ctrlKey` Boolean - * `metaKey` Boolean -* `bounds` Object - トレイアイコンのバウンド - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -トレイアイコンがダブルクリックされたら出力されます。 - -### イベント: 'balloon-show' _Windows_ - -トレイバルーンを表示したときに出力されます。 - -### イベント: 'balloon-click' _Windows_ - -トレイバルーンがクリックされたときに出力されます。 - -### イベント: 'balloon-closed' _Windows_ - -タイムアウトもしくはユーザーの操作で閉じて、トレイバルーンがクロースされたときに出力されます。 - -### イベント: 'drop' _macOS_ - -トレイアイコンでアイテムがドラグアンドドロップされたときに出力されます。 - -### イベント: 'drop-files' _macOS_ - -* `event` -* `files` Array - ドロップされたアイテムのフルパス - -トレイアイコンでファイルがドロップされたときに出力されます。 - -### イベント: 'drag-enter' _macOS_ - -トレイアイコンにドラッグ操作が入ったときに出力されます。 - -### イベント: 'drag-leave' _macOS_ - -トレイアイコンででドラッグ操作が行われたときに出力されます。 - -### イベント: 'drag-end' _macOS_ - -トレイ上でドラッグ操作が終了したか、ほかの場所で終了したときに出力されます。 - -## Methods - -`Tray`モジュールは次のメソッドを持ちます。 - -**Note:** いくつかのメソッドは、特定のオペレーティングシステム向けに提供され、そのようにラベルで表示します。 - -### `Tray.destroy()` - -ただちにトレイアイコンを終了します。 - -### `Tray.setImage(image)` - -* `image` [NativeImage](native-image.md) - -トレイアイコンの`image`を設定します。 - -### `Tray.setPressedImage(image)` _macOS_ - -* `image` [NativeImage](native-image.md) - -macOSで押されたときにトレイアイコンの`image`を設定します。 - -### `Tray.setToolTip(toolTip)` - -* `toolTip` String - -トレイアイコン用のホバーテキストを設定します。 - -### `Tray.setTitle(title)` _macOS_ - -* `title` String - -ステータスバーで、トレイアイコンのわきに表示するタイトルを設定します。 - -### `Tray.setHighlightMode(highlight)` _macOS_ - -* `highlight` Boolean - -トレイアイコンがクリックされた時、トレイアイコンの背景をハイライト(青色)するかどうかを設定します。既定ではTrueです。 - -### `Tray.displayBalloon(options)` _Windows_ - -* `options` Object - * `icon` [NativeImage](native-image.md) - * `title` String - * `content` String - -トレイバルーンを表示します。 - -### `Tray.popUpContextMenu([menu, position])` _macOS_ _Windows_ - -* `menu` Menu (optional) -* `position` Object (optional) - ポップアップ位置 - * `x` Integer - * `y` Integer - -トレイアイコンのコンテキストメニューをポップアップします。`menu`が渡されたとき、`menu`はトレイコンテキストメニューの代わりに表示されます。 - -`position`はWindowsのみで提供され、既定では(0, 0) です。 - -### `Tray.setContextMenu(menu)` - -* `menu` Menu - -アイコン用のコンテキストメニューを設定します。 - -[event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter diff --git a/docs-translations/jp/api/web-frame.md b/docs-translations/jp/api/web-frame.md deleted file mode 100644 index 75e8ab4a5a9f9..0000000000000 --- a/docs-translations/jp/api/web-frame.md +++ /dev/null @@ -1,100 +0,0 @@ -# webFrame - -`web-frame`モジュールは現在のウェブページンのレンダリングのカスタマイズをできるようにします。 - -現在のページの倍率を200%にする例です。 - -```javascript -var webFrame = require('electron').webFrame; - -webFrame.setZoomFactor(2); -``` - -## メソッド - -`web-frame`モジュールは次のメソッドを持ちます: - -### `webFrame.setZoomFactor(factor)` - -* `factor` Number - 拡大倍数 - -指定した倍数に拡大倍数を変更します。拡大倍数は、拡大率を100で割った数字なので、300%だと3.0です。 - -### `webFrame.getZoomFactor()` - -現在の拡大倍数を返します。 - -### `webFrame.setZoomLevel(level)` - -* `level` Number - 拡大レベル - -指定したレベルに拡大レベルを変更します。オリジナルサイズは0で、1 つ上下させると20%拡大か縮小になり、既定の制限ではオリジナルサイズの300%と50%です。 - -### `webFrame.getZoomLevel()` - -返事あの拡大レベルを返します。 - -### `webFrame.setZoomLevelLimits(minimumLevel, maximumLevel)` - -* `minimumLevel` Number -* `maximumLevel` Number - -最大と最小の拡大レベルを設定します。 - -### `webFrame.setSpellCheckProvider(language, autoCorrectWord, provider)` - -* `language` String -* `autoCorrectWord` Boolean -* `provider` Object - -inputフィールドやtextエリアでスペルチェックの提供を設定します。 - -`provider`は、単語が正しいスペルかどうかを返す`spellCheck`メソッドを持つオブジェクトでなければなりません。 - - -プロバイダーとして[node-spellchecker][spellchecker]を使用する例です: - -```javascript -webFrame.setSpellCheckProvider("en-US", true, { - spellCheck: function(text) { - return !(require('spellchecker').isMisspelled(text)); - } -}); -``` - -### `webFrame.registerURLSchemeAsSecure(scheme)` - -* `scheme` String - -セキュアなスキーマーとして`scheme`を登録します。 - -セキュアなスキーマーは、今テンスの混在警告をトリガーしません。例えば、アクティブなネットワーク攻撃では破壊できないので`https`と`data`はセキュアなスキーマーです。 - -### `webFrame.registerURLSchemeAsBypassingCSP(scheme)` - -* `scheme` String - -リソースは現在のページのコンテンツセキュリティポリシーにかかわらず `scheme`からロードします。 - -### `webFrame.registerURLSchemeAsPrivileged(scheme)` - -* `scheme` String - -セキュアとして`scheme`を登録し、リソースの今テンスセキュリティポリシーを回避して、ServiceWorkerの登録とAPIのフェッチをサポートします。 - -### `webFrame.insertText(text)` - -* `text` String - -フォーカスが当たっているエレメントに`text`を挿入します。 - -### `webFrame.executeJavaScript(code[, userGesture])` - -* `code` String -* `userGesture` Boolean (オプション) - 既定では`false`です。 - -ページで`code`を評価します。 - -ブラウザウィンドウで、 `requestFullScreen`のようないくつかのHTML APIは、ユーザージェスチャーによってのみ起動できます。`userGesture`を`true` に設定すると、この制限は削除されます。 - -[spellchecker]: https://github.com/atom/node-spellchecker diff --git a/docs-translations/jp/api/web-view-tag.md b/docs-translations/jp/api/web-view-tag.md deleted file mode 100644 index e70f84f2d2587..0000000000000 --- a/docs-translations/jp/api/web-view-tag.md +++ /dev/null @@ -1,745 +0,0 @@ -# `` タグ - -> 外部ウェブコンテンツを別のプロセスとフレームで表示します。 - -Electronアプリ内でウェブページのような外部コンテンツを埋め込む際は、`webview`タグを使用してください。外部コンテンツは`webview`コンテナ内に閉じ込められます。 -アプリケーションの埋め込みページは、外部コンテンツがどのように表示されるかを制御することができます。 - -`iframe`と違い、`webview`はあなたのアプリと別のプロセスで動作します。あなたのウェブページとは違う実行許可レベルを持っており、あなたのアプリと埋め込みコンテンツの間のデータのやり取りは非同期で行われます。これにより、あなたのアプリケーションは埋め込みコンテンツからの安全が確保されます。 - -セキュリティ的な理由で、`webview`は`nodeIntegration`が有効な`BrowserWindow`でしか使用できません。 - -## 例 - -ウェブページをあなたのアプリに埋め込むには、`webview`タグをあなたの埋め込みページ(外部コンテンツを表示するアプリのページ)に追加してください。 -もっとも単純な方法では、`webview`タグはウェブページの`src`と、見た目を制御する`style`を持っています。 - -```html - -``` - -もし、外部コンテンツを制御したい場合、`webview`イベントを受け取り、`webview`メソッドでそれらのイベントに返答するJavaScriptコードを書くことになります。 -下記にあるのはウェブページの読み込みが開始した時と、止まった時にイベントを受け取るサンプルで、読み込み中に"loading..."というメッセージを表示します。 - -```html - -``` - -## CSS Styling Notes - -もし、flexbox layouts(v.0.36.11以降)を使用する場合は、`webview`タグは子`object`要素が`webview`自体の高さと幅いっぱいとなるよう、内部で`display: flex;`を使用しているのに注意してください。 -インラインレイアウトとしたい時に`display: inline-flex;`を指定する以外には、この`display: flex;`は上書きしないでください。 - -`webview`は`hidden`属性か、`display: none;`と使用して非表示にする際に、いくつか問題があります。 -`browserplugin`オブジェクトの中での描画や、ウェブページを再度表示するために再読み込みした際などに通常とは異なる描画となる場合があります。 -`webview`を隠すオススメの方法としては、`width`と`height`をゼロに設定し、`flex`を通じて、0pxまで小さくできるようにします。 - -```html - -``` - -## Tag 属性 - -`webview`タグは下記のような属性を持っています: - -### `src` - -```html - -``` - -表示されているURLを返します。本属性への書き込みは、トップレベルナビゲーションを開始させます。 - -`src`の値を現在の値に再度設定することで、現在のページを再読み込みさせることができます。 - -また、`src`属性はdata URLを指定することができます(例: `data:text/plain,Hello, world!`)。 - -### `autosize` - -```html - -``` - -"on"の際は、`minwidth`, `minheight`, `maxwidth`, `maxheight`で設定された範囲内で、自動的に大きさが変化します。 -これらの制限値は、`autosize`が有効でない場合は影響しません。 -`autosize`が有効の際は、`webview`コンテナサイズは指定した最小値より小さくなりませんし、最大値より大きくなりません。 - -### `nodeintegration` - -```html - -``` - -"on"の際は、`webview`内のゲストページ(外部コンテンツ)でnode integrationが有効となり、`require`や`process`と行ったnode APIでシステムリソースにアクセスできるようになります。1 - -**注意:** 親ウィンドウでnode integrationが無効の場合は、`webview`でも常に無効になります。 - - -### `plugins` - -```html - -``` - -"on"の際は、ゲストページはブラウザプラグインを使用できます。 - -### `preload` - -```html - -``` - -ゲストページ上のスクリプトより先に実行されるスクリプトを指定してください。内部では、ゲストページ内で`require`で読み込まれるので、スクリプトのURLのプロトコルはは`file:`または`asar:`でなければなりません。 - -ゲストページがnode integrationが無効の場合でも、このスクリプトは全てのNode APIにアクセスできます。ただし、グローバルオブジェクトはこのスクリプトの実行終了後にすべて削除されます。 - -### `httpreferrer` - -```html - -``` - -ゲストページのためにリファラを設定します。 - -### `useragent` - -```html - -``` - -ページ遷移の前に、User agentを指定します。すでにページが読み込まれている場合は、`setUserAgent`メソッドを利用して変更してください。 - -### `disablewebsecurity` - -```html - -``` - -"on"の際は、ゲストページのウェブセキュリティは無効となります。 - -### `partition` - -```html - - -``` - -ページで使用されるセッションを設定します。もし、`partition`が`persist:`から始まる場合、アプリ上の同じ`partition`を指定した全てのページで有効な永続セッションを使用します。 -`persist:`接頭辞なしで指定した場合、メモリ内セッションを使用します。同じセッションを指定すると複数のページで同じセッションを使用できます。 -`partition`を設定しない場合は、アプリケーションのデフォルトセッションが使用されます。 - -レンダラプロセスのセッションは変更できないため、この値は最初のページ遷移の前に変更されないといけません。 -その後に変更をしようとしても、DOM例外を起こすことになります。 - -### `allowpopups` - -```html - -``` - -"on"の場合、ゲストページは新しいウィンドウを開くことができます。 - -### `blinkfeatures` - -```html - -``` - -有効にしたいblink featureを`,`で区切って指定します。 -サポートされている全ての機能は、[setFeatureEnabledFromString][blink-feature-string]にリストがあります。 - -## メソッド - -`webview`タグは、下記のようなメソッドを持っています: - -**注意:** webview要素はメソッドを使用する前に読み込まれていないといけません。 - -**例** - -```javascript -webview.addEventListener('dom-ready', () => { - webview.openDevTools(); -}); -``` - -### `.loadURL(url[, options])` - -* `url` URL -* `options` Object (optional) - * `httpReferrer` String - リファラURL - * `userAgent` String - リクエストに使用されるUser agent - * `extraHeaders` String - 追加のヘッダを"\n"で区切って指定します。 - -`url`をwebviewで読み込みます。`url`はプロトコル接頭辞(`http://`や`file://`など)を含んでいなければいけません。 - -### `.getURL()` - -ゲストページのURLを取得します。 - -### `.getTitle()` - -ゲストページのタイトルを返します。 - -### `.isLoading()` - -ゲストページが読み込み中かのbool値を返します。 - -### `.isWaitingForResponse()` - -ゲストページがページの最初の返答を待っているかのbool値を返します。 - -### `.stop()` - -実行待ち中のナビゲーションを中止します。 - -### `.reload()` - -ゲストページを再読み込みします。 - -### `.reloadIgnoringCache()` - -キャッシュを無効にして再読み込みします。 - -### `.canGoBack()` - -ページを戻ることができるかのbool値を返します。 - -### `.canGoForward()` - -ページを進むことができるかのbool値を返します。 - -### `.canGoToOffset(offset)` - -* `offset` Integer - -`offset`だけ、移動できるかのbool値を返します。 - -### `.clearHistory()` - -移動履歴をクリアします。 - -### `.goBack()` - -ページを戻ります。 - -### `.goForward()` - -ページを進みます。 - -### `.goToIndex(index)` - -* `index` Integer - -インデックスを指定して移動します。 - -### `.goToOffset(offset)` - -* `offset` Integer - -現在の場所からの移動量を指定して移動します。 - -### `.isCrashed()` - -レンダラプロセスがクラッシュしているかを返します。 - -### `.setUserAgent(userAgent)` - -* `userAgent` String - -ゲストページ用のUser agentを変更します。 - -### `.getUserAgent()` - -User agentを取得します。 - -### `.insertCSS(css)` - -* `css` String - -ゲストエージにCSSを追加します。 - -### `.executeJavaScript(code, userGesture, callback)` - -* `code` String -* `userGesture` Boolean - Default `false`. -* `callback` Function (optional) - Called after script has been executed. - * `result` - -ページ内で`code`を評価します。`userGesture`を設定した場合、ページ内でgesture contextを作成します。例えば`requestFullScreen`のようなユーザーの対応が必要なHTML APIでは、自動化時にこれが有利になる時があります。 - -### `.openDevTools()` - -DevToolsを開きます。 - -### `.closeDevTools()` - -DevToolsを閉じます。 - -### `.isDevToolsOpened()` - -DevToolsが開いているかのbool値を返します。 - -### `.isDevToolsFocused()` - -DevToolsがフォーカスを得ているかのbool値を返します。 - -### `.inspectElement(x, y)` - -* `x` Integer -* `y` Integer - -ゲストページの(`x`, `y`)の位置にある要素を調べます。 - -### `.inspectServiceWorker()` - -ゲストページのサービスワーカーのDevToolsを開きます。 - -### `.setAudioMuted(muted)` - -* `muted` Boolean - -ページをミュートするかを設定します。 - -### `.isAudioMuted()` - -ページがミュートされているかを返します。 - -### `.undo()` - -`undo` (元に戻す)を行います。 -Executes editing command `undo` in page. - -### `.redo()` - -`redo` (やり直し)を行います。 - -### `.cut()` - -`cut` (切り取り)を行います。 - -### `.copy()` - -`copy` (コピー)を行います。 - -### `.paste()` - -`paste` (貼り付け)を行います。 - -### `.pasteAndMatchStyle()` - -`pasteAndMatchStyle`(貼り付けてスタイルを合わせる)を行います。 - -### `.delete()` - -`delete` (削除)を行います。 - -### `.selectAll()` - -`selectAll` (全て選択)を行います。 - -### `.unselect()` - -`unselect` (選択を解除)を行います。 - -### `.replace(text)` - -* `text` String - -`replace` (置き換え)を行います。 - -### `.replaceMisspelling(text)` - -* `text` String - -`replaceMisspelling` (スペル違いを置き換え)を行います。 - -### `.insertText(text)` - -* `text` String - -`text`を選択された要素に挿入します。 - -### `.findInPage(text[, options])` - -* `text` String - 検索する文字列(空文字列にはできません) -* `options` Object (省略可) - * `forward` Boolean - 前方・後方のどちらを検索するかどうかです。省略時は`true`で前方に検索します。 - * `findNext` Boolean - 初回検索か、次を検索するかを選びます。省略時は`false`で、初回検索です。 - * `matchCase` Boolean - 大文字・小文字を区別するかを指定します。省略時は`false`で、区別しません。 - * `wordStart` Boolean - ワード始まりからの検索かを指定します。省略時は`false`で、語途中でもマッチします。 - * `medialCapitalAsWordStart` Boolean - `wordStart`指定時、CamelCaseの途中もワード始まりと見なすかを指定します。省略時は`false`です。 - -`text`をページ内全てから検索し、リクエストに使用するリクエストID(`Integer`)を返します。リクエストの結果は、[`found-in-page`](web-view-tag.md#event-found-in-page)イベントを介して受け取ることができます。 - -### `.stopFindInPage(action)` - -* `action` String - [`.findInPage`](web-view-tag.md#webviewtagfindinpage)リクエストを終わらせる時にとるアクションを指定します。 - * `clearSelection` - 選択をクリアします。 - * `keepSelection` - 選択を通常の選択へと変換します。 - * `activateSelection` - 選択ノードにフォーカスを当て、クリックします。 - -`action`にしたがって`webview`への`findInPage`リクエストを中止します。 - -### `.print([options])` - -`webview`で表示されているウェブページを印刷します。`webContents.print([options])`と同じです。 - -### `.printToPDF(options, callback)` - -`webview`のウェブサイトをPDFとして印刷します。`webContents.printToPDF(options, callback)`と同じです。 - -### `.send(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (optional) - -`channel`を通じてレンダラプロセスに非同期メッセージを送ります。合わせて、 -任意のメッセージを送ることができます。レンダラプロセスは`ipcRenderer`モジュールを -使用して、`channel`イベントでメッセージを把握することができます。 - -サンプルが[webContents.send](web-contents.md#webcontentssendchannel-args)にあります。 - -### `.sendInputEvent(event)` - -* `event` Object - -入力イベント(`event`)をページに送ります。 - -`event`に関する詳しい説明は、[webContents.sendInputEvent](web-contents.md##webcontentssendinputeventevent)を -参照してください。 - -### `.getWebContents()` - -`webview`に関連付けられた[WebContents](web-contents.md)を取得します。 - -## DOM events - -`webview`タグで有効なイベントは次の通りです: - -### Event: 'load-commit' - -返り値: - -* `url` String -* `isMainFrame` Boolean - -読み込みが行われる時に発生するイベントです。 -これには、現在のドキュメントやサブフレームの読み込みが含まれます。ただし、非同期なリソース読み込みは含まれません。 - -### Event: 'did-finish-load' - -ナビゲーションが完了した際に発生するイベントです。 -言い換えると、タブ上の"くるくる"が止まった時に発生し、`onload`イベントが配信されます。 - -### Event: 'did-fail-load' - -返り値: - -* `errorCode` Integer -* `errorDescription` String -* `validatedURL` String -* `isMainFrame` Boolean - -`did-finish-load`と同じようですが、読み込みに失敗した時やキャンセルされた時に発生します。 -例えば、`window.stop()`が呼ばれた時などです。 - -### Event: 'did-frame-finish-load' - -返り値: - -* `isMainFrame` Boolean - -フレームがナビゲーションを終えた時に発生します。 - -### Event: 'did-start-loading' - -タブ上の"くるくる"が回転を始めた時点でこのイベントが発生します。 - -### Event: 'did-stop-loading' - -タブ上の"くるくる"が回転をやめた時点でこのイベントが発生します。 - -### Event: 'did-get-response-details' - -返り値: - -* `status` Boolean -* `newURL` String -* `originalURL` String -* `httpResponseCode` Integer -* `requestMethod` String -* `referrer` String -* `headers` Object -* `resourceType` String - -読み込むリソースの詳細がわかった時点で発生します。 -`status`は、リソースをダウンロードするソケット接続であるかを示します。 - -### Event: 'did-get-redirect-request' - -返り値: - -* `oldURL` String -* `newURL` String -* `isMainFrame` Boolean - -リソースの取得中に、リダイレクトを受け取った際に発生します。 - -### Event: 'dom-ready' - -該当フレーム内のドキュメントが読み込まれた時に発生します。 - -### Event: 'page-title-updated' - -返り値: - -* `title` String -* `explicitSet` Boolean - -ページのタイトルが設定された時に発生します。 -タイトルがurlから作られたものであれば、`explicitSet`は`false`になります。 - -### Event: 'page-favicon-updated' - -返り値: - -* `favicons` Array - URLの配列 - -ページのfavicon URLを受け取った時に発生します。 - -### Event: 'enter-html-full-screen' - -HTML APIでフルスクリーンになった際に発生します。 - -### Event: 'leave-html-full-screen' - -HTML APIでフルスクリーンでなくなった際に発生します。 - -### Event: 'console-message' - -返り値: - -* `level` Integer -* `message` String -* `line` Integer -* `sourceId` String - -ゲストウィンドウがコンソールメッセージを記録する際に発生します。 - -下記のサンプルは、埋め込まれたサイトのログを、log levelに関係なく親側に転送します。 - - -```javascript -webview.addEventListener('console-message', (e) => { - console.log('Guest page logged a message:', e.message); -}); -``` - -### Event: 'found-in-page' - -返り値: - -* `result` Object - * `requestId` Integer - * `finalUpdate` Boolean - 次のレスポンスが待っているかを示します。 - * `activeMatchOrdinal` Integer (optional) - このマッチの場所を示します。 - * `matches` Integer (optional) - マッチした数です。 - * `selectionArea` Object (optional) - 最初のマッチした場所です。 - -[`webview.findInPage`](web-view-tag.md#webviewtagfindinpage)リクエストで結果が得られた場合に発生します。 - -```javascript -webview.addEventListener('found-in-page', (e) => { - if (e.result.finalUpdate) - webview.stopFindInPage('keepSelection'); -}); - -const requestId = webview.findInPage('test'); -``` - -### Event: 'new-window' - -返り値: - -* `url` String -* `frameName` String -* `disposition` String -`default`, `foreground-tab`, `background-tab`, - `new-window`, `other`のどれかです。 -* `options` Object - 新しい`BrowserWindow`を作る際に使用されるoptionです。 - -ゲストページが新しいブラウザウィンドウを開こうとする際に発生します。 - -下記のサンプルは、新しいURLをシステムのデフォルトブラウザで開きます。 - -```javascript -const {shell} = require('electron'); - -webview.addEventListener('new-window', (e) => { - const protocol = require('url').parse(e.url).protocol; - if (protocol === 'http:' || protocol === 'https:') { - shell.openExternal(e.url); - } -}); -``` - -### Event: 'will-navigate' - -返り値: - -* `url` String - -ユーザーまたはページがナビゲーションを始めようとする際に発生します。これは、 -`window.location`が変更になる時や、ユーザーがリンクをクリックした際に発生します。 - -`.loadURL`や`.back`でプログラムによりナビゲーションが始まった場合は -このイベントは発生しません。 - -アンカーリンクのクリックや`window.location.hash`の変更といった、ページ内遷移でも、このイベントは発生しません。 -この場合は、`did-navigate-in-page`イベントを使ってください。 - -`event.preventDefault()`は使用しても__何も起こりません__。 - -### Event: 'did-navigate' - -返り値: - -* `url` String - -ナビゲーション終了時に呼ばれます。 - -アンカーリンクのクリックや`window.location.hash`の変更といった、ページ内遷移では、このイベントは発生しません。 -この場合は、`did-navigate-in-page`イベントを使ってください。 - -### Event: 'did-navigate-in-page' - -返り値: - -* `url` String - -ページ内遷移の際に発生します。 - -ページ内遷移の際は、ページURLは変更になりますが、ページ外部へのナビゲーションは発生しません。 -例として、アンカーリンクのクリック時や、DOMの`hashchange`イベントが発生した時にこれが起こります。 - -### Event: 'close' - -ゲストページそのものが、閉じられようとしている際に発生します。 - -下記のサンプルは、`webview`が閉じられる際に、`about:blank`にナビゲートします。 - -```javascript -webview.addEventListener('close', () => { - webview.src = 'about:blank'; -}); -``` - -### Event: 'ipc-message' - -返り値: - -* `channel` String -* `args` Array - -ゲストページが埋め込み元に非同期メッセージを送ってきた際に発生します。 - -`sendToHost`メソッドと、`ipc-message`イベントを利用すると、ゲストページと埋め込み元のページでデータのやり取りを簡単に行うことができます。 - -```javascript -// 埋め込み元ページ(があるページ)で -webview.addEventListener('ipc-message', (event) => { - console.log(event.channel); - // Prints "pong" -}); -webview.send('ping'); -``` - -```javascript -// ゲストページ(内)で -const {ipcRenderer} = require('electron'); -ipcRenderer.on('ping', () => { - ipcRenderer.sendToHost('pong'); -}); -``` - -### Event: 'crashed' - -プロセスがクラッシュした際に発生します。 - -### Event: 'gpu-crashed' - -GPUプロセスがクラッシュした際に発生します。 - -### Event: 'plugin-crashed' - -返り値: - -* `name` String -* `version` String - -プラグインプロセスがクラッシュした際に発生します。 - -### Event: 'destroyed' - -WebContentsが破壊された際に呼ばれます。 - -### Event: 'media-started-playing' - -メディアの再生が開始された際に呼ばれます。 - -### Event: 'media-paused' - -メディアが一時停止になるか、再生を終えた際に呼ばれます。 - -### Event: 'did-change-theme-color' - -返り値: - -* `themeColor` String - -ページのテーマカラーが変更になった際に呼ばれます。 -これは、下記のようなメタタグがある際に通常発生します: - -```html - -``` - -### Event: 'devtools-opened' - -DevToolsが開かれた際に発生します。 - -### Event: 'devtools-closed' - -DevToolsが閉じられた際に発生します。 - -### Event: 'devtools-focused' - -DevToolsにフォーカスが当たった際 / 開かれた際に発生します。 - -[blink-feature-string]: https://code.google.com/p/chromium/codesearch#chromium/src/out/Debug/gen/blink/platform/RuntimeEnabledFeatures.cpp&sq=package:chromium&type=cs&l=527 diff --git a/docs-translations/jp/api/window-open.md b/docs-translations/jp/api/window-open.md deleted file mode 100644 index 3cf0954a82c93..0000000000000 --- a/docs-translations/jp/api/window-open.md +++ /dev/null @@ -1,59 +0,0 @@ -# `window.open` 関数 - -Webページで新しいウィンドウを作成するために`window.open`をコールすると、`url`用の`BrowserWindow`の新しいインスタンスが作成され、プロキシはそれ以上の制御を制限したページを許可する`window.open`を返します。 - -プロキシは伝統的なウェブページと互換性のある制限された標準的な機能が実装されています。新しいウィンドウの完全な制御のために、直接、`BrowserWindow`を作成する必要があります。 - -新しく作成された`BrowserWindow`は、既定で、親ウィンドウのオプションを継承し、`features`文字列で設定したオプションを継承しオーバーライドします。 - -### `window.open(url[, frameName][, features])` - -* `url` String -* `frameName` String (optional) -* `features` String (optional) - -新しいウィンドウを作成し、`BrowserWindowProxy` クラスのインスタンを返します。 - - `features`文字列は標準的なブラウザーのフォーマットに従いますが、それぞれの機能は`BrowserWindow`のオプションフィールドである必要があります。 - -### `window.opener.postMessage(message, targetOrigin)` - -* `message` String -* `targetOrigin` String - -優先的なオリジンなく特定のオリジンまたは`*`で親ウィンドウにメッセージが送信されます。 - -## Class: BrowserWindowProxy - -`BrowserWindowProxy`オブジェクトは`window.open`から返り、子ウィンドウに制限された機能を提供します。 - -### `BrowserWindowProxy.blur()` - -子ウィンドウからフォーカスを削除します。 - -### `BrowserWindowProxy.close()` - -アンロードイベントをコールせず、強制的に子ウィンドウを閉じます。 - -### `BrowserWindowProxy.closed` - -子ウィンドウがクローズした後、trueを設定します。 - -### `BrowserWindowProxy.eval(code)` - -* `code` String - -子ウィンドウでコードを評価します。 - -### `BrowserWindowProxy.focus()` - -前面にウィンドウを出し、子ウィンドウにフォーカスします。 - -### `BrowserWindowProxy.postMessage(message, targetOrigin)` - -* `message` String -* `targetOrigin` String - -優先的なオリジンなく特定のオリジンまたは`*`で子ウィンドウにメッセージが送信されます。 - -それらのメッセージに加え、子ウィンドウはプロパティとシグナルメッセージなしで`window.opener`オブジェクトを実装します。 diff --git a/docs-translations/jp/development/atom-shell-vs-node-webkit.md b/docs-translations/jp/development/atom-shell-vs-node-webkit.md deleted file mode 100644 index 09a8621a24c91..0000000000000 --- a/docs-translations/jp/development/atom-shell-vs-node-webkit.md +++ /dev/null @@ -1,37 +0,0 @@ -# Electron と NW.js (node-webkit)の技術的違い - -__Note: Electron は以前は Atom Shell と呼ばれていました__ - -NW.js と同じように Electron は HTML と JavaScript でデスクトップアプリケーションを書くためのプラットフォームを提供しており、また web ページからローレベルなシステムにもアクセスできる Node との統合的な仕組みを持っていました。 - -しかし、2つのプロジェクトには根本的な違いがあり、Electron と NW.js は完全に別なプロダクトになりました。 - -__1. アプリケーションの開始__ - -NW.js ではアプリケーションは web ページから開始されます。 `package.json` にてアプリケーションのメインページURLを指定し、ブラウザウィンドウがそのページを開くことで、それがアプリケーションのメインウィンドウとなります。 - -Electron では、JavaScript のスクリプトがエントリポイントとなります。URLを直接指定するのではなく、自分でブラウザウィンドウを作成し、API を通して HTML ファイルを読み込みます。また、ウィンドウで発生するイベントを購読して、アプリケーションの終了をハンドリングする必要もあります。 - -Electron は Node.js ランタイムのように動作します。 Electron の API はローレベルなので、[PhantomJS](http://phantomjs.org/)の代わりにブラウザテストに使用することもできます。 - -__2. ビルドシステム__ - -Chromium の全てのコードをビルドする複雑さを回避するため、Electron は [`libchromiumcontent`](https://github.com/brightray/libchromiumcontent) を通して Chromium の Content API にアクセスします。 - -`libchromiumcontent` は Chromium の Content モジュールとそれに依存する全てを含んだ単一の共有ライブラリです。 -おかげで Electron をビルドするためにパワフルなマシンを用意する必要はありません。 - -__3. Node との統合__ - -NW.js では web ページと Node を統合するために Chromium にパッチを適用しています。一方、Electron では Chromium を改造する方法を取らず、libuv ループとプラットフォームのメッセージループを統合する方法を私達は取りました。 -何をやっているかについては、[`node_bindings`][node-bindings] を参照してください。 - -__4. Multi-context__ - -もしあなたが経験豊かな NW.js ユーザーならば、Node のコンテキストと Web のコンテキストに精通しているかと思います。これらのコンセプトは、NW.js の実装によって導入されたものです。 - -Node の [multi-context](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/) 機能によって、Electron は Web ページに新しい Javascript のコンテキストを導入しません。 - -Note: NW.js は バージョン 0.13 からオプションとして multi-context をサポートしました。 - -[node-bindings]: https://github.com/electron/electron/tree/master/atom/common diff --git a/docs-translations/jp/development/build-instructions-osx.md b/docs-translations/jp/development/build-instructions-osx.md deleted file mode 100644 index 2f766020ea99c..0000000000000 --- a/docs-translations/jp/development/build-instructions-osx.md +++ /dev/null @@ -1,62 +0,0 @@ -# ビルド方法 (macOS) - -macOS で Electron をビルドする際は以下のガイドラインに従って下さい - -## 前提条件 - -* macOS >= 10.8 -* [Xcode](https://developer.apple.com/technologies/tools/) >= 5.1 -* [node.js](http://nodejs.org) (external) - -Homebrew からダウンロードした Python を使用している場合、下記 python モジュールもインストールしてください - -* pyobjc - -## ソースコードの取得 - -```bash -$ git clone https://github.com/electron/electron.git -``` - -## bootstrap - -bootstrap スクリプトは、ビルドに必要な全ての依存関係の解決と、プロジェクトファイルを作成してくれます。Electron のビルドには [ninja](https://ninja-build.org/) を使用しているので、 Xcode project が生成されないことに注意してください。 - -```bash -$ cd electron -$ ./script/bootstrap.py -v -``` - -## ビルド - -`Release` 向けと `Debug` 向けを両方共ビルドするには下記を実行してください。 - -```bash -$ ./script/build.py -``` - -`Debug` 向けのみビルドしたい時は下記を実行してください。 - -```bash -$ ./script/build.py -c D -``` - -ビルドが終われば、`out/D` ディレクトリ配下に `Electron.app`が生成されます。 - -## 32bit サポート - -Electron は 64bit の macOS 向けのみビルドできます。32bit macOS への対応の予定はありません。 - -## テスト - -コーディング規約を満たしているかどうかは下記でテストできます。 - -```bash -$ ./script/cpplint.py -``` - -機能のテストは下記でテストできます。 - -```bash -$ ./script/test.py -``` diff --git a/docs-translations/jp/development/coding-style.md b/docs-translations/jp/development/coding-style.md deleted file mode 100644 index becd4f9c03ec1..0000000000000 --- a/docs-translations/jp/development/coding-style.md +++ /dev/null @@ -1,44 +0,0 @@ -# コーディング規約 - -Electron 開発におけるコーディング規約です。 - -`npm run lint` を実行することで `cpplint` 及び `eslint` によって -検出された規約違反を検出することができます。 - -## C++ と Python - -C++ と Python は Chromium の[コーディング規約](http://www.chromium.org/developers/coding-style)を踏襲しています。`script/cpplint.py` というスクリプトを実行することで、全てのファイルがこの規約に従っているかどうかチェックできます。 - -私達が今使っている Python のバージョンは Python 2.7 です。 - -C++ のコードは Chromium の抽象型をたくさん使っているので、それに精通していることをオススメします。Chromium の [Important Abstractions and Data Structures](https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures) のドキュメントから始めるのがよいでしょう。ドキュメントでは、いくつかの特別な型や、スコープのある型(スコープ外に出ると自動でメモリが開放される型)、ログの仕組みなどが言及されています。 - -## JavaScript - -* [standard](http://npm.im/standard) JavaScript style で書いてください。 -* ファイルは改行で**終わらないでください**。Google の規約と合わないためです。 -* ファイル名はアンダーバー `_` で結合せず、ハイフン `-` で結合してください。 - 例えば `file_name.js` ではなく `file-name.js` です。なぜかというと - [github/atom](https://github.com/github/atom) モジュールの名前が - `module-name` 形式だからです。このルールは `.js` ファイルのみ適用されます。 -* 必要に応じて新しい ES6/ES2015 の構文を使用してください。 - * [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) - を定数使用時に - * [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) - を変数宣言時に - * [Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - を `function () { }` の代わりに - * [Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) - を `+` を使って文字結合する代わりに - -## 名前付け - -Electron の API は Node.js と同じ大文字小文字のルールを使用しています。 - -- モジュールがクラスの場合は、`BrowserWindow` のようにキャメルケースを使います。 -- モジュールが API の一部なら `globalShortcut` のように小文字大文字を混ぜて使います(`mixedCase`)。 -- `win.webContents` のように API が オブジェクトのプロパティで、かつ分けると複雑になる場合は、小文字大文字を混ぜて使います(`mixedCase`)。 -- その他のモジュールでないAPIでは、` Tag` や `Process Object` のように通常通り名づけます。 - -新しい API を作る際は、jQuery のように一つの関数で getter/setter にするより、getter と setter を分ける方が望ましいです。 -例えば `.text([text])` ではなく `.getText()` と `.setText(text)` にします。この辺りは [issue 46](https://github.com/electron/electron/issues/46) で議論されました。 diff --git a/docs-translations/jp/faq/electron-faq.md b/docs-translations/jp/faq/electron-faq.md deleted file mode 100644 index 3991b71953cd0..0000000000000 --- a/docs-translations/jp/faq/electron-faq.md +++ /dev/null @@ -1,133 +0,0 @@ -# Electron FAQ - -## Electronは、いつ最新のChromeにアップグレードされますか? - -ElectronのChromeバージョンは、通常、新しいChromeのstabeleバージョンがリリースされた後、1~2週間以内に上げられます。ただし、この期間というのは保障されてはおらず、またバージョンアップでの作業量に左右されます。 - -また、Chromeのstableチャンネルのみを使用し、もし、重要な修正がbetaまたはdevチャンネルにある場合、それをバックポートします。 - -もっと知りたければ、[セキュリティについて](../tutorial/security.md)をご参照ください。 - -## Electronは、いつ最新のNode.jsにアップグレードされますか? - -Node.js の新しいバージョンがリリースされたとき、私たちは Electron の Node.js を更新するのを通常約1か月待ちます。そのようにして、とても頻繁に発生している、新しい Node.js バージョンによって取り込まれたバグによる影響を避けることができます。 - -通常、Node.js の新しい機能は V8 のアップグレードによってもたらされますが、Electron は Chrome ブラウザーに搭載されている V8 を使用しているので、新しい Node.js に入ったばかりのピカピカに新しい JavaScript 機能は Electron ではたいてい既に導入されています。 - -## ウェブページ間のデータを共有する方法は? - -ウェブページ(レンダラープロセス)間のデータを共有するために最も単純な方法は、ブラウザで、すでに提供されているHTML5 APIを使用することです。もっとも良い方法は、[Storage API][storage]、[`localStorage`][local-storage]、[`sessionStorage`][session-storage]、[IndexedDB][indexed-db]です。 - -```javascript -// In the main process. -global.sharedObject = { - someProperty: 'default value' -}; -``` - -```javascript -// In page 1. -require('remote').getGlobal('sharedObject').someProperty = 'new value'; -``` - -```javascript -// In page 2. -console.log(require('remote').getGlobal('sharedObject').someProperty); -``` - -## 何分か経つと、アプリの Window/tray が消えてしまいます - -これは、Window/trayを格納するのに使用している変数がガベージコレクトされたときに発生します。 - -この問題に遭遇した時には、次のドキュメントを読むことをお勧めします。 - -* [Memory Management][memory-management] -* [Variable Scope][variable-scope] - -もし簡単に修正したい場合は、コードを以下のように修正して変数をグローバルにすると良いでしょう: - -変更前: - -```javascript -app.on('ready', function() { - var tray = new Tray('/path/to/icon.png'); -}) -``` - -変更後: - -```javascript -var tray = null; -app.on('ready', function() { - tray = new Tray('/path/to/icon.png'); -}) -``` - -## ElectronでjQuery/RequireJS/Meteor/AngularJSを使用できません - -Electronに組み込まれているNode.jsの影響で, `module`, `exports`, `require`のようなシンボルがDOMに追加されています。このため、いくつかのライブラリでは同名のシンボルを追加しようとして問題が発生することがあります。 - -これを解決するために、Electronに組み込まれているnodeを無効にすることができます。 - -```javascript -// In the main process. -var win = new BrowserWindow({ - webPreferences: { - nodeIntegration: false - } -}); -``` - -しかし、Node.jsとElectron APIを使用した機能を維持したい場合は、ほかのライブラリを読み込む前に、ページのシンボルをリネームする必要があります。 - -```html - - - - -``` - -## `require('electron').xxx` は定義されていません。 - -Electronの組み込みモジュールを使うとに、次のようなエラーに遭遇するかもしれません。 - -``` -> require('electron').webFrame.setZoomFactor(1.0); -Uncaught TypeError: Cannot read property 'setZoomLevel' of undefined -``` - -これは、ローカルまたはグローバルのどちらかで [npm `electron` module][electron-module] をインストールしたことが原因で、Electronの組み込みモジュールを上書きしてしまいます。 - -正しい組み込みモジュールを使用しているかを確認するために、`electron`モジュールのパスを出力します。 - -```javascript -console.log(require.resolve('electron')); -``` - -そして、次の形式かどうかを確認します。 - -``` -"/path/to/Electron.app/Contents/Resources/atom.asar/renderer/api/lib/exports/electron.js" -``` - -もし、`node_modules/electron/index.js` のような形式の場合は、npm `electron` モジュールを削除するか、それをリネームします。 - -```bash -npm uninstall electron -npm uninstall -g electron -``` - -しかし、組み込みモジュールを使用しているのに、まだこのエラーが出る場合、不適切なプロセスでモジュールを使用しようとしている可能性が高いです。例えば、`electron.app`はメインプロセスのみで使え、一方で`electron.webFrame`はレンダラープロセスのみに提供されています。 - -[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 -[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 diff --git a/docs-translations/jp/tutorial/application-distribution.md b/docs-translations/jp/tutorial/application-distribution.md deleted file mode 100644 index 43df2adb3de58..0000000000000 --- a/docs-translations/jp/tutorial/application-distribution.md +++ /dev/null @@ -1,108 +0,0 @@ -# アプリケーションの配布 - -Electronでアプリケーションを配布するために、アプリケーションを`app` という名前のディレクトリにし、Electronのリソースディレクトリ(macOS では -`Electron.app/Contents/Resources/` 、Linux と Windows では `resources/`)配下に置くべきです, - -macOS: - -```text -electron/Electron.app/Contents/Resources/app/ -├── package.json -├── main.js -└── index.html -``` - -Windows と Linux: - -```text -electron/resources/app -├── package.json -├── main.js -└── index.html -``` - -`Electron.app` (または Linux上では、`electron`、Windows上では、 `electron.exe`)を実行すると、Electronはアプリケーションを開始します。`electron` ディレクトリを最終的なユーザーに提供するために配布します。 - -## ファイルにアプリケーションをパッケージングする - -すべてのソースコードをコピーすることでアプリケーションを提供する方法とは別に、アプリケーションのソースコードをユーザーに見えるのを避けるために、[asar](https://github.com/electron/asar) にアーカイブしてアプリケーションをパッケージ化することができます。 - -`app` フォルダの代わりに `asar` アーカイブを使用するためには、アーカイブファイルを `app.asar` という名前に変更し、Electron のリソースディレクトリに以下のように配置する必要があります。すると、Electron はアーカイブを読み込もうとし、それを開始します。 - -macOS: - -```text -electron/Electron.app/Contents/Resources/ -└── app.asar -``` - -Windows と Linux: - -```text -electron/resources/ -└── app.asar -``` - -[Application packaging](application-packaging.md)で、詳細を確認できます。 - -## ダウンロードするバイナリのブランド名の変更 - -Electronにバンドルした後、ユーザーに配布する前に、 Electron名を変更したいでしょう。 - -### Windows - -`electron.exe`を任意の名前に変更でき、[rcedit](https://github.com/atom/rcedit) -のようなツールでアイコンやその他の情報を編集できます。 - -### macOS - -`Electron.app` を任意の名前に変更でき、次のファイルの `CFBundleDisplayName`と `CFBundleIdentifier`、 `CFBundleName`のフィールドの名前を変更する必要があります。 - -* `Electron.app/Contents/Info.plist` -* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` - -ヘルパーアプリケーションの名前を変更して、アクティビティモニタに `Electron Helper` と表示されないようにすることもできますが、その際はヘルパーアプリケーションの実行可能ファイルの名前を変更したことを確認してください。 - -名前変更後のアプリケーションの構成は以下の通りです: - -``` -MyApp.app/Contents -├── Info.plist -├── MacOS/ -│   └── MyApp -└── Frameworks/ - ├── MyApp Helper EH.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper EH - ├── MyApp Helper NP.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper NP - └── MyApp Helper.app - ├── Info.plist - └── MacOS/ -    └── MyApp Helper -``` - -### Linux - -`electron` を任意の名前に変更できます。 - -## ソースからElectronをリビルドしてブランド名を変更する - -プロダクト名を変更し、ソースからビルドすることで、Electronのブランド名を変更できます。これをするために、`atom.gyp` ファイルを変更し、クリーンリビルドする必要があります。 - -### grunt-build-atom-shell - -Electron のコードを手動チェックアウトして再構築するのには複雑な手順が必要ですが、これを自動的に扱うための Grunt タスクが作られています: -[grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell). - -このタスクは自動的に `.gyp` ファイルの編集、ソースからのビルド、そして新しい実行可能ファイル名に一致するようにネイティブの Node モジュールを再構築します。 - -## パッケージングツール - -手動でアプリケーションをパッケージ化する以外の方法として、サードパーティのパッケジングツールを選ぶこともできます。 - -* [electron-packager](https://github.com/maxogden/electron-packager) -* [electron-builder](https://github.com/loopline-systems/electron-builder) diff --git a/docs-translations/jp/tutorial/application-packaging.md b/docs-translations/jp/tutorial/application-packaging.md deleted file mode 100644 index 79b807d3111e6..0000000000000 --- a/docs-translations/jp/tutorial/application-packaging.md +++ /dev/null @@ -1,149 +0,0 @@ -# アプリケーションのパッケージ化 - -Windows上の長いパス名周りの[問題](https://github.com/joyent/node/issues/6960) を軽減したり、`require`を若干スピードアップしたり、簡単な調査からソースコードを隠したりするために、ソースコードを少々変更して、アプリケーションを [asar][asar] アーカイブとしてパッケージ化することもできます。 - -## `asar` アーカイブの生成 - -[asar][asar] アーカイブは、1つのファイルに連結されたtarライクのシンプルなフォーマットです。Electron はファイル全体をアンパックしなくても任意のファイルを読み込めます。 - -アプリを `asar` アーカイブにパッケージ化する手順: - -### 1. asar ユーティリティのインストール - -```bash -$ npm install -g asar -``` - -### 2. `asar pack`でパッケージ化する - -```bash -$ asar pack your-app app.asar -``` - -## `asar` アーカイブを使用する - -Electronには、2組のAPIがあります。Node.js により提供される Node API、そして Chromium により提供される Web API です。どちらの API も `asar` アーカイブからのファイル読み込みに対応しています。 - -### Node API - -Electronでは特定のパッチで、`fs.readFile` や `require` のようなNode APIは、`asar` アーカイブを仮想ディレクトリのように扱い、ファイルをファイルシステム上の通常のファイルのように扱います。 - -例えば、`/path/to` 配下に、`example.asar` アーカイブがあると仮定します: - -```bash -$ asar list /path/to/example.asar -/app.js -/file.txt -/dir/module.js -/static/index.html -/static/main.css -/static/jquery.min.js -``` - -`asar` アーカイブ内のファイルを読み込む: - -```javascript -const fs = require('fs'); -fs.readFileSync('/path/to/example.asar/file.txt'); -``` - -アーカイブのルート直下にあるすべてのファイルを一覧にする: - -```javascript -const fs = require('fs'); -fs.readdirSync('/path/to/example.asar'); -``` - -アーカイブからモジュールを使用する: - -```javascript -require('/path/to/example.asar/dir/module.js'); -``` - -`BrowserWindow` を使って `asar` アーカイブ内の Web ページを表示することもできます: - -```javascript -const {BrowserWindow} = require('electron'); -let win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('file:///path/to/example.asar/static/index.html'); -``` - -### Web API - -Webページで、アーカイブ内のファイルを `file:` プロトコルでリクエストできます。 -Node API と同様、`asar` アーカイブはディレクトリのように扱われます。 - -例えば、 `$.get` でファイルを取得できます: - -```html - -``` - -### `asar` アーカイブを通常のファイルのように扱う - -アーカイブのチェックサムを検証する等の幾つかのケースでは、`asar` アーカイブをファイルとして読み込む必要があります。この目的のために、 `asar` サポートしないオリジナルの `fs` API を提供するビルトインの `original-fs` モジュールを使用できます。 - -```javascript -const originalFs = require('original-fs'); -originalFs.readFileSync('/path/to/example.asar'); -``` - -`process.noAssar` に `true` をセットしても `fs` モジュールの `asar` サポートを無効にすることができます: - -```javascript -process.noAsar = true; -fs.readFileSync('/path/to/example.asar'); -``` - -## Node API の制限 - -Node APIで、`asar` アーカイブが可能な限りディレクトリのように動作するよう懸命に試してますが、低レベル環境での Node API に起因した制限が幾つかあります。 - -### アーカイブは読み取り専用です - -アーカイブは修正できないため、ファイルを変更できる変更できる全ての Node API は `asar` アーカイブに対して動作しません。 - -### 作業ディレクトリは、アーカイブ内のディレクトリに設定できません - -`asar` アーカイブはディレクトリのように扱われるにも関わらず、ファイルシステム上には実際のディレクトリが存在しないため、`asar` アーカイブ内のディレクトリを作業ディレクトリとして設定することはできません。幾つかの API の `cwd` オプションにアーカイブ内のディレクトリを渡すのも同様にエラーの原因になります。 - -### いくつかのAPIで追加のアンパッキングがされます - -たいていの `fs` APIは、アンパッキングせずに、 `asar` アーカイブからファイルを読み込んだり、ファイル情報を取得できます。しかし、システムコールに実際のファイルパスを渡すようになっている幾つかの API では、Electron は必要なファイルを一時ファイルとして抽出し、API に一時ファイルのパスを渡して、API が動作するようにします。このため、当該 API には多少のオーバーヘッドがあります。 - -追加のアンパッキングに必要なAPIです: - -* `child_process.execFile` -* `child_process.execFileSync` -* `fs.open` -* `fs.openSync` -* `process.dlopen` - ネイティブモジュール上の `require` で使用されます - -### `fs.stat` の偽の統計情報 - -`asar` アーカイブ内のファイルはファイルシステム上に存在しないので、`fs.stat` および `asar` アーカイブ内のファイルへの関連情報によって返される`Stats` オブジェクトは、推測して生成されます。ファイルサイズの取得とファイルタイプのチェックを除いて、 `Stats` オブジェクトを信頼すべきではありません。 - -### `asar` アーカイブ内のバイナリの実行 - -`child_process.exec` と `child_process.spawn` 、 `child_process.execFile` のようなバイナリを実行できるNode APIがあります。しかし、`execFile` だけが、`asar` アーカイブ内でのバイナリ実行をサポートしています。 - -なぜならば、`exec` と `spawn` は入力として `file` の代わりに `command` を受け取り、`command` はシェル配下で実行されるからです。コマンドが asar アーカイブ内のファイルを使うかどうかを決定するための信頼できる方法はありませんし、そうするとしてもコマンドで使うファイルパスを副作用なしに置き換えることができるかどうかを確認することはできません。 - -## `asar` アーカイブ内のファイルをアンパックして追加 - -上記のように、いくつかのNode APIが呼ばれると、ファイルシステム上にファイルをアンパックしますが,パフォーマンス問題は別として、ウィルススキャナーのアラートにつながる可能性があります。 - -これに対応するために、`--unpack` オプションを使用して、アーカイブを作成する際に、いくつかのファイルをアンパックできます。例えば、ネイティブモジュールの共有ライブラリを除く場合: - -```bash -$ asar pack app app.asar --unpack *.node -``` - -このコマンドを実行した後、`app.asar` とは別に、アンパックされたファイルを含んだ`app.asar.unpacked` フォルダーが生成されます。ユーザーに提供するときには、`app.asar` と一緒にコピーしなければなりません。 - -[asar]: https://github.com/electron/asar diff --git a/docs-translations/jp/tutorial/debugging-main-process.md b/docs-translations/jp/tutorial/debugging-main-process.md deleted file mode 100644 index ffffdeb83ac55..0000000000000 --- a/docs-translations/jp/tutorial/debugging-main-process.md +++ /dev/null @@ -1,70 +0,0 @@ -# メインプロセスのデバッグ - -ブラウザウィンドウ DevToolsのみ、レンダリングプロセススクリプトをデバッグすることができます。メインプロセスからスクリプトをデバッグする方法を提供するために、Electronは、`--debug` と `--debug-brk` スイッチを提供します。 - -## コマンドライン スイッチ - -Electronのメインプロセスをデバッグするために次のコマンドラインスイッチを使用します - -### `--debug=[port]` - -このスイッチを使ったとき、Electronは、 `port` 上でV8デバッガープロトコルメッセージをリッスンします。デフォルトの `port` は `5858`です。 - -### `--debug-brk=[port]` - -`--debug` のようですが、最初の行でスクリプトをポーズします。 - -## デバッグ用のnode-inspectorを使用する - -__Note:__ Electron は今のところ、明確にはnode-inspectorは動作せず、node-inspectorのコンソール下で、`process` オブジェクトを調査した場合、メインプロセスはクラッシュするでしょう。 - -### 1. インストールされた[node-gyp required tools][node-gyp-required-tools] を確認する - -### 2. [node-inspector][node-inspector]をインストールする - -```bash -$ npm install node-inspector -``` - -### 3. `node-pre-gyp`のパッチバージョンをインストールする - -```bash -$ npm install git+https://git@github.com/enlight/node-pre-gyp.git#detect-electron-runtime-in-find -``` - -### 4. Electron用の `node-inspector` `v8` モジュールをリコンパイルする(対象のElectronのバージョン番号を変更する) - -```bash -$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall -$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall -``` - -[How to install native modules](how-to-install-native-modules)を見る。 - -### 5. Electron用のデバッグモードを有効にする - -デバッグフラッグでElectronを開始する: - -```bash -$ electron --debug=5858 your/app -``` - -または、最初のライン上でスクリプトをポーズする: - -```bash -$ electron --debug-brk=5858 your/app -``` - -### 6. Electronを使用して、[node-inspector][node-inspector] サーバーを開始する - -```bash -$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js -``` - -### 7. デバッグUIを読み込みます - -Chromeブラウザで、 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 を開きます。エントリーラインを見るために、debug-brkを始めるには、ポーズをクリックします。 - -[node-inspector]: https://github.com/node-inspector/node-inspector -[node-gyp-required-tools]: https://github.com/nodejs/node-gyp#installation -[how-to-install-native-modules]: using-native-node-modules.md#how-to-install-native-modules diff --git a/docs-translations/jp/tutorial/desktop-environment-integration.md b/docs-translations/jp/tutorial/desktop-environment-integration.md deleted file mode 100644 index c6f7a585fbebf..0000000000000 --- a/docs-translations/jp/tutorial/desktop-environment-integration.md +++ /dev/null @@ -1,260 +0,0 @@ -# デスクトップ環境の統合 - -異なるオペレーティングシステムは、それぞれのデスクトップ環境でデスクトップに統合されたアプリケーション用に異なる機能を提供します。例えば、Windows アプリケーションではタスクバーのジャンプバーリストにショートカットをおけ、Macではドックメニューにカスタムメニューをおけます。 - -このガイドでは、Electron APIでデスクトップ環境にアプリケーションを統合する方法を説明します。 - -## 通知 (Windows, Linux, macOS) - -3つのオペレーティングシステム全てで、アプリケーションからユーザーに通知を送る手段が提供されています。通知を表示するためにオペレーティングシステムのネイティブ通知APIを使用しする[HTML5 Notification API](https://notifications.spec.whatwg.org/)で、Electronは、開発者に通知を送ることができます。 - -**注意:** これはHTML5 APIですので、レンダラプロセス内のみで有効です。 - - -```javascript -let myNotification = new Notification('Title', { - body: 'Lorem Ipsum Dolor Sit Amet' -}); - -myNotification.onclick = () => { - console.log('Notification clicked'); -}; -``` - -オペレーティングシステム間でコードとユーザ体験は似ていますが、細かい違いがあります。 - -### Windows - -* Windows 10では、通知はすぐに動作します。 -* Windows 8.1 と Windows 8では、[Application User -Model ID][app-user-model-id]で、アプリへのショートカットはスタートメニューにインストールされます。しかし、スタートメニューにピン止めをする必要がありません。 -* Windows 7以前は、通知はサポートされていません。 しかし、[Tray API][tray-balloon]を使用してバルーンヒントを送信することができます。 - -その上で、bodyの最大サイズは250文字であることに留意してください。Windowsチームは、通知は200文字にすることを推奨しています。 - -### Linux - -通知は、`libnotify`を使用して送信されます。[デスクトップ通知仕様][notification-spec]に対応したデスクトップ環境上(Cinnamon、Enlightenment、Unity、GNOME、KDEなど)で通知を表示できます。 - -### macOS - -通知は、そのままmacOSに通知されます。しかし、[通知に関するAppleのヒューマンインターフェイスガイドライン(英語版)](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html)を知っておくべきです。 - -通知は、256バイトサイズに制限されており、制限を超えていた場合、通知が破棄されます。 - -## 最近のドキュメント (Windows と macOS) - -Windows と macOSは、ジャンプリストやドックメニュー経由で、アプリケーションが開いた最近のドキュメント一覧に簡単にアクセスできます。 - -__JumpList:__ - -![JumpList Recent Files](http://i.msdn.microsoft.com/dynimg/IC420538.png) - -__Application dock menu:__ - - - -最近のドキュメントにファイルを追加するために、[app.addRecentDocument][addrecentdocument] APIを使用できます: - -```javascript -app.addRecentDocument('/Users/USERNAME/Desktop/work.type'); -``` - -[app.clearRecentDocuments][clearrecentdocuments] API を使用して、最近のドキュメント一覧を空にできます: - -```javascript -app.clearRecentDocuments(); -``` - -### Windows 留意点 - -Windows で、この機能を使用できるようにするために、アプリケーションにドキュメントのファイルタイプのハンドラーを登録すべきです。さもなければ、ジャンプリストに表示されません。[Application Registration][app-registration]で、登録しているアプリケーションをすべて見れます。 - -ユーザーがジャンプリストからファイルをクリックしたとき、アプリケーションの新しいインスタンスは、コマンドライン引数にファイルのパスを渡して開始します。 - -### macOS 留意点 - -ファイルが最近のドキュメントメニューからリクエストされた時、 `app` モジュールの `open-file` イベントが発行されます。 - -## ドックメニュー (macOS)のカスタマイズ - -通常アプリケーションで使用する共通機能用のショートカットを含める、ドック用のカスタムメニューをmacOSでは指定できます。 - -__Dock menu of Terminal.app:__ - - - -カスタムドックメニューを設定するために、macOSのみに提供されている `app.dock.setMenu` APIを使用できます。 - -```javascript -const electron = require('electron'); -const app = electron.app; -const Menu = electron.Menu; - -const dockMenu = Menu.buildFromTemplate([ - { label: 'New Window', click() { console.log('New Window'); } }, - { label: 'New Window with Settings', submenu: [ - { label: 'Basic' }, - { label: 'Pro'} - ]}, - { label: 'New Command...'} -]); -app.dock.setMenu(dockMenu); -``` - -## ユーザータスク (Windows) - -Windowsでは、ジャンプリストの `Tasks` カテゴリでカスタムアクションを指定できます。 -MSDNから引用します。 - ->アプリケーションでは、プログラムの機能とユーザーがプログラムを使用して実行する可能性が最も高い主な操作の両方に基づいてタスクを定義します。タスクを実行するためにアプリケーションが起動している必要がないように、タスクは状況に依存しないものにする必要があります。また、タスクは、一般的なユーザーがアプリケーションで実行する操作の中で、統計上最も一般的な操作です。たとえば、メール プログラムでは電子メールの作成や予定表の表示、ワード プロセッサでは新しい文書の作成、特定のモードでのアプリケーションの起動、アプリケーションのサブコマンドを実行することなどです。一般的なユーザーが必要としない高度な機能や、登録などの 1 回限りの操作によって、メニューがわかりづらくなることがないようにしてください。アップグレードやキャンペーンなどの販売促進用の項目としてタスクを使用しないでください。 - ->タスク一覧は静的なものにすることを強くお勧めします。アプリケーションの状態や状況に関係なく、タスク一覧は同じ状態にすることをお勧めします。リストを動的に変更することも可能ですが、ユーザーはターゲット一覧のこの部分が変更されると考えていないので、ユーザーを混乱させる可能性があることを考慮してください。 - -__Internet Explorerのタスク:__ - -![IE](http://i.msdn.microsoft.com/dynimg/IC420539.png) - -実際のメニューであるmacOSのドックメニューとは異なり、ユーザーがタスクをクリックしたとき、Windowsではユーザータスクはアプリケーションのショートカットのように動作し、プログラムは指定された引数を実行します。 - -アプリケーション用のユーザータスクを設定するために、[app.setUserTasks][setusertaskstasks] APIを使用できます: - -```javascript -app.setUserTasks([ - { - program: process.execPath, - arguments: '--new-window', - iconPath: process.execPath, - iconIndex: 0, - title: 'New Window', - description: 'Create a new window' - } -]); -``` - -タスクリストをクリアするために、`app.setUserTasks` をコールし、配列を空にします。 - -```javascript -app.setUserTasks([]); -``` - -アプリケーションを閉じた後もユーザータスクは表示されていてるので、アプリケーションをアンインストールするまではタスクに指定したアイコンとプログラムのパスは存在し続けてる必要があります。 - -## サムネイルツールバー(縮小表示ツールバー) - -Windowsでは、アプリケーションウィンドウのタスクバーレイアウトに、指定のボタンを縮小表示ツールバーに追加できます。アプリケーションのウィンドウを元のサイズに戻したりアクティブ化したりすることなく、主要なコマンドにアクセスできるようにします。 - -MSDNからの引用: - ->このツール バーは、単純に、使い慣れた標準的なツール バー コモン コントロールです。最大で 7 個のボタンが配置されます。各ボタンの ID、イメージ、ツールヒント、および状態は構造体で定義され、その後タスク バーに渡されます。アプリケーションでは、現在の状態での必要に応じて、縮小表示ツール バーのボタンの表示、有効化、無効化、非表示を実行できます。 ->たとえば、Windows Media Player の縮小表示ツール バーでは、再生、一時停止、ミュート、停止などの、標準的なメディア トランスポート コントロールを提供できます。 - -__Windows Media Playerの縮小表示ツールバー:__ - -![player](https://i-msdn.sec.s-msft.com/dynimg/IC420540.png) - -アプリケーションに縮小表示ツールバーを設定するために、[BrowserWindow.setThumbarButtons][setthumbarbuttons]を使えます: - -```javascript -const {BrowserWindow} = require('electron'); -const path = require('path'); - -let win = new BrowserWindow({ - width: 800, - height: 600 -}); -win.setThumbarButtons([ - { - tooltip: 'button1', - icon: path.join(__dirname, 'button1.png'), - click() { console.log("button2 clicked"); } - }, - { - tooltip: 'button2', - icon: path.join(__dirname, 'button2.png'), - flags: ['enabled', 'dismissonclick'], - click() { console.log("button2 clicked."); } - } -]); -``` - -縮小表示ツールバーボタンをクリアするために、 `BrowserWindow.setThumbarButtons` をコールして配列を空にします: - -```javascript -win.setThumbarButtons([]); -``` - -## Unity ランチャーショートカット (Linux) - -Unityでは、`.desktop` ファイルの修正を経由してランチャーにカスタムエントリーを追加できます。[Adding Shortcuts to a Launcher][unity-launcher]を参照してください。 - -__Audaciousのランチャーショートカット:__ - -![audacious](https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles?action=AttachFile&do=get&target=shortcuts.png) - -## タスクバーの進行状況バー (Windows, macOS, Unity) - -Windowsでは、タスクバーボタンは、進行状況バーを表示するのに使えます。ウィンドウを切り替えることなくウィンドウの進行状況情報をユーザーに提供することができます。 - -macOSではプログレスバーはドックアイコンの一部として表示されます。 -Unity DEは、ランチャーに進行状況バーの表示をするのと同様の機能を持っています。 - -__タスクバーボタン上の進行状況バー:__ - -![Taskbar Progress Bar](https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png) - -ウィンドウに進行状況バーを設定するために、[BrowserWindow.setProgressBar][setprogressbar] APIを使えます: - -```javascript -let win = new BrowserWindow({...}); -win.setProgressBar(0.5); -``` - -## タスクバーでアイコンをオーバーレイする (Windows) - -Windowsで、タスクバーボタンはアプリケーションステータスを表示するために小さなオーバーレイを使うことができます。MSDNから引用します。 - -> アイコン オーバーレイは、状況に応じた状態通知として機能し、通知領域に状態アイコンを個別に表示する必要性をなくして、情報をユーザーに伝えることを目的としています。たとえば、現在、通知領域に表示される Microsoft Office Outlook の新着メールの通知は、タスク バー ボタンのオーバーレイとして表示できるようになります。ここでも、開発サイクルの間に、アプリケーションに最適な方法を決定する必要があります。アイコン オーバーレイは、重要で長期にわたる状態や通知 (ネットワークの状態、メッセンジャーの状態、新着メールなど) を提供することを目的としています。ユーザーに対して、絶えず変化するオーバーレイやアニメーションを表示しないようにしてください。 - -__タスクバーボタンでのオーバーレイ:__ - -![Overlay on taskbar button](https://i-msdn.sec.s-msft.com/dynimg/IC420441.png) - -ウィンドウでオーバーレイアイコンを設定するために、[BrowserWindow.setOverlayIcon][setoverlayicon] APIを使用できます。 - -```javascript -let win = new BrowserWindow({...}); -win.setOverlayIcon('path/to/overlay.png', 'Description for overlay'); -``` - -## Windowのファイル表示 (macOS) - -macOSでは、ウィンドウがrepresented fileを設定でき、タイトルバー上にファイルのアイコンを表示でき、タイトル上でCommand-クリックまたはControl-クリックをすると、パスがポップアップ表示されます。 - -ウィンドウの編集状態を設定できるように、このウィンドウのドキュメントが変更されたかどうかをファイルのアイコンで示せます。 - -__Represented file ポップアップメニュー:__ - - - -ウィンドウにrepresented fileを設定するために、[BrowserWindow.setRepresentedFilename][setrepresentedfilename] と [BrowserWindow.setDocumentEdited][setdocumentedited] APIsを使えます: - -```javascript -let win = new BrowserWindow({...}); -win.setRepresentedFilename('/etc/passwd'); -win.setDocumentEdited(true); -``` - -[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows -[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments-os-x-windows -[setusertaskstasks]: ../api/app.md#appsetusertaskstasks-windows -[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress -[setoverlayicon]: ../api/browser-window.md#winsetoverlayiconoverlay-description-windows-7 -[setrepresentedfilename]: ../api/browser-window.md#winsetrepresentedfilenamefilename-os-x -[setdocumentedited]: ../api/browser-window.md#winsetdocumenteditededited-os-x -[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx -[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher -[setthumbarbuttons]: ../api/browser-window.md#winsetthumbarbuttonsbuttons-windows-7 -[tray-balloon]: ../api/tray.md#traydisplayballoonoptions-windows -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx -[notification-spec]: https://developer.gnome.org/notification-spec/ diff --git a/docs-translations/jp/tutorial/devtools-extension.md b/docs-translations/jp/tutorial/devtools-extension.md deleted file mode 100644 index b631b4e406e90..0000000000000 --- a/docs-translations/jp/tutorial/devtools-extension.md +++ /dev/null @@ -1,45 +0,0 @@ -# DevTools エクステンション - -簡単にデバッグをするために、Electronは[Chrome DevTools Extension][devtools-extension]に基本的な対応しています。 - -DevToolsエクステンションのために、ソースコードをダウンローし、`BrowserWindow.addDevToolsExtension` APIを使って読み込みます。読み込んだエクステンションは維持されているので、ウィンドウを作成するとき、毎回APIをコールする必要はありません。 - -** NOTE: React DevTools は動作しません。issue https://github.com/electron/electron/issues/915 をご覧ください ** - -例えば、[React DevTools Extension](https://github.com/facebook/react-devtools)を使うために、最初にソースコードをダウンロードする必要があります。 - -```bash -$ cd /some-directory -$ git clone --recursive https://github.com/facebook/react-devtools.git -``` - -エクステンションをビルドするために、[`react-devtools/shells/chrome/Readme.md`](https://github.com/facebook/react-devtools/blob/master/shells/chrome/Readme.md)を参照してください。 - -複数のウィンドウで、DevToolsを開くために、Electronでエクステンションをロードし、DevToolsコンソールで次のコードを実行します。 - -```javascript -const BrowserWindow = require('electron').remote.BrowserWindow; -BrowserWindow.addDevToolsExtension('/some-directory/react-devtools/shells/chrome'); -``` - -エクステンションをアンロードするために、`BrowserWindow.removeDevToolsExtension` APIを名前を指定してコールすると、次回DevToolsを開いた時にはロードされません。 - -```javascript -BrowserWindow.removeDevToolsExtension('React Developer Tools'); -``` - -## DevTools エクステンションのフォーマット - -理想的には、Chromeブラウザー用に書かれたすべてのDevToolsエクステンションをElectronがロードできることですが、それらはプレーンディレクトリにある必要があります。`crx` エクステンションパッケージは、ディレクトリに解凍できる方法がなければ、Electronはロードする方法はありません。 - -## バックグラウンドページ - -今のところ、ElectronはChromeエクステンションのバックグラウンドページ機能に対応していません。そのため、Electronでは、この機能に依存するDevToolsエクステンションは動作しません。 - -## `chrome.*` APIs - -いくつかのChromeエクステンションは、`chrome.*` APIsを使用しており、ElectronでそれらのAPIを実装するための努力をしていますが、すべては実装されていません。 - -すべては実装されていない`chrome.*` APIについて考えると、もしDevToolsエクステンションが `chrome.devtools.*` 以外のAPIを使用していると、エクステンションは動作しない可能性が非常に高いです。うまく動作しないエクステンションがあれば、APIのサポートの追加のために、issue trackerへご報告ください。 - -[devtools-extension]: https://developer.chrome.com/extensions/devtools diff --git a/docs-translations/jp/tutorial/electron-versioning.md b/docs-translations/jp/tutorial/electron-versioning.md deleted file mode 100644 index e8fc8b64c5f83..0000000000000 --- a/docs-translations/jp/tutorial/electron-versioning.md +++ /dev/null @@ -1,11 +0,0 @@ -# Electronのバージョン管理 - -もしあなたが経験豊富なNodeプログラマなら、`semver`(セマンティックバージョニング)のことはご存知でしょうし、バージョン番号をきっちり固定するのではなく、大まかな指針をパッケージの依存管理システムに指定していることと思います。ElectronはNodeとChromiumに強く依存しているので、少し難しい位置付けにあってsemverにきっちり従っていません。そのため、いつでも特定バージョンのElectronを参照しないといけません。 - -バージョン番号は次のルールに沿ってあげられます。 - - * メジャーバージョン: ElectronのAPIに大きな変更があった時- 例えば、`0.37.0`から`1.0.0`にアップグレードした時は、あなたはアプリケーションのアップデートをしなければなりません。 - * マイナーバージョン: ChromeのメジャーバージョンまたはNodeのマイナーバージョンのアップデート、またはElectronの重大な変更 - 例えば`1.0.0`から`1.1.0`にアップグレードした時は、あなたのアプリは多分動きますが、もしかしたら少々の変更をしないといけないかもしれません。 - * パッチ: 新しい機能やバグフィックス - `1.0.0`から`1.0.1`へのアップグレードでは、あなたのアプリはそのまま動くはずです。 - -もし、`electron-prebuilt`を使用しているのであれば、Electronのすべてのアップデートが開発者であるあなたによって手動で行われることを保証するために、固定バージョンを指定(`^1.1.0`ではなく`1.1.0`)することをお勧めします。 diff --git a/docs-translations/jp/tutorial/mac-app-store-submission-guide.md b/docs-translations/jp/tutorial/mac-app-store-submission-guide.md deleted file mode 100644 index f396de6091d42..0000000000000 --- a/docs-translations/jp/tutorial/mac-app-store-submission-guide.md +++ /dev/null @@ -1,153 +0,0 @@ -# Mac App Store 提出ガイド - -v0.34.0から、ElectronはMac App Store (MAS)にパッケージ化したアプリを登録することができます。このガイドでは、MASビルド用の制限とアプリを登録する方法についての情報を提供します。 - -__Note:__ Mac App Storeにアプリを登録するには、費用が発生する[Apple Developer Program][developer-program]に登録する必要があります。 - -## アプリを登録する方法 - -次の手順は、Mac App Storeにアプリを登録する簡単な手順を説明します。しかし、これらの手順はAppleによってAppが承認されることを保証するものではありません。Mac App Storeの要件については、Appleの[Submitting Your App][submitting-your-app]ガイドを読んでおく必要があります。 - -### 証明書の取得 - -Mac App StoreにAppを登録するには、最初にAppleから証明書を取得しなければありません。Web上で、[existing guides][nwjs-guide] を参照してください。 - -### アプリケーションの署名 - -Appleから証明書を取得した後、[Application Distribution](application-distribution.md)を参照してアプリをパッケージ化し、アプリに証明をします。この手順は、基本的にほかのプログラムと同じですが、Electronが依存するすべてに1つ1つサインします。 - -最初に、2つの資格ファイルを用意する必要があります。 - -`child.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.inherit - - - -``` - -`parent.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.application-groups - - your.bundle.id - - - -``` - -_`your.bundle.id`は`Info.plist`で指定されているあなたのアプリのBundle IDに置き換えてください。_ -そして、次のスクリプトでアプリを署名します。 - -```bash -#!/bin/bash - -# Name of your app. -APP="YourApp" -# The path of you app to sign. -APP_PATH="/path/to/YouApp.app" -# The path to the location you want to put the signed package. -RESULT_PATH="~/Desktop/$APP.pkg" -# The name of certificates you requested. -APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)" -INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)" - -FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" - -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework" -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib" -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib" -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework" -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper" -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH" -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP" -codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" -codesign -s "$APP_KEY" -f --entitlements child.plist "$APP_PATH/Contents/MacOS/$APP" -codesign -s "$APP_KEY" -f --entitlements parent.plist "$APP_PATH" - -productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" -``` - -macOSでのアプリのサンドボックス化を行うことが初めてなら、Appleの[Enabling App Sandbox][enable-app-sandbox]を通読し、基本的な考え方を確認してから、、エンタイトルメントファイルにアプリに必要なパーミッションキーを追加します。 - -### Appをアップロードする。 - -アプリに署名後、iTunes ConnectにアップロードするためにApplication Loaderを使用できます。アップロードする前に[created a record][create-record]を確認してください。 - -### アプリケーションを審査に提出 - -これらのステップを終えた後、[レビュー用にアプリを登録できます][submit-for-review]. - -## MAS Buildの制限 - -アプリのサンドボックスですべての要件を満たすために、MASビルドで次のモジュールを無効にしてください。 - -* `crashReporter` -* `autoUpdater` - -次の挙動を変更してください。 - -* ビデオキャプチャーはいくつかのマシンで動作しないかもしれません。 -* 一部のアクセシビリティ機能が動作しないことがあります。 -* アプリはDNSの変更を認識しません。 - -アプリのサンドボックスでの使用では、アプリがアクセスできるリソースは厳密に制限されています。詳細は、 [App Sandboxing][app-sandboxing] を参照してください。 - -## Electronが使用する暗号化アルゴリズム - -あなたが住んでいる国や地域に依存して、Mac App Store がアプリで使用する暗号化アルゴリズムを文章化することを要求することがあり、暗号登録番号(U.S. Encryption Registration (ERN))の同意のコピーの提出を求められます。 - -Electron は次の暗号アルゴリズムを使用しています: - -* AES - [NIST SP 800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf), [NIST SP 800-38D](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf), [RFC 3394](http://www.ietf.org/rfc/rfc3394.txt) -* HMAC - [FIPS 198-1](http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf) -* ECDSA - ANS X9.62–2005 -* ECDH - ANS X9.63–2001 -* HKDF - [NIST SP 800-56C](http://csrc.nist.gov/publications/nistpubs/800-56C/SP-800-56C.pdf) -* PBKDF2 - [RFC 2898](https://tools.ietf.org/html/rfc2898) -* RSA - [RFC 3447](http://www.ietf.org/rfc/rfc3447) -* SHA - [FIPS 180-4](http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf) -* Blowfish - https://www.schneier.com/cryptography/blowfish/ -* CAST - [RFC 2144](https://tools.ietf.org/html/rfc2144), [RFC 2612](https://tools.ietf.org/html/rfc2612) -* DES - [FIPS 46-3](http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf) -* DH - [RFC 2631](https://tools.ietf.org/html/rfc2631) -* DSA - [ANSI X9.30](http://webstore.ansi.org/RecordDetail.aspx?sku=ANSI+X9.30-1%3A1997) -* EC - [SEC 1](http://www.secg.org/sec1-v2.pdf) -* IDEA - "On the Design and Security of Block Ciphers" book by X. Lai -* MD2 - [RFC 1319](http://tools.ietf.org/html/rfc1319) -* MD4 - [RFC 6150](https://tools.ietf.org/html/rfc6150) -* MD5 - [RFC 1321](https://tools.ietf.org/html/rfc1321) -* MDC2 - [ISO/IEC 10118-2](https://www.openssl.org/docs/manmaster/crypto/mdc2.html) -* RC2 - [RFC 2268](https://tools.ietf.org/html/rfc2268) -* RC4 - [RFC 4345](https://tools.ietf.org/html/rfc4345) -* RC5 - http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf -* RIPEMD - [ISO/IEC 10118-3](http://webstore.ansi.org/RecordDetail.aspx?sku=ISO%2FIEC%2010118-3:2004) - -ERNの同意を取得するには、 [How to legally submit an app to Apple's App Store when it uses encryption (or how to obtain an ERN)][ern-tutorial]を参照してください。 - -[developer-program]: https://developer.apple.com/support/compare-memberships/ -[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html -[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps -[enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html -[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html -[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html -[app-sandboxing]: https://developer.apple.com/app-sandboxing/ -[issue-3871]: https://github.com/electron/electron/issues/3871 -[ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/ -[temporary-exception]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AppSandboxTemporaryExceptionEntitlements.html diff --git a/docs-translations/jp/tutorial/online-offline-events.md b/docs-translations/jp/tutorial/online-offline-events.md deleted file mode 100644 index 3b4f669c1f2d4..0000000000000 --- a/docs-translations/jp/tutorial/online-offline-events.md +++ /dev/null @@ -1,81 +0,0 @@ -# オンライン/オフライン イベントの検知 - -オンラインとオフラインイベントの検知は、以下の例で示すように、標準のHTML 5 APIを使用してレンダラプロセスに実装することができます。 - -_main.js_ - -```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; - -let onlineStatusWindow; - -app.on('ready', () => { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` - -メインプロセスでこれらのイベントに応答したいことがあるかもしれません。しかし、メインプロセスは `navigator` オブジェクトを持たないため、直接これらのイベントを検知することができません。Electronの inter-process communication ユーティリティを使用して、オンライン・オフラインイベントをメインプロセスに転送し、必要に応じて扱うことができます。次の例を見てみましょう。 - -_main.js_ - -```javascript -const electron = require('electron'); -const app = electron.app; -const ipcMain = electron.ipcMain; -const BrowserWindow = electron.BrowserWindow; - -let onlineStatusWindow; - -app.on('ready', () => { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`); -}); - -ipcMain.on('online-status-changed', (event, status) => { - console.log(status); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` diff --git a/docs-translations/jp/tutorial/quick-start.md b/docs-translations/jp/tutorial/quick-start.md deleted file mode 100644 index 8bd24994b52ea..0000000000000 --- a/docs-translations/jp/tutorial/quick-start.md +++ /dev/null @@ -1,187 +0,0 @@ -# クイックスタート - -Electron ではリッチなネイティブ API を持ったランタイムを提供することによってピュアな JavaScript でデスクトップアプリケーションをつくることができます。ウェブサーバーの代わりにデスクトップアプリケーションに焦点をあてた Node.js ランタイムであるといえばわかりやすいかもしれません。 - -Electron は JavaScript を GUI ライブラリにバインディングしません。その代わりに、Electron はウェブページを GUI として使用します。なので Electron は JavaScript によってコントロールされる最小のChromium ブラウザでもあるともいえます。 - -### メインプロセス - -Electron では、`package.json` の `main` スクリプトで実行されるプロセスを __メインプロセス__ と呼びます。メインプロセスで実行されるスクリプトがウェブページを作ることによって GUI を表示することができます。 - -### レンダラープロセス - -Electron はウェブページを表示させるために Chromium を使用しているので、Chromium のマルチプロセスアーキテクチャも使用されることになります。Electron で実行されるウェブページはそれぞれ自身のプロセスで実行されます。それを __レンダラープロセス__ と呼びます。 - -通常のブラウザでは、ウェブページはサンドボックス環境で実行されネイティブなリソースへのアクセスができません。Electron ではウェブページから Node.js の API を使えるためオペレーティングシステムと低レベルなやりとりが可能です。 - -### メインプロセスとレンダラープロセスの違い - -メインプロセスは `BrowserWindow` インスタンスを作ることによってウェブページをつくります。それぞれの `BrowserWindow` インスタンスはそれ自身のレンダラープロセス上でウェブページを実行します。`BrowserWindow` インスタンスが破棄されると、対応するレンダラープロセスも終了されます。 - -メインプロセスはすべてのウェブページとそれに対応するレンダラープロセスを管理しています。それぞれのレンダラープロセスは隔離されているので、自身の中で実行されているウェブページの面倒だけをみます。 - -ウェブページでは、GUI 関連の API を呼ぶことはできません。なぜならば、ウェブページからネイティブ GUI リソースを扱うことは非常に危険であり、簡単にリソースをリークしてしまうからです。もしウェブページ内でGUI を操作したい場合には、ウェブページのレンダラープロセスはメインプロセスにそれらの操作をするように伝える必要があります。 - -Electron では、メインプロセスとレンダラープロセスとのコミュニケーションをするために [ipc](../api/ipc-renderer.md) モジュールを提供しています。またそれと、RPC 形式の通信を行う [remote](../api/remote.md) モジュールもあります。 - -Electron では、メインプロセスとレンダラープロセスとのコミュニケーションをするには幾つかのほうほうがあります。メッセージを送信する[`ipcRenderer`](../api/ipc-renderer.md)モジュールと[`ipcMain`](../api/ipc-main.md)モジュールのように、RPC 形式の通信を行う[remote](../api/remote.md)モジュールです。[ウェブページ間のデータを共有する方法][share-data]にFAQエントリーがあります。 - -## Electronアプリを作成する - -一般的に Electron アプリの構成は次のようになります: - -```text -your-app/ -├── package.json -├── main.js -└── index.html -``` - -`package.json` の形式は Node モジュールとまったく同じです。 `main` フィールドで指定するスクリプトはアプリの起動スクリプトであり、メインプロセスを実行します。 `package.json` の例は次のようになります: - -```json -{ - "name" : "your-app", - "version" : "0.1.0", - "main" : "main.js" -} -``` - -__注記__: `package.json` に `main` が存在しない場合、Electron は `index.js` のロードを試みます。 - -`main.js` ではウィンドウを作成してシステムイベントを管理します。典型的な例は次のようになります: - -```javascript -const electron = require('electron'); -// アプリケーションを操作するモジュール -const {app} = electron; -// ネイティブブラウザウィンドウを作成するモジュール -const {BrowserWindow} = electron; - -// ウィンドウオブジェクトをグローバル参照をしておくこと。 -// しないと、ガベージコレクタにより自動的に閉じられてしまう。 -let win; - -function createWindow() { - // ブラウザウィンドウの作成 - win = new BrowserWindow({width: 800, height: 600}); - - // アプリケーションのindex.htmlの読み込み - win.loadURL(`file://${__dirname}/index.html`); - - // DevToolsを開く - win.webContents.openDevTools(); - - // ウィンドウが閉じられた時に発行される - win.on('closed', () => { - // ウィンドウオブジェクトを参照から外す。 - // もし何個かウィンドウがあるならば、配列として持っておいて、対応するウィンドウのオブジェクトを消去するべき。 - win = null; - }); -} - -// このメソッドはElectronが初期化を終えて、ブラウザウィンドウを作成可能になった時に呼び出される。 -// 幾つかのAPIはこのイベントの後でしか使えない。 -app.on('ready', createWindow); - -// すべてのウィンドウが閉じられた時にアプリケーションを終了する。 -app.on('window-all-closed', () => { - // macOSでは、Cmd + Q(終了)をユーザーが実行するまではウィンドウが全て閉じられても終了しないでおく。 - if (process.platform !== 'darwin') { - app.quit(); - } -}); - -app.on('activate', () => { - // macOS では、ドックをクリックされた時にウィンドウがなければ新しく作成する。 - if (win === null) { - createWindow(); - } -}); - -// このファイルでアプリケーション固有のメインプロセスのコードを読み込むことができる。 -// ファイルを別に分けておいてここでrequireすることもできる。 -``` - -最後に、表示するウェブページ `index.html` は次のようになります: - -```html - - - - - Hello World! - - -

Hello World!

- We are using node , - Chrome , - and Electron . - - -``` - -## アプリを実行する - -最初の `main.js`、`index.html`、`package.json` を作ったら、手元でアプリを実行し、思った通りに動くのを確認したいでしょう。 - -### electron-prebuilt - -[`electron-prebuilt`](https://github.com/electron-userland/electron-prebuilt)は、コンパイル済みのElectronを含んだ`npm`モジュールです。 - -`npm`でグローバルインストールをしているなら、下記のコマンドをアプリケーションのソースディレクトリで実行するだけで済みます。 - -```bash -electron . -``` - -ローカルにインストールしているなら以下を実行してください: - -```bash -./node_modules/.bin/electron . -``` - -### 手動ダウンロードした Electron バイナリを使う場合 - -もしも Electron を手動ダウンロードしているなら、同梱されているバイナリであなたのアプリを直接実行できます。 - -#### Windows - -```bash -$ .\electron\electron.exe your-app\ -``` - -#### Linux - -```bash -$ ./electron/electron your-app/ -``` - -#### macOS - -```bash -$ ./Electron.app/Contents/MacOS/Electron your-app/ -``` - -`Electron.app` は Electron のリリースパッケージの一部で、[ここ](https://github.com/electron/electron/releases) からダウンロードできます。 - -### Run as a distribution - -アプリケーションを作り終えたら、[Application distribution](./application-distribution.md) ガイドにしたがってディストリビューションを作成し、そしてパッケージされたアプリケーションとして実行することが可能です。 - -### 試してみよう - -このチュートリアルのコードは [`atom/electron-quick-start`](https://github.com/electron/electron-quick-start) リポジトリから clone して実行できます。 - -**注記**:例を試すには、[Git](https://git-scm.com) と [Node.js](https://nodejs.org/en/download/) ([npm](https://npmjs.org) もこれに含まれています) が必要です。 - -```bash -# Clone the repository -$ git clone https://github.com/electron/electron-quick-start -# Go into the repository -$ cd electron-quick-start -# Install dependencies and run the app -$ npm install && npm start -``` - -[share-data]: ../faq/electron-faq.md#how-to-share-data-between-web-pages diff --git a/docs-translations/jp/tutorial/security.md b/docs-translations/jp/tutorial/security.md deleted file mode 100644 index 57c47e4de734a..0000000000000 --- a/docs-translations/jp/tutorial/security.md +++ /dev/null @@ -1,44 +0,0 @@ -# セキュリティ・ネイティブ実行で出来ること・あなたの責任 - -Web開発者として、通常私たちはブラウザの強力なセキュリティ機能の恩恵を受けていますーそのため、書いたコードによる危険性は比較的小さいものです。 -ウェブサイトはサンドボックス内で限定された能力のみを使用することが許されていて、また、新しく見つかったセキュリティ脆弱性に素早く対処してくれるたくさんのプログラマチームによって作られたブラウザをユーザーが使ってくれています。 - -Electronを使用するにあたって、「Electronはウェブブラウザではない」ということを理解するのが大切です。使い慣れたWebテクノロジで豊富な機能を持ったデスクトップアプリケーションを作ることができますが、書いたコードはより強力な力を行使することのできるものです。JavaScriptでファイルシステム・シェルなどにアクセスすることができます。これによって、高機能なネイティブアプリケーションを作ることができますが、コードが許された力に比例して、受けるセキュリティリスクも大きいものになります。 - -そのことを頭に入れて、信頼できないソースから得られた任意の内容を表示することは、Electronが意図しない重要なセキュリティリスクを生み出すことに注意してください。 -実際、多くのElectronアプリケーション(Atom, Slack, Visual Studio Code など)は主としてローカルにあるファイルの内容(やNode integration外の信頼できる内容)を表示します。もしアプリケーション上でオンライン上から得られるコードを実行する場合、内容が悪意のあるものでないことを確認するのはあなたの責任です。 - - -# Chromium のセキュリティ問題とアップグレード - -Electronは新しいバージョンのChromiumを出来るだけ早くサポートするように努力をしてはいますが、アップグレードは数十、時には数百のファイルの編集を含む大変な左表であることを後理解ください。たくさんのリソースと貢献を受けていますが、ElectronはChromium最新版に追いついてないこともあり、数日・数週間遅れることがあります。 - -現在のChromiumコンポーネントのアップデートシステムは、使用できるリソースとほとんどのアプリケーションの需要を満たす、適切なバランスの場所にあると思います。我々は、Electronを使用する個々のケースに関する意見をいただきたいと思っています。この件に関するPull requestと貢献をいつでも歓迎します。 - - -## 上記の忠告を無視した場合 -リモートで得られたコードをローカルで実行した場合、セキュリティ問題が発生することになります。 -例えば、ブラウザでリモートのウェブサイトを表示することを考えてみてください。 -もし攻撃者がどうにかして(情報源そのものの攻撃や中間者攻撃によって)得られる内容を変更した場合、ユーザーのPC上でネイティブコードを実行できることになります。 - -> :warning: Node integration有効な環境で、リモートコードの読み込みと実行を行うべきではありません。代わりに、Nodeコードの実行にはローカルのファイルを使用してください。 -リモートのデータの内容を表示するには`webview`を使用して、`nodeIntegration`を無効にしてください。 - -#### チェックリスト -このリストは、防弾チョッキのように攻撃を防げるものではないですが、最低限あなたがしなければいけないことを記載しています。 - -* セキュア(https)な内容のみを表示してください。 -* リモートの内容を表示する全てのレンダラでNode integrationを無効にしてください (`webPreferences`を使用) -* `webSecurity`を無効にしないください。無効にすると、same-origin policyが無効になります。 -* [`Content-Security-Policy`](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)を定義して、スクリプトの読み込み元を制限してください。(例: `script-src 'self'`) -* [`eval`を無効にしてください。](https://github.com/nylas/N1/blob/0abc5d5defcdb057120d726b271933425b75b415/static/index.js#L6) evalは文字列をコードとして実行してしまいます。 -* `allowDisplayingInsecureContent` を有効にしないでください。 -* `allowRunningInsecureContent` を有効にしないでください。 -* しっかり理解していない限りは`experimentalFeatures`や`experimentalCanvasFeatures`を有効にしないでください。 -* しっかり理解していない限りは`blinkFeatures`を有効にしないでください。 -* WebView: `nodeintegration`を無効にしてください。 -* WebView: `disablewebsecurity`を使用しないでください。 -* WebView: `allowpopups`を使用しないでください。 -* WebView: `insertCSS`や`executeJavaScript`を外部のCSS/JSに使用しないでください。 - -再確認ですが、このリストは単にリスクを小さくするもので、リスクをなくすものではありません。もしウェブサイトを表示することが目的なら、ブラウザを使うのがより安全な選択肢です。 diff --git a/docs-translations/jp/tutorial/supported-platforms.md b/docs-translations/jp/tutorial/supported-platforms.md deleted file mode 100644 index 07da250f1b917..0000000000000 --- a/docs-translations/jp/tutorial/supported-platforms.md +++ /dev/null @@ -1,24 +0,0 @@ -# サポートするプラットフォーム - -Electronでは次のプラットフォームをサポートします。 - -### macOS - -macOS用に提供しているバイナリは64bitのみで、サポートするmacOSのバージョンは、macOS 10.9 以降です。 - -### Windows - -Windows 7 以降をサポートしており、それ以前のオペレーティングシステムはサポートしていません(し、動作しません)。 - -`x86` と `amd64` (x64) の両方のバイナリが、Windows用に提供しています。 -ただし、`ARM` バージョンのWindowsは今のところサポートしていません。 - -### Linux - -`ia32`(`i686`) と `x64`(`amd64`) のビルド済みバイナリは、Ubuntu 12.04上でビルドされ、`arm` バイナリは、Debian Wheezy用のhard-float ABIとNEONのARM v7を対象にビルドしています。 - -Electronはビルドプラットフォームにリンクされているので、ディストリビューションに同梱されているライブラリに依存しているかどうかに関係なくディストリビューション上で動作します。そのため Ubuntu 12.04 のみを動作保証しますが、次のプラットフォームについてもビルド済みのElectronバイナリを実行できるか検証します。 - -* Ubuntu 12.04 以降 -* Fedora 21 -* Debian 8 diff --git a/docs-translations/jp/tutorial/testing-on-headless-ci.md b/docs-translations/jp/tutorial/testing-on-headless-ci.md deleted file mode 100644 index 7fba4fef7d180..0000000000000 --- a/docs-translations/jp/tutorial/testing-on-headless-ci.md +++ /dev/null @@ -1,43 +0,0 @@ -# 継続的インテグレーションシステムによるテスト(Travis CI, Jenkins) - -Electron は Chromium を元にしているので、実行にはディスプレイドライバーが必要です。Chromium がディスプレイドライバーを見つけられないと、Electron は起動に失敗してテストの実行ができません。Travis や Circle、 Jenkins などの継続的インテグレーションシステムで Electron アプリをテストするにはちょっとした設定が必要です。端的に言うと仮想ディスプレイドライバーを使用します。 - -## 仮想ディスプレイサーバーの設定 - -まず [Xvfb](https://en.wikipedia.org/wiki/Xvfb) をインストールします(リンク先は英語)。Xvfb は X Window System のプロトコルを実装した仮想フレームバッファです。描画系の操作をスクリーン表示無しにメモリ内で行ってくれます。 - -その後 xvfb の仮想スクリーンを作成して、環境変数 `$DISPLAY` に作成した仮想スクリーンを指定します。Electron の Chromium は自動で`$DISPLAY`を見るので、アプリ側の設定は必要ありません。この手順は Paul Betts 氏が公開しているツール [xvfb-maybe](https://github.com/paulcbetts/xvfb-maybe) によって自動化されています。テスト実行コマンドの前に `xvfb-maybe` を追加するだけで、現在のシステムが必要とする xvfb の設定を自動で行ってくれます。xvfb の設定が必要ない Windows や macOS では何もしません。 - -``` -## Windows や macOS では以下のコマンドは electron-mocha をただ起動するだけです。 -## Linux でかつ GUI 環境でない場合、以下のコマンドは -## xvfb-run electron-mocha ./test/*.js と同等になります。 -xvfb-maybe electron-mocha ./test/*.js -``` - -### Travis CI - -Travis では `.travis.yml` を以下のようにするといいでしょう。 - -```yml -addons: - apt: - packages: - - xvfb - -install: - - export DISPLAY=':99.0' - - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & -``` - -### Jenkins - -Jenkins では [Xvfb plugin](https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin) という便利なプラグインが利用可能です(リンク先は英語)。 - -### Circle CI - -Circle CI では、なんと既に xvfb 及び `$DISPLAY` が設定されているので、[何の設定も必要ありません](https://circleci.com/docs/environment#browsers)(リンク先は英語)。 - -### AppVeyor - -AppVeyor は Selenium や Chromium、Electron などをサポートしている Windows 上で動くので、特に設定は必要ありません。 diff --git a/docs-translations/jp/tutorial/using-native-node-modules.md b/docs-translations/jp/tutorial/using-native-node-modules.md deleted file mode 100644 index eced3d36a2b6d..0000000000000 --- a/docs-translations/jp/tutorial/using-native-node-modules.md +++ /dev/null @@ -1,50 +0,0 @@ -# ネイティブのNodeモジュールを使用する - -Electronは、ネイティブのNodeモジュールをサポートしていますが、Node公式とは異なるV8バージョンを使用しているので、ネイティブモジュールでビルドする時、Electronのヘッダーで指定する必要があります。 - -## ネイティブNodeモジュールとの互換性 - -Nodeが新しいV8バージョンを使用し始めた時、Nativeモジュールは動作しなくなるかもしれません。ElectronでNativeモジュールが動作するかどうかを確認するために、Electronで使用する内部のNodeバージョンがサポートしているかを確認すべきです。ElectronでNodeが使用しているバージョンを確認するには、[releases](https://github.com/electron/electron/releases)ページを見るか、`process.version` (例えば [Quick Start](https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md)を見てください)を使用してください。 - -Nodeの複数バージョンを簡単にサポートできるので、あなたのモジュールに [NAN](https://github.com/nodejs/nan/) を使うことを検討してください。古いバージョンからElectronで動作するNodeの新しいバージョンへ移植するのに役立ちます。 - -## ネイティブモジュールのインストール方法 - -ネイティブモジュールをインストールするための3つの方法: - -### 簡単な方法 - -ヘッダーをダウンロードし、ネイティブモジュールをビルドする手順をマニュアルで管理する、[`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild) パッケージ経由で、ネイティブモジュールをリビルドするのが最も簡単な方法です。 - -```sh -npm install --save-dev electron-rebuild - -# Every time you run "npm install", run this -./node_modules/.bin/electron-rebuild - -# On Windows if you have trouble, try: -.\node_modules\.bin\electron-rebuild.cmd -``` - -### npmを使う方法 - -モジュールをインストールするために`npm` を使用できます。環境変数の設定を除いて、Nodeモジュールと完全に同じ手順です。 - -```bash -export npm_config_disturl=https://atom.io/download/atom-shell -export npm_config_target=0.33.1 -export npm_config_arch=x64 -export npm_config_runtime=electron -HOME=~/.electron-gyp npm install module-name -``` - -### node-gypを使う方法 - -ElectronのヘッダーでNodeモジュールをビルドするために、どこからヘッダーをダウンロードするかとどのバージョンを使用するかを選択して`node-gyp`を実行する必要があります。 - -```bash -$ cd /path-to-module/ -$ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=https://atom.io/download/atom-shell -``` - -開発ヘッダーを探し、 `HOME=~/.electron-gyp` を変更します。`--target=0.29.1`がElectronのバージョンです。 `--dist-url=...` で、どこからヘッダーをダウンロードするかを指定します。`--arch=x64`を使用して、64bit システム用にモジュールをビルドします。 diff --git a/docs-translations/jp/tutorial/using-pepper-flash-plugin.md b/docs-translations/jp/tutorial/using-pepper-flash-plugin.md deleted file mode 100644 index 85a896f8cc3b8..0000000000000 --- a/docs-translations/jp/tutorial/using-pepper-flash-plugin.md +++ /dev/null @@ -1,51 +0,0 @@ -# Pepper Flash プラグインを使用する - -Electronは、Pepper Flashプラグインをサポートしています。ElectronでPepper Flashプラグインを使用するために、マニュアルでPepper Flashプラグインのパスを指定し、アプリケーションで有効化しなければなりません。 - - -## Flash プラグインのコピー準備 - -macOSとLinuxでは、Pepper Flashプラグインの詳細は、Chromeブラウザーで、`chrome://plugins` にアクセスして確認できます。そこで表示されるパスとバージョンは、ElectronのPepper Flashサポートに役立ちます。それを別のパスにコピーすることができます。 - -## Electron スイッチの追加 - -直接、Electronコマンドラインに`--ppapi-flash-path` と `ppapi-flash-version` を追加するか、 アプリのreadyイベントの前に、`app.commandLine.appendSwitch`メソッドを使用します。`browser-window`の`plugins`スイッチを追加します。 - -例: - -```javascript -// Specify flash path. -// On Windows, it might be /path/to/pepflashplayer.dll -// On macOS, /path/to/PepperFlashPlayer.plugin -// On Linux, /path/to/libpepflashplayer.so -app.commandLine.appendSwitch('ppapi-flash-path', '/path/to/libpepflashplayer.so'); - -// Specify flash version, for example, v17.0.0.169 -app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169'); - -app.on('ready', function() { - mainWindow = new BrowserWindow({ - 'width': 800, - 'height': 600, - 'web-preferences': { - 'plugins': true - } - }); - mainWindow.loadURL('file://' + __dirname + '/index.html'); - // Something else -}); -``` - -## `` タグでFlashプラグインを有効化 - -`` タグに`plugins`属性を追加する - -```html - -``` - -## トラブルシューティング - -Pepper Flashプラグインが読み込まれているかは、devtoolsのconsoleで`navigator.plugins`を見ることで確認することができます。(プラグインのパスが正しいかがわからなくても) - -Pepper FlashプラグインのアーキテクチャはElectronのアーキテクチャと一致している必要があります。Windowsで、64bit Electronに32bit Flashプラグインを使用するのはよくある間違いです。 diff --git a/docs-translations/jp/tutorial/using-selenium-and-webdriver.md b/docs-translations/jp/tutorial/using-selenium-and-webdriver.md deleted file mode 100644 index 5e16c75d64393..0000000000000 --- a/docs-translations/jp/tutorial/using-selenium-and-webdriver.md +++ /dev/null @@ -1,159 +0,0 @@ -# Selenium と WebDriverを使用する - -[ChromeDriver - WebDriver for Chrome][chrome-driver]より: - -> WebDriverは、複数のブラウザ間でWebアプリの自動テストをするためのオープンソースツールです。Webページの移動、ユーザー入力、JavaScriptの実行などを可能にします。ChromeDriverはChromium用のWebDriverのワイヤープロトコルで実装されたスタンドアロンサーバーです。ChromiumとWebDriverチームメンバーが開発しています。 - -Electronで `chromedriver` を使用するために、Electronがどこにあるかを示し、ElectronはChromeブラウザーであると思わせます。 - -## Spectronの設定 - -[Spectron][spectron]はElectronのための公式なChromeDriverテストフレームワークです。 -[WebdriverIO](http://webdriver.io/)に基づいてビルドされており、テストの中でElectron APIを使用するヘルパーやChromeDriveを持っています。 - -```bash -$ npm install --save-dev spectron -``` - -```js -// 可視のウィンドウがタイトル付きで開かれているかを調べる簡単なテスト -var Application = require('spectron').Application -var assert = require('assert') - -var app = new Application({ - path: '/Applications/MyApp.app/Contents/MacOS/MyApp' -}) - -app.start().then(function () { - // ウィンドウは表示されている? - return app.browserWindow.isVisible() -}).then(function (isVisible) { - // ウィンドウが表示されているか確認 - assert.equal(isVisible, true) -}).then(function () { - // ウィンドウのタイトルを取得 - return app.client.getTitle() -}).then(function (title) { - // ウィンドウのタイトルを確認 - assert.equal(title, 'My App') -}).then(function () { - // アプリケーションを止める - return app.stop() -}).catch(function (error) { - // 失敗した場合ログを残す - console.error('Test failed', error.message) -}) -``` - -## WebDriverJsを設定 - -[WebDriverJs](https://code.google.com/p/selenium/wiki/WebDriverJs) は、web driver でテストするためのNodeパッケージを提供します。例のように使用します。 - -### 1. ChromeDriverを開始 - -最初に、 `chromedriver` バイナリをダウンロードし、実行します: - -```bash -$ ./chromedriver -Starting ChromeDriver (v2.10.291558) on port 9515 -Only local connections are allowed. -``` - -ポート番号 `9515`を覚えておいてください、あとで使用します。 - -### 2. WebDriverJSのインストール - -```bash -$ npm install selenium-webdriver -``` - -### 3. ChromeDriverに接続する - -Electronでの `selenium-webdriver` 使用方法は、chrome driverへの接続方法とElectronバイナリがどこにあるかをマニュアルで指定する以外は、upstreamと基本的に同じです。 - -```javascript -const webdriver = require('selenium-webdriver'); - -const driver = new webdriver.Builder() - // The "9515" is the port opened by chrome driver. - .usingServer('http://localhost:9515') - .withCapabilities({ - chromeOptions: { - // Here is the path to your Electron binary. - binary: '/Path-to-Your-App.app/Contents/MacOS/Electron', - } - }) - .forBrowser('electron') - .build(); - -driver.get('http://www.google.com'); -driver.findElement(webdriver.By.name('q')).sendKeys('webdriver'); -driver.findElement(webdriver.By.name('btnG')).click(); -driver.wait(function() { - return driver.getTitle().then(function(title) { - return title === 'webdriver - Google Search'; - }); -}, 1000); - -driver.quit(); -``` - -## WebdriverIOのセットアップをする - -[WebdriverIO](http://webdriver.io/) は、web driverでテストするNodeパッケージを提供します。 - -### 1. ChromeDriverを開始する - -最初に、 `chromedriver` バイナリをダウンロードし、実行します。: - -```bash -$ chromedriver --url-base=wd/hub --port=9515 -Starting ChromeDriver (v2.10.291558) on port 9515 -Only local connections are allowed. -``` - -ポート番号 `9515`を覚えておいてください、あとで使用します。 - -### 2. WebdriverIOをインストールする - -```bash -$ npm install webdriverio -``` - -### 3. chrome driverに接続する - -```javascript -const webdriverio = require('webdriverio'); -const options = { - host: "localhost", // Use localhost as chrome driver server - port: 9515, // "9515" is the port opened by chrome driver. - desiredCapabilities: { - browserName: 'chrome', - chromeOptions: { - binary: '/Path-to-Your-App/electron', // Path to your Electron binary. - args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/ - } - } -}; - -let client = webdriverio.remote(options); - -client - .init() - .url('http://google.com') - .setValue('#q', 'webdriverio') - .click('#btnG') - .getTitle().then((title) => { - console.log('Title was: ' + title); - }) - .end(); -``` - -## ワークフロー - -Electronはリビルドせずにアプリケーションをテストするために、単純にElectronのリソースディレクトリでアプリのソースを[配置します](https://github.com/electron/electron/blob/master/docs/tutorial/application-distribution.md)。 - -もしくは、アプリのフォルダーを引数にしてElectronバイナリを実行します。これによって、Electronのリソースディレクトリにアプリをコピー&ペーストする必要がなくなります。 - -[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/ -[spectron]: http://electron.atom.io/spectron diff --git a/docs-translations/jp/tutorial/using-widevine-cdm-plugin.md b/docs-translations/jp/tutorial/using-widevine-cdm-plugin.md deleted file mode 100644 index f8839182e5b34..0000000000000 --- a/docs-translations/jp/tutorial/using-widevine-cdm-plugin.md +++ /dev/null @@ -1,59 +0,0 @@ -# Widevine CDM Pluginを使用する - -Electronで、Chromeブラウザーに同梱される Widevine CDMプラグインを使用できます。 - -## プラグインを取得する - -Electronは、ライセンス的な理由でWidevine CDMプラグインは同梱されません。Widevine CDMプラグインを取得するために、最初に、使用するElectronビルドのChromeバージョンとアーキテクチャを合わせた公式のChromeブラウザーをインストールする必要があります。 - -__Note:__ Chromeブラウザのメジャーバージョンは、Electronが使用するChromeバージョンと同じでなければなりません。そうでなければ、プラグインは、`navigator.plugins`経由でロードされて表示されるにも関わらず動作しません。 - -### Windows & macOS - -Chromeブラウザーで、`chrome://components/`を開き、 `WidevineCdm` を探し、それが最新であることを確認し、`APP_DATA/Google/Chrome/WidevineCDM/VERSION/_platform_specific/PLATFORM_ARCH/`ディレクトリからすべてのプラグインバイナリを探します。 - -`APP_DATA` は、アプリデータを格納するシステムロケーションです。Windowsでは`%LOCALAPPDATA%`、macOSでは`~/Library/Application Support`です。`VERSION` は、Widevine CDM プラグインのバージョン文字列で、 `1.4.8.866`のような文字列が格納されます。`PLATFORM` は、 `mac` か `win`です。`ARCH` は `x86` か `x64`です。 - -Windowsでは、`widevinecdm.dll` と `widevinecdmadapter.dll`が必要で、macOSでは、`libwidevinecdm.dylib` と `widevinecdmadapter.plugin`です。任意の場所にコピーできますが、一緒に配置する必要があります。 - -### Linux - -Linux上では、プラグインバイナリは、Chromeブラウザーにいっほに格納され、 `/opt/google/chrome` 配下にあり、ファイル名は `libwidevinecdm.so` と `libwidevinecdmadapter.so`です。 - -## プラグインを使用する - -プラグインファイルを取得した後、Electronoの`--widevine-cdm-path`コマンドラインスイッチで`widevinecdmadapter`のパスを指定し、`--widevine-cdm-version`スイッチでプラグインのバージョンを指定します。 - -__Note:__ `widevinecdmadapter` バイナリはElectronにパスが通っていても`widevinecdm` バイナリはそこに置く必要があります。 - -コマンドラインスイッチは、`app`モジュールの`ready`イベントが発火する前に通り、プラグインが使用するページは、プラグインを有効にしなければなりません。 - -サンプルコード: - -```javascript -// You have to pass the filename of `widevinecdmadapter` here, it is -// * `widevinecdmadapter.plugin` on macOS, -// * `libwidevinecdmadapter.so` on Linux, -// * `widevinecdmadapter.dll` on Windows. -app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevinecdmadapter.plugin'); -// The version of plugin can be got from `chrome://plugins` page in Chrome. -app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866'); - -let win = null; -app.on('ready', () => { - win = new BrowserWindow({ - webPreferences: { - // The `plugins` have to be enabled. - plugins: true - } - }); -}); -``` - -## プラグインの検証 - -プラグインが動作するかどうかを検証するために、次の方法を使用できます。 - -* devtoolsを開き、Widevine CDMプラグインに`navigator.plugins`が含まれているかどうかを確認します。 -* https://shaka-player-demo.appspot.com/ を開き、`Widevine`で使用するマニフェストをロードします。 -* http://www.dash-player.com/demo/drm-test-area/を開き、`bitdash uses Widevine in your browser`をチェックし、ビデオを再生します。 diff --git a/docs-translations/ko-KR/README.md b/docs-translations/ko-KR/README.md deleted file mode 100644 index 8a8898f191e86..0000000000000 --- a/docs-translations/ko-KR/README.md +++ /dev/null @@ -1,100 +0,0 @@ -반드시 사용하는 Electron 버전과 문서 버전을 일치시켜야 합니다. 버전 숫자는 문서 페이지 -URL에 포함되어 있습니다. 만약 그렇지 않다면, 아마 현재 보고 있는 문서는 개발 중인 -브랜치의 문서를 보고 있을 가능성이 있으며 해당 문서는 추후 API의 변경 가능성이 있고 -현재 사용하고 있는 Electron의 버전과 호환되지 않을 수 있습니다. 이 경우 atom.io의 -[사용할 수 있는 버전](http://electron.atom.io/docs/) 목록에서 다른 버전으로 변경할 -수 있습니다. 또한 GitHub 인터페이스의 "Switch branches/tags" 드롭다운 메뉴에서도 -사용 중인 Electron 버전으로 변경할 수 있습니다. - -**역자주:** 한국어 번역 문서는 `atom.io`에 반영되어 있지 않습니다. 한국어 번역 문서는 -현재 `upstream` 원본 문서의 변경에 따라 최대한 문서의 버전을 맞추려고 노력하고 있지만 -가끔 누락된 번역이 존재할 수 있습니다. - -## FAQ - -Electron에 대해 자주 묻는 질문이 있습니다. 이슈를 생성하기 전에 다음 문서를 먼저 -확인해 보세요: - -* [Electron FAQ](faq.md) - -## 개발 가이드 - -* [지원하는 플랫폼](tutorial/supported-platforms.md) -* [보안](tutorial/security.md) -* [Electron 버전 관리](tutorial/electron-versioning.md) -* [애플리케이션 배포](tutorial/application-distribution.md) -* [Mac 앱스토어 애플리케이션 제출 가이드](tutorial/mac-app-store-submission-guide.md) -* [Windows 스토어 가이드](tutorial/windows-store-guide.md) -* [애플리케이션 패키징](tutorial/application-packaging.md) -* [네이티브 Node 모듈 사용하기](tutorial/using-native-node-modules.md) -* [메인 프로세스 디버깅하기](tutorial/debugging-main-process.md) -* [Selenium 과 WebDriver 사용하기](tutorial/using-selenium-and-webdriver.md) -* [개발자 도구 확장 기능](tutorial/devtools-extension.md) -* [Pepper 플래시 플러그인 사용하기](tutorial/using-pepper-flash-plugin.md) -* [Widevine CDM 플러그인 사용하기](tutorial/using-widevine-cdm-plugin.md) -* [Headless CI 시스템에서 테스팅하기 (Travis, Jenkins)](tutorial/testing-on-headless-ci.md) - -## 튜토리얼 - -* [시작하기](tutorial/quick-start.md) -* [데스크톱 환경 통합](tutorial/desktop-environment-integration.md) -* [온라인/오프라인 이벤트 감지](tutorial/online-offline-events.md) - -## API 레퍼런스 - -* [개요](api/synopsis.md) -* [Process 객체](api/process.md) -* [크롬 명령줄 스위치 지원](api/chrome-command-line-switches.md) -* [환경 변수](api/environment-variables.md) - -### 커스텀 DOM 요소: - -* [`File` 객체](api/file-object.md) -* [`` 태그](api/web-view-tag.md) -* [`window.open` 함수](api/window-open.md) - -### 메인 프로세스에서 사용할 수 있는 모듈: - -* [app](api/app.md) -* [autoUpdater](api/auto-updater.md) -* [BrowserWindow](api/browser-window.md) -* [contentTracing](api/content-tracing.md) -* [dialog](api/dialog.md) -* [globalShortcut](api/global-shortcut.md) -* [ipcMain](api/ipc-main.md) -* [Menu](api/menu.md) -* [MenuItem](api/menu-item.md) -* [powerMonitor](api/power-monitor.md) -* [powerSaveBlocker](api/power-save-blocker.md) -* [protocol](api/protocol.md) -* [session](api/session.md) -* [systemPreferences](api/system-preferences.md) -* [Tray](api/tray.md) -* [webContents](api/web-contents.md) - -### 렌더러 프로세스에서 사용할 수 있는 모듈 (웹 페이지): - -* [desktopCapturer](api/desktop-capturer.md) -* [ipcRenderer](api/ipc-renderer.md) -* [remote](api/remote.md) -* [webFrame](api/web-frame.md) - -### 두 프로세스 모두 사용할 수 있는 모듈: - -* [clipboard](api/clipboard.md) -* [crashReporter](api/crash-reporter.md) -* [nativeImage](api/native-image.md) -* [screen](api/screen.md) -* [shell](api/shell.md) - -## 개발자용 - -* [코딩 스타일](development/coding-style.md) -* [소스 코드 디렉터리 구조](development/source-code-directory-structure.md) -* [NW.js(node-webkit)와 기술적으로 다른점](development/atom-shell-vs-node-webkit.md) -* [빌드 시스템 개요](development/build-system-overview.md) -* [빌드 설명서 (macOS)](development/build-instructions-osx.md) -* [빌드 설명서 (Windows)](development/build-instructions-windows.md) -* [빌드 설명서 (Linux)](development/build-instructions-linux.md) -* [디버그 설명서 (Windows)](development/debug-instructions-windows.md) -* [디버거 심볼 서버 설정](development/setting-up-symbol-server.md) diff --git a/docs-translations/ko-KR/api/accelerator.md b/docs-translations/ko-KR/api/accelerator.md deleted file mode 100644 index 1930277493003..0000000000000 --- a/docs-translations/ko-KR/api/accelerator.md +++ /dev/null @@ -1,55 +0,0 @@ -# Accelerator - -> 키보드 단축키를 정의합니다. - -Accelerator는 `+` 문자를 통해 여러 혼합키와 키코드를 결합할 수 있습니다. - -예시: - -* `CommandOrControl+A` -* `CommandOrControl+Shift+Z` - -## 플랫폼에 관련하여 주의할 점 - -Linux와 Windows에서는 `Command`키가 없으므로 작동하지 않습니다. 대신에 -`CommandOrControl`을 사용하면 macOS의 `Command`와 Linux, Windows의 `Control` 모두 -지원할 수 있습니다. - -`Option` 대신 `Alt`을 사용하는게 좋습니다. `Option` 키는 macOS에만 있으므로 -모든 플랫폼에서 사용할 수 있는 `Alt` 키를 권장합니다. - -`Super`키는 Windows와 Linux 에서는 `윈도우`키를, macOS에서는 `Cmd`키로 맵핑됩니다. - -## 사용 가능한 혼합키 - -* `Command` (단축어 `Cmd`) -* `Control` (단축어 `Ctrl`) -* `CommandOrControl` (단축어 `CmdOrCtrl`) -* `Alt` -* `Option` -* `AltGr` -* `Shift` -* `Super` - -## 사용 가능한 전체 키코드 - -* `0` 부터 `9` 까지 -* `A` 부터 `Z` 까지 -* `F1` 부터 `F24` 까지 -* `~`, `!`, `@`, `#`, `$`, etc 와 같은 구두점 기호들 -* `Plus` -* `Space` -* `Tab` -* `Backspace` -* `Delete` -* `Insert` -* `Return` (또는 `Enter`) -* `Up`, `Down`, `Left` 와 `Right` -* `Home` 그리고 `End` -* `PageUp` 그리고 `PageDown` -* `Escape` (단축어 `Esc`) -* `VolumeUp`, `VolumeDown` 그리고 `VolumeMute` -* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` 그리고 `MediaPlayPause` -* `PrintScreen` - -__키코드는 `단축어`로도 사용할 수 있습니다__ diff --git a/docs-translations/ko-KR/api/app.md b/docs-translations/ko-KR/api/app.md deleted file mode 100644 index 9dcd0db8e3cf4..0000000000000 --- a/docs-translations/ko-KR/api/app.md +++ /dev/null @@ -1,723 +0,0 @@ -# app - -> 애플리케이션의 이벤트 생명주기를 제어합니다. - -밑의 예시는 마지막 윈도우가 종료되었을 때, 애플리케이션을 종료시키는 예시입니다: - -```javascript -const {app} = require('electron'); -app.on('window-all-closed', () => { - app.quit(); -}); -``` - -## Events - -`app` 객체는 다음과 같은 이벤트를 가지고 있습니다: - -### Event: 'will-finish-launching' - -애플리케이션이 기본적인 시작 준비를 마치면 발생하는 이벤트입니다. -Windows, Linux 운영체제에서의 `will-finish-launching` 이벤트는 `ready` 이벤트와 -동일합니다. macOS에서의 이벤트는 `NSApplication`의 -`applicationWillFinishLaunching`에 대한 알림으로 표현됩니다. 대개 이곳에서 -`open-file`과 `open-url` 이벤트 리스너를 설정하고 crash reporter와 auto updater를 -시작합니다. - -대부분의 경우, 모든 것을 `ready` 이벤트 핸들러 안에서 해결해야 합니다. - -### Event: 'ready' - -Electron이 초기화를 끝냈을 때 발생하는 이벤트입니다. - -### Event: 'window-all-closed' - -모든 윈도우가 종료되었을 때 발생하는 이벤트입니다. - -만약 이 이벤트를 구독하지 않은 상태로 모든 윈도우가 닫혔을 때의 기본 동작은 앱을 -종료하는 것입니다. 하지만, 이 이벤트를 구독하면, 앱을 종료할지 다른 일을 할지 제어할 -수 있습니다. 만약 사용자가 `Cmd + Q`를 입력했거나 개발자가 `app.quit()`를 호출했다면, -Electron은 먼저 모든 윈도우의 종료를 시도하고 `will-quit` 이벤트를 발생시킵니다. -그리고 `will-quit` 이벤트가 발생했을 땐 `window-all-closed` 이벤트가 발생하지 -않습니다. - -**역자주:** 이 이벤트는 말 그대로 현재 애플리케이션에서 윈도우만 완전히 종료됬을 때 -발생하는 이벤트입니다. 따라서 애플리케이션을 완전히 종료하려면 이 이벤트에서 -`app.quit()`를 호출해 주어야 합니다. - -### Event: 'before-quit' - -Returns: - -* `event` Event - -애플리케이션 윈도우들이 닫히기 시작할 때 발생하는 이벤트입니다. -`event.preventDefault()` 호출은 이벤트의 기본 동작을 방지하기 때문에 -이를 통해 애플리케이션의 종료를 방지할 수 있습니다. - -### Event: 'will-quit' - -Returns: - -* `event` Event - -모든 윈도우들이 종료되고 애플리케이션이 종료되기 시작할 때 발생하는 이벤트입니다. -`event.preventDefault()` 호출을 통해 애플리케이션의 종료를 방지할 수 있습니다. - -`will-quit` 와 `window-all-closed` 이벤트의 차이점을 확인하려면 `window-all-closed` -이벤트의 설명을 참고하세요. - -### Event: 'quit' - -Returns: - -* `event` Event -* `exitCode` Integer - -애플리케이션이 종료될 때 발생하는 이벤트입니다. - -### Event: 'open-file' _macOS_ - -Returns: - -* `event` Event -* `path` String - -사용자가 애플리케이션을 통해 파일을 열고자 할 때 발생하는 이벤트입니다. - -`open-file` 이벤트는 보통 애플리케이션이 열려 있을 때 OS가 파일을 열기 위해 -애플리케이션을 재사용할 때 발생합니다. 이 이벤트는 파일을 dock에 떨어트릴 때, -애플리케이션이 실행되기 전에도 발생합니다. 따라서 이 이벤트를 제대로 처리하려면 -`open-file` 이벤트 핸들러를 애플리케이션이 시작하기 전에 등록해 놓았는지 확실히 -확인해야 합니다. (`ready` 이벤트가 발생하기 전에) - -이 이벤트를 처리할 땐 반드시 `event.preventDefault()`를 호출해야 합니다. - -Windows에선 `process.argv` (메인 프로세스에서)를 통해 파일 경로를 얻을 수 있습니다. - -### Event: 'open-url' _macOS_ - -Returns: - -* `event` Event -* `url` String - -유저가 애플리케이션을 통해 URL을 열고자 할 때 발생하는 이벤트입니다. - -애플리케이션에서 URL을 열기 위해 반드시 URL 스킴이 등록되어 있어야 합니다. - -이 이벤트를 처리할 땐 반드시 `event.preventDefault()`를 호출해야 합니다. - -### Event: 'activate' _macOS_ - -Returns: - -* `event` Event -* `hasVisibleWindows` Boolean - -애플리케이션이 활성화 되었을 때 발생하는 이벤트입니다. 이 이벤트는 사용자가 -애플리케이션의 dock 아이콘을 클릭했을 때 주로 발생합니다. - -### Event: 'continue-activity' _macOS_ - -Returns: - -* `event` Event -* `type` String - Activity를 식별하는 문자열. - [`NSUserActivity.activityType`][activity-type]을 맵핑합니다. -* `userInfo` Object - 다른 기기의 activity에서 저장된 앱-특정 상태를 포함합니다. - -다른 기기에서 받아온 activity를 재개하려고 할 때 [Handoff][handoff] 하는 동안 -발생하는 이벤트입니다. 이 이벤트를 처리하려면 반드시 `event.preventDefault()`를 -호출해야 합니다. - -사용자 activity는 activity의 소스 애플리케이션과 같은 개발자 팀 ID를 가지는 -애플리케이션 안에서만 재개될 수 있고, activity의 타입을 지원합니다. 지원하는 -activity의 타입은 애플리케이션 `Info.plist`의 `NSUserActivityTypes` 키에 열거되어 -있습니다. - -### Event: 'browser-window-blur' - -Returns: - -* `event` Event -* `window` BrowserWindow - -[browserWindow](browser-window.md)에 대한 포커스가 사라졌을 때 발생하는 이벤트입니다. - -### Event: 'browser-window-focus' - -Returns: - -* `event` Event -* `window` BrowserWindow - -[browserWindow](browser-window.md)에 대한 포커스가 발생했을 때 발생하는 이벤트입니다. - -**역자주:** _포커스_ 는 창을 클릭해서 활성화 시켰을 때를 말합니다. - -### Event: 'browser-window-created' - -Returns: - -* `event` Event -* `window` BrowserWindow - -새로운 [browserWindow](browser-window.md)가 생성되었을 때 발생하는 이벤트입니다. - -### Event: 'web-contents-created' - -Returns: - -* `event` Event -* `webContents` WebContents - -새로운 [webContents](web-contents.md)가 생성되었을 때 발생하는 이벤트입니다. - -### Event: 'certificate-error' - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `url` URL -* `error` String - 에러 코드 -* `certificate` Object - * `data` Buffer - PEM 인코딩된 데이터 - * `issuerName` String -* `callback` Function - -`url`에 대한 `certificate` 인증서의 유효성 검증에 실패했을 때 발생하는 이벤트입니다. -인증서를 신뢰한다면 `event.preventDefault()` 와 `callback(true)`를 호출하여 -기본 동작을 방지하고 인증을 승인할 수 있습니다. - -```javascript -app.on('certificate-error', (event, webContents, url, error, certificate, callback) => { - if (url === 'https://github.com') { - // 확인 로직. - event.preventDefault(); - callback(true); - } else { - callback(false); - } -}); -``` - -### Event: 'select-client-certificate' - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `url` URL -* `certificateList` [Objects] - * `data` Buffer - PEM으로 인코딩된 데이터 - * `issuerName` String - 발급자의 공통 이름 -* `callback` Function - -클라이언트 인증이 요청되었을 때 발생하는 이벤트입니다. - -`url`은 클라이언트 인증서를 요청하는 탐색 항목에 해당합니다. -그리고 `callback`은 목록에서 필터링된 항목과 함께 호출될 필요가 있습니다. -이 이벤트에서의 `event.preventDefault()` 호출은 초기 인증 때 저장된 데이터를 사용하는 -것을 막습니다. - -```javascript -app.on('select-client-certificate', (event, webContents, url, list, callback) => { - event.preventDefault(); - callback(list[0]); -}); -``` - -### Event: 'login' - -Returns: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `request` Object - * `method` String - * `url` URL - * `referrer` URL -* `authInfo` Object - * `isProxy` Boolean - * `scheme` String - * `host` String - * `port` Integer - * `realm` String -* `callback` Function - -`webContents`가 기본 인증을 요청할 때 발생하는 이벤트입니다. - -기본 동작은 인증 요청을 모두 취소시킵니다. -동작을 새로 정의하려면 반드시 `event.preventDefault()`를 호출한 후 -`callback(username, password)` 형태의 콜백을 호출하여 인증을 처리해야 합니다. - -```javascript -app.on('login', (event, webContents, request, authInfo, callback) => { - event.preventDefault(); - callback('username', 'secret'); -}); -``` - -### Event: 'gpu-process-crashed' - -GPU가 작동하던 중 크래시가 일어났을 때 발생하는 이벤트입니다. - -### Event: 'accessibility-support-changed' _macOS_ _Windows_ - -Returns: - -* `event` Event -* `accessibilitySupportEnabled` Boolean - Chrome의 접근성 지원이 활성화되어있으면 - `true`를 반환하고 아니라면 `false`를 반환합니다. - -Chrome의 접근성 지원이 변경될 때 발생하는 이벤트입니다. 이 이벤트는 스크린 리더와 같은 -접근성 기술이 활성화되거나 비활성화될 때 발생합니다. -자세한 내용은 https://www.chromium.org/developers/design-documents/accessibility 를 -참고하세요. - -## Methods - -`app` 객체는 다음과 같은 메서드를 가지고 있습니다: - -**참고:** 몇몇 메서드는 특정 플랫폼에서만 작동합니다. - -### `app.quit()` - -모든 윈도우 종료를 시도합니다. `before-quit` 이벤트가 먼저 발생합니다. -모든 윈도우가 성공적으로 종료되면 `will-quit` 이벤트가 발생하고 기본 동작에 따라 -애플리케이션이 종료됩니다. - -이 함수는 모든 `beforeunload`와 `unload` 이벤트 핸들러가 제대로 실행됨을 보장합니다. -`beforeunload` 이벤트 핸들러에서 `false`를 반환했을 때 윈도우 종료가 취소 될 수 -있습니다. - -### `app.exit(exitCode)` - -* `exitCode` Integer - -`exitCode`와 함께 애플리케이션을 즉시 종료합니다. - -모든 윈도우는 사용자의 동의 여부에 상관없이 즉시 종료되며 `before-quit` 이벤트와 -`will-quit` 이벤트가 발생하지 않습니다. - -### `app.relaunch([options])` - -* `options` Object (optional) - * `args` Array (optional) - * `execPath` String (optional) - -현재 인스턴스가 종료되면 애플리케이션을 재시작합니다. - -기본적으로 새 인스턴스는 같은 작업 디렉토리의 것과 함께 현재 인스턴스의 명령줄 인수를 -사용합니다. 만약 `args`가 지정되면, `args`가 기본 명령줄 인수 대신에 전달됩니다. -`execPath`가 지정되면, 현재 애플리케이션 대신 `execPath`가 실행됩니다. - -참고로 이 메서드는 애플리케이션을 종료하지 않으며, 애플리케이션을 다시 시작시키려면 -`app.relaunch`를 호출한 후 `app.quit` 또는 `app.exit`를 실행해주어야 합니다. - -`app.relaunch`가 여러 번 호출되면, 현재 인스턴스가 종료된 후 여러 인스턴스가 -시작됩니다. - -다음은 현재 인스턴스를 즉시 종료시킨 후 새로운 명령줄 인수를 추가하여 새 -인스턴스의 애플리케이션을 실행하는 예시입니다: - -```javascript -app.relaunch({args: process.argv.slice(1) + ['--relaunch']}) -app.exit(0) -``` - -### `app.focus()` - -Linux에선, 첫 번째로 보여지는 윈도우가 포커스됩니다. macOS에선, 애플리케이션을 활성화 -앱 상태로 만듭니다. Windows에선, 애플리케이션의 첫 윈도우에 포커스 됩니다. - -### `app.hide()` _macOS_ - -최소화를 하지 않고 애플리케이션의 모든 윈도우들을 숨깁니다. - -### `app.show()` _macOS_ - -숨긴 애플리케이션 윈도우들을 다시 보이게 만듭니다. 자동으로 포커스되지 않습니다. - -### `app.getAppPath()` - -현재 애플리케이션의 디렉터리를 반환합니다. - -### `app.getPath(name)` - -* `name` String - -`name`에 관련한 특정 디렉터리 또는 파일의 경로를 반환합니다. -경로를 가져오는 데 실패할 경우 `Error`를 반환합니다. - -**역자주:** 이 메서드는 운영체제에서 지정한 특수 디렉터리를 가져오는데 사용할 수 있습니다. - -`name`은 다음 목록에 있는 경로 중 하나를 선택해 사용할 수 있습니다: - -* `home` - 사용자의 홈 디렉터리. -* `appData` - 각 사용자의 애플리케이션 데이터 디렉터리. 기본 경로는 다음과 같습니다: - * `%APPDATA%` - Windows - * `$XDG_CONFIG_HOME` 또는 `~/.config` - Linux - * `~/Library/Application Support` - macOS -* `userData` - 애플리케이션의 설정을 저장하는 디렉터리. - 이 디렉터리는 기본적으로 `appData`에 애플리케이션 이름으로 생성된 폴더가 지정됩니다. -* `temp` - 임시 폴더 디렉터리. -* `userDesktop` - 현재 사용자의 데스트탑 디렉터리. -* `exe` - 현재 실행중인 Electron 바이너리 파일. -* `module` - `libchromiumcontent` 라이브러리. -* `desktop` - 사용자의 데스크탑 디렉터리. -* `documents` - 사용자의 "내 문서" 디렉터리. -* `downloads` - 사용자의 다운로드 디렉터리. -* `music` - 사용자의 음악 디렉터리. -* `pictures` - 사용자의 사진 디렉터리. -* `videos` - 사용자의 동영상 디렉터리. -* `pepperFlashSystemPlugin` - 시스템 버전의 Pepper Flash 플러그인의 전체 경로. - -### `app.setPath(name, path)` - -* `name` String -* `path` String - -`name`에 대한 특정 디렉터리나 파일의 경로인 `path`를 재정의합니다. -만약 지정한 디렉터리의 경로가 존재하지 않으면 디렉터리가 이 메서드를 통해 새로 -생성됩니다. 재정의에 실패했을 땐 `Error`를 반환합니다. - -이 메서드는 `app.getPath`에 정의되어 있는 `name`의 경로만 재정의할 수 있습니다. - -기본적으로, 웹 페이지의 쿠키와 캐시는 `userData` 디렉터리에 저장됩니다. -만약 이 위치를 변경하고자 한다면, 반드시 `app` 모듈의 `ready` 이벤트가 발생하기 전에 -`userData` 경로를 재정의해야 합니다. - -### `app.getVersion()` - -로드된 애플리케이션의 버전을 반환합니다. - -만약 `package.json` 파일에서 애플리케이션의 버전을 찾을 수 없는 경우, 현재 번들 또는 -실행 파일의 버전을 반환합니다. - -### `app.getName()` - -`package.json`에서 기술된 현재 애플리케이션의 이름을 반환합니다. - -npm 모듈 규칙에 따라 대부분의 경우 `package.json`의 `name` 필드는 소문자 이름을 -사용합니다. 하지만 Electron은 `name`대신 `productName` 필드를 주로 사용하기 때문에 -반드시 이 필드도 같이 지정해야 합니다. 이 필드는 맨 앞글자가 대문자인 애플리케이션 -전체 이름을 지정해야 합니다. - -### `app.setName(name)` - -* `name` String - -현재 애플리케이션의 이름을 덮어씌웁니다. - -### `app.getLocale()` - -현재 애플리케이션의 [로케일](https://ko.wikipedia.org/wiki/%EB%A1%9C%EC%BC%80%EC%9D%BC)을 -반환합니다. 반환될 수 있는 값은 [여기](locales.md)에서 찾아볼 수 있습니다. - -**참고:** 패키징된 앱을 배포할 때, `locales` 폴더도 같이 배포해야 합니다. - -**참고:** Windows에선 `ready` 이벤트가 발생한 이후에 이 메서드를 호출해야 합니다. - -### `app.addRecentDocument(path)` _macOS_ _Windows_ - -* `path` String - -최근 문서 목록에 `path`를 추가합니다. - -이 목록은 OS에 의해 관리됩니다. 최근 문서 목록은 Windows의 경우 작업 표시줄에서 찾을 -수 있고, macOS의 경우 dock 메뉴에서 찾을 수 있습니다. - -### `app.clearRecentDocuments()` _macOS_ _Windows_ - -최근 문서 목록을 모두 비웁니다. - -### `app.setAsDefaultProtocolClient(protocol)` _macOS_ _Windows_ - -* `protocol` String - 프로토콜의 이름, `://` 제외. 만약 앱을 통해 `electron://`과 - 같은 링크를 처리하고 싶다면, 이 메서드에 `electron` 인수를 담아 호출하면 됩니다. - -이 메서드는 지정한 프로토콜(URI scheme)에 대해 현재 실행파일을 기본 핸들러로 -등록합니다. 이를 통해 운영체제와 더 가깝게 통합할 수 있습니다. 한 번 등록되면, -`your-protocol://`과 같은 모든 링크에 대해 호출시 현재 실행 파일이 실행됩니다. -모든 링크, 프로토콜을 포함하여 애플리케이션의 인수로 전달됩니다. - -**참고:** macOS에선, 애플리케이션의 `info.plist`에 등록해둔 프로토콜만 사용할 수 -있습니다. 이는 런타임에서 변경될 수 없습니다. 이 파일은 간단히 텍스트 에디터를 -사용하거나, 애플리케이션을 빌드할 때 스크립트가 생성되도록 할 수 있습니다. 자세한 -내용은 [Apple의 참조 문서][CFBundleURLTypes]를 확인하세요. - -이 API는 내부적으로 Windows 레지스트리와 LSSetDefaultHandlerForURLScheme를 사용합니다. - -### `app.removeAsDefaultProtocolClient(protocol)` _macOS_ _Windows_ - -* `protocol` String - 프로토콜의 이름, `://` 제외. - -이 메서드는 현재 실행파일이 지정한 프로토콜(URI scheme)에 대해 기본 핸들러인지를 -확인합니다. 만약 그렇다면, 이 메서드는 앱을 기본 핸들러에서 제거합니다. - -### `app.isDefaultProtocolClient(protocol)` _macOS_ _Windows_ - -* `protocol` String - `://`를 제외한 프로토콜의 이름. - -이 메서드는 현재 실행 파일이 지정한 프로토콜에 대해 기본 동작인지 확인합니다. (URI -스킴) 만약 그렇다면 `true`를 반환하고 아닌 경우 `false`를 반환합니다. - -**참고:** macOS에선, 응용 프로그램이 프로토콜에 대한 기본 프로토콜 동작으로 -등록되었는지를 확인하기 위해 이 메서드를 사용할 수 있습니다. 또한 macOS에서 -`~/Library/Preferences/com.apple.LaunchServices.plist`를 확인하여 검증할 수도 -있습니다. 자세한 내용은 [Apple의 참조 문서][LSCopyDefaultHandlerForURLScheme]를 -참고하세요. - -이 API는 내부적으로 Windows 레지스트리와 LSSetDefaultHandlerForURLScheme를 사용합니다. - -### `app.setUserTasks(tasks)` _Windows_ - -* `tasks` Array - `Task` 객체의 배열 - -Windows에서 사용할 수 있는 JumpList의 [Tasks][tasks] 카테고리에 `task`를 추가합니다. - -`tasks`는 다음과 같은 구조를 가지는 `Task` 객체의 배열입니다: - -`Task` Object: -* `program` String - 실행할 프로그램의 경로. - 보통 현재 작동중인 애플리케이션의 경로인 `process.execPath`를 지정합니다. -* `arguments` String - `program`이 실행될 때 사용될 명령줄 인수. -* `title` String - JumpList에 표시할 문자열. -* `description` String - 이 작업에 대한 설명. -* `iconPath` String - JumpList에 표시될 아이콘의 절대 경로. - 아이콘을 포함하고 있는 임의의 리소스 파일을 사용할 수 있습니다. - 보통 애플리케이션의 아이콘을 그대로 사용하기 위해 `process.execPath`를 지정합니다. -* `iconIndex` Integer - 아이콘 파일의 인덱스. 만약 아이콘 파일이 두 개 이상의 - 아이콘을 가지고 있을 경우, 사용할 아이콘의 인덱스를 이 옵션으로 지정해 주어야 합니다. - 단, 아이콘을 하나만 포함하고 있는 경우 0을 지정하면 됩니다. - -### `app.makeSingleInstance(callback)` - -* `callback` Function - -현재 애플리케이션을 **Single Instance Application** 으로 만들어줍니다. -이 메서드는 애플리케이션이 여러 번 실행됐을 때 다중 인스턴스가 생성되는 대신 한 개의 -주 인스턴스만 유지되도록 만들 수 있습니다. 이때 중복 생성된 인스턴스는 주 인스턴스에 -신호를 보내고 종료됩니다. - -`callback`은 주 인스턴스가 생성된 이후 또 다른 인스턴스가 생성됐을 때 -`callback(argv, workingDirectory)` 형식으로 호출됩니다. `argv`는 두 번째 인스턴스의 -명령줄 인수이며 `workingDirectory`는 현재 작업중인 디렉터리입니다. 보통 대부분의 -애플리케이션은 이러한 콜백이 호출될 때 주 윈도우를 포커스하고 최소화되어있으면 창 -복구를 실행합니다. - -`callback`은 `app`의 `ready` 이벤트가 발생한 후 실행됨을 보장합니다. - -이 메서드는 현재 실행된 애플리케이션이 주 인스턴스인 경우 `false`를 반환하고 -애플리케이션의 로드가 계속 진행 되도록 합니다. 그리고 두 번째 중복된 인스턴스 생성인 -경우 `true`를 반환합니다. (다른 인스턴스에 인수가 전달됬을 때) 이 불리언 값을 통해 -중복 생성된 인스턴스는 즉시 종료시켜야 합니다. - -macOS에선 사용자가 Finder에서 애플리케이션의 두 번째 인스턴스를 열려고 했을 때 자동으로 -**Single Instance** 화 하고 `open-file`과 `open-url` 이벤트를 발생시킵니다. 그러나 -사용자가 애플리케이션을 CLI 터미널에서 실행하면 운영체제 시스템의 싱글 인스턴스 -메커니즘이 무시되며 그대로 중복 실행됩니다. 따라서 macOS에서도 이 메서드를 통해 확실히 -중복 실행을 방지하는 것이 좋습니다. - -다음 예시는 두 번째 인스턴스가 생성되었을 때 중복된 인스턴스를 종료하고 주 애플리케이션 -인스턴스의 윈도우를 활성화 시키는 예시입니다: - -```javascript -let myWindow = null; - -const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => { - // 애플리케이션을 중복 실행했습니다. 주 애플리케이션 인스턴스를 활성화 합니다. - if (myWindow) { - if (myWindow.isMinimized()) myWindow.restore(); - myWindow.focus(); - } - return true; -}); - -if (shouldQuit) { - app.quit(); - return; -} - -// 윈도우를 생성하고 각종 리소스를 로드하고 작업합니다. -app.on('ready', () => { -}); -``` - -### `app.releaseSingleInstance()` - -모든 `makeSingleInstance`에 의해 생성된 제한을 해제합니다. 이 메서드는 다시 여러 -인스턴스의 애플리케이션이 나란히 실행될 수 있도록 합니다. - -### `app.setUserActivity(type, userInfo[, webpageURL])` _macOS_ - -* `type` String - 고유하게 activity를 식별합니다. - [`NSUserActivity.activityType`][activity-type]을 맵핑합니다. -* `userInfo` Object - 다른 기기에서 사용하기 위해 저장할 앱-특정 상태. -* `webpageURL` String - 적당한 앱이 기기에 설치되지 않았을 때 브라우저에서 로드할 - 웹 페이지. 스킴은 반드시 `http` 또는 `https`가 되어야 합니다. - -`NSUserActivity`를 만들고 현재 activity에 설정합니다. 이 activity는 이후 다른 기기와 -[Handoff][handoff]할 때 자격으로 사용됩니다. - -### `app.getCurrentActivityType()` _macOS_ - -현재 작동중인 activity의 타입을 반환합니다. - -### `app.setAppUserModelId(id)` _Windows_ - -* `id` String - -[애플리케이션의 사용자 모델 ID][app-user-model-id]를 `id`로 변경합니다. - -### `app.importCertificate(options, callback)` _LINUX_ - -* `options` Object - * `certificate` String - pkcs12 파일의 위치. - * `password` String - 인증서의 암호. -* `callback` Function - * `result` Integer - 가져오기의 결과. - -pkcs12 형식으로된 인증서를 플랫폼 인증서 저장소로 가져옵니다. `callback`은 가져오기의 -결과를 포함하는 `result` 객체를 포함하여 호출됩니다. 값이 `0` 일 경우 성공을 의미하며 -다른 값은 모두 Chrominum의 [net_error_list](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h)에 -따라 실패를 의미합니다. - -### `app.disableHardwareAcceleration()` - -현재 애플리케이션의 하드웨어 가속을 비활성화합니다. - -이 메서드는 `app`의 `ready` 이벤트가 발생하기 전에만 호출할 수 있습니다. - -### `app.setBadgeCount(count)` _Linux_ _macOS_ - -* `count` Integer - -현재 앱에 대해 카운터 뱃지를 설정합니다. count를 `0`으로 설정하면 뱃지를 숨깁니다. -호출이 성공적으로 끝나면 `true`를 반환하고 아닌 경우 `false`를 반환합니다. - -macOS에선 독 아이콘에 표시됩니다. Linux에선 Unity 런처에서만 작동합니다. - -**참고:** Unity 런처는 이 기능을 작동하기 위해 `.desktop` 파일을 필요로 합니다. -이에 대한 자세한 내용은 [데스크톱 환경 통합][unity-requiremnt]을 참고하세요. - -### `app.getBadgeCount()` _Linux_ _macOS_ - -현재 카운터 뱃지에 표시중인 값을 반환합니다. - -### `app.isUnityRunning()` _Linux_ - -현재 데스크톱 환경이 Unity인지 여부를 반환합니다. - -### `app.isAccessibilitySupportEnabled()` _macOS_ _Windows_ - -`Boolean` 값을 반환하며 Chrome의 접근성 지원이 활성화되어있으면 `true`를 그렇지 -않다면 `false`를 반환합니다. 이 API는 사용할 수 있는 스크린 리더와 같은 접근성 기술이 -감지되었을 때 `true`를 반환합니다. 자세한 내용은 -https://www.chromium.org/developers/design-documents/accessibility 를 참고하세요. - -### `app.commandLine.appendSwitch(switch[, value])` - -Chrominum의 명령줄에 스위치를 추가합니다. `value`는 추가적인 값을 뜻하며 옵션입니다. - -**참고:** 이 메서드는 `process.argv`에 영향을 주지 않습니다. 개발자들은 보통 -Chrominum의 로우 레벨 수준의 동작을 제어하기 위해 주로 사용합니다. - -### `app.commandLine.appendArgument(value)` - -Chrominum의 명령줄에 인수를 추가합니다. 인수는 올바르게 인용됩니다. - -**참고:** 이 메서드는 `process.argv`에 영향을 주지 않습니다. - -### `app.dock.bounce([type])` _macOS_ - -* `type` String (optional) - `critical` 또는 `informational`을 지정할 수 있습니다. - 기본값은 `informational` 입니다. - -`critical`이 전달되면 dock 아이콘이 애플리케이션이 활성화되거나 요청이 중지되기 전까지 -통통 튀는 바운스 효과를 적용합니다. - -`informational`이 전달되면 dock 아이콘이 1초만 통통 튑니다. 하지만 애플리케이션이 -활성화되거나 요청이 중지되기 전까지 요청은 계속 활성화로 유지 됩니다. - -또한 요청을 취소할 때 사용할 수 있는 ID를 반환합니다. - -### `app.dock.cancelBounce(id)` _macOS_ - -* `id` Integer - -`app.dock.bounce([type])` 메서드에서 반환한 `id`의 바운스 효과를 취소합니다. - -### `app.dock.downloadFinished(filePath)` _macOS_ - -* `filePath` String - -`filePath`가 다운로드 폴더에 들어있다면 다운로드 스택을 바운스합니다. - -### `app.dock.setBadge(text)` _macOS_ - -* `text` String - -dock의 badge에 표시할 문자열을 설정합니다. - -### `app.dock.getBadge()` _macOS_ - -dock의 badge에 설정된 문자열을 반환합니다. - -### `app.dock.hide()` _macOS_ - -dock 아이콘을 숨깁니다. - -### `app.dock.show()` _macOS_ - -dock 아이콘을 표시합니다. - -### `app.dock.setMenu(menu)` _macOS_ - -* `menu` [Menu](menu.md) - -애플리케이션의 [dock menu][dock-menu]를 설정합니다. - -### `app.dock.setIcon(image)` _macOS_ - -* `image` [NativeImage](native-image.md) - -dock 아이콘의 `image`를 설정합니다. - -### `app.getLoginItemSettings()` _macOS_ - -앱의 로그인 항목 설정을 객체로 반환합니다. - -* `openAtLogin` Boolean - 앱이 로그인시 열리도록 설정되어있는 경우 `true`를 반환. -* `openAsHidden` Boolean - 앱이 로구인시 숨겨진 채로 열리도록 설정되어있는 경우 - `true`를 반환. -* `wasOpenedAtLogin` Boolean - 자동으로 로그인할 때 애플리케이션이 열려있었는지 여부. -* `wasOpenedAsHidden` Boolean - 앱이 숨겨진 로그인 항목처럼 열려있었는지 여부. - 이는 앱이 시작시 어떤 윈도우도 열지 않을 것을 표시합니다. -* `restoreState` Boolean - 앱이 이전 세션에서 상태를 복원하여 로그인 항목처럼 - 열려있었는지 여부. 이는 앱이 마지막으로 종료되었던 때에 열려있었던 윈도우를 복원하는 - 것을 표시합니다. - -### `app.setLoginItemSettings(settings)` _macOS_ - -* `settings` Object - * `openAtLogin` Boolean - `true`로 지정하면 로그인시 애플리케이션을 열도록 하며 - `false`로 지정시 로그인 항목에서 삭제합니다. - * `openAsHidden` Boolean - `true`로 지정하면 애플리케이션을 숨겨진 채로 열도록 - 합니다. 기본값은 `false`입니다. 사용자가 시스템 설정에서 이 설정을 변경할 수 - 있으며 앱이 열렸을 때 현재 값을 확인하려면 - `app.getLoginItemStatus().wasOpenedAsHidden`를 확인해야 합니다. - -앱의 로그인 항목 설정을 지정합니다. - -[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 -[tasks]:http://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 -[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 -[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-requiremnt]: ../tutorial/desktop-environment-integration.md#unity-launcher-shortcuts-linux diff --git a/docs-translations/ko-KR/api/auto-updater.md b/docs-translations/ko-KR/api/auto-updater.md deleted file mode 100644 index 8dedf6ba8e1b8..0000000000000 --- a/docs-translations/ko-KR/api/auto-updater.md +++ /dev/null @@ -1,126 +0,0 @@ -# autoUpdater - -> 애플리케이션이 자동으로 업데이트를 진행할 수 있도록 기능을 활성화합니다. - -`autoUpdater` 모듈은 [Squirrel](https://github.com/Squirrel) 프레임워크에 대한 -인터페이스를 제공합니다. - -다음 프로젝트 중 하나를 선택하여, 애플리케이션을 배포하기 위한 멀티-플랫폼 릴리즈 -서버를 손쉽게 구축할 수 있습니다: - -- [nuts][nuts]: *애플리케이션을 위한 똑똑한 릴리즈 서버이며 GitHub를 백엔드로 - 사용합니다. Squirrel을 통해 자동 업데이트를 지원합니다. (Mac & Windows)* -- [electron-release-server][electron-release-server]: *완벽하게 모든 기능을 -지원하는 electron 애플리케이션을 위한 자가 호스트 릴리즈 서버입니다. autoUpdater와 -호환됩니다* -- [squirrel-updates-server][squirrel-updates-server]: *GitHub 릴리즈를 사용하는 -Squirrel.Mac 와 Squirrel.Windows를 위한 간단한 node.js 기반 서버입니다* - -## 플랫폼별 참고 사항 - -`autoUpdater`는 기본적으로 모든 플랫폼에 대해 같은 API를 제공하지만, 여전히 플랫폼별로 -약간씩 다른 점이 있습니다. - -### macOS - -macOS에선 `autoUpdater`가 [Squirrel.Mac][squirrel-mac]를 기반으로 작동합니다. -따라서 이 모듈을 작동시키기 위해 특별히 준비해야 할 작업은 없습니다. -서버 사이드 요구 사항은 [서버 지원][server-support]을 참고하세요. - -**참고:** macOS에서 자동 업데이트를 지원하려면 반드시 사인이 되어있어야 합니다. -이것은 `Squirrel.Mac`의 요구 사항입니다. - -### Windows - -Windows에선 `autoUpdater`를 사용하기 전에 애플리케이션을 사용자의 장치에 -설치해야 합니다. [electron-winstaller][installer-lib], -[electron-builder][electron-builder-lib] 또는 -[grunt-electron-installer][installer]를 사용하여 애플리케이션 인스톨러를 만드는 것을 -권장합니다. - -Windows에선 `autoUpdater` 모듈을 사용하기 전에 사용자의 장치에 애플리케이션을 -설치해야 합니다. 따라서 [electron-winstaller][installer-lib] 모듈이나 -[grunt-electron-installer][installer] 패키지를 사용하여 애플리케이션 인스톨러를 -만드는 것을 권장합니다. - -Squirrel로 생성된 인스톨러는 [Application User Model ID][app-user-model-id]와 함께 -`com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`으로 형식화된 바로가기 아이콘을 -생성합니다. `com.squirrel.slack.Slack` 과 `com.squirrel.code.Code`가 그 예시입니다. -`app.setAppUserModelId` API를 통해 애플리케이션 ID를 동일하게 유지해야 합니다. 그렇지 -않으면 Windows 작업 표시줄에 애플리케이션을 고정할 때 제대로 적용되지 않을 수 있습니다. - -서버 사이드 요구 사항 또한 macOS와 다르게 적용됩니다. 자세한 내용은 -[Squirrel.Windows][squirrel-windows]를 참고하세요. - -### Linux - -Linux는 따로 `autoUpdater`를 지원하지 않습니다. -각 배포판의 패키지 관리자를 통해 애플리케이션 업데이트를 제공하는 것을 권장합니다. - -## Events - -`autoUpdater` 객체는 다음과 같은 이벤트를 발생시킵니다: - -### Event: 'error' - -Returns: - -* `error` Error - -업데이트에 문제가 생기면 발생하는 이벤트입니다. - -### Event: 'checking-for-update' - -업데이트를 확인하기 시작할 때 발생하는 이벤트입니다. - -### Event: 'update-available' - -사용 가능한 업데이트가 있을 때 발생하는 이벤트입니다. 이벤트는 자동으로 다운로드 됩니다. - -### Event: 'update-not-available' - -사용 가능한 업데이트가 없을 때 발생하는 이벤트입니다. - -### Event: 'update-downloaded' - -Returns: - -* `event` Event -* `releaseNotes` String -* `releaseName` String -* `releaseDate` Date -* `updateURL` String - -업데이트의 다운로드가 완료되었을 때 발생하는 이벤트입니다. - -## Methods - -`autoUpdater` 객체에서 사용할 수 있는 메서드입니다: - -### `autoUpdater.setFeedURL(url[, requestHeaders])` - -* `url` String -* `requestHeaders` Object _macOS_ - HTTP 요청 헤더. - -`url`을 설정하고 자동 업데이터를 초기화합니다. - -### `autoUpdater.checkForUpdates()` - -서버에 새로운 업데이트가 있는지 요청을 보내 확인합니다. API를 사용하기 전에 -`setFeedURL`를 호출해야 합니다. - -### `autoUpdater.quitAndInstall()` - -애플리케이션을 다시 시작하고 다운로드된 업데이트를 설치합니다. -이 메서드는 `update-downloaded` 이벤트가 발생한 이후에만 사용할 수 있습니다. - -[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-builder-lib]: https://github.com/electron-userland/electron-builder -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx -[electron-release-server]: https://github.com/ArekSredzki/electron-release-server -[squirrel-updates-server]: https://github.com/Aluxian/squirrel-updates-server -[nuts]: https://github.com/GitbookIO/nuts diff --git a/docs-translations/ko-KR/api/browser-window.md b/docs-translations/ko-KR/api/browser-window.md deleted file mode 100644 index be4e8550ca939..0000000000000 --- a/docs-translations/ko-KR/api/browser-window.md +++ /dev/null @@ -1,1060 +0,0 @@ -# BrowserWindow - -> 브라우저 윈도우를 생성하고 제어합니다. - -다음 예시는 윈도우를 생성합니다: - -```javascript -// 메인 프로세스에서 -const {BrowserWindow} = require('electron') - -// 또는 렌더러 프로세스에서 -const {BrowserWindow} = require('electron').remote - -let win = new BrowserWindow({width: 800, height: 600}) -win.on('closed', () => { - win = null; -}) - -win.loadURL('https://github.com'); -``` - -## Frameless 윈도우 - -Frameless 윈도우를 만들거나 일정한 모양의 투명한 윈도우를 만드려면, -[Frameless 윈도우](frameless-window.md) API를 사용할 수 있습니다. - -## 우아하게 윈도우 표시하기 - -윈도우에서 페이지를 로딩할 때, 사용자는 페이지가 로드되는 모습을 볼 것입니다. -네이티브 어플리케이션으로써 좋지 않은 경험입니다. 윈도우가 시각적인 깜빡임 없이 -표시되도록 만드려면, 서로 다른 상황을 위해 두 가지 방법이 있습니다. - -### `ready-to-show` 이벤트 사용하기 - -페이지가 로딩되는 동안, `ready-to-show` 이벤트가 랜더러 프로세스가 랜더링이 완료되었을 -때 처음으로 발생합니다. 이 이벤트 이후로 윈도우를 표시하면 시각적인 깜빡임 없이 표시할 -수 있습니다. - -```javascript -let win = new BrowserWindow({show: false}) -win.once('ready-to-show', () => { - win.show() -}) -``` - -이 이벤트는 보통 `did-finish-load` 이벤트 이후에 발생하지만, 페이지가 너무 많은 외부 -리소스를 가지고 있다면, `did-finish-load` 이벤트가 발생하기 이전에 발생할 수도 -있습니다. - -### `backgroundColor` 설정하기 - -복잡한 어플리케이션에선, `ready-to-show` 이벤트가 너무 늦게 발생할 수 있습니다. -이는 사용자가 어플리케이션이 느리다고 생각할 수 있습니다. 이러한 경우 어플리케이션 -윈도우를 바로 보이도록 하고 어플리케이션의 배경과 가까운 배경색을 `backgroundColor`을 -통해 설정합니다: - -```javascript -let win = new BrowserWindow({backgroundColor: '#2e2c29'}) -win.loadURL('https://github.com') -``` - -참고로 `ready-to-show` 이벤트를 사용하더라도 어플리케이션을 네이티브 느낌이 나도록 -하기 위해 `backgroundColor`도 같이 설정하는 것을 권장합니다. - -## 부모와 자식 윈도우 - -`parent` 옵션을 사용하면 자식 윈도우를 만들 수 있습니다: - -```javascript -let top = new BrowserWindow() -let child = new BrowserWindow({parent: top}) -``` - -`child` 윈도우는 언제나 `top` 윈도우의 상위에 표시됩니다. - -### 모달 윈도우 - -모달 윈도우는 부모 윈도우를 비활성화 시키는 자식 윈도우입니다. 모달 윈도우를 만드려면 `parent`, `modal` 옵션을 동시에 설정해야 합니다: - -```javascript -let child = new BrowserWindow({parent: top, modal: true, show: false}) -child.loadURL('https://github.com') -child.once('ready-to-show', () => { - child.show() -}) -``` - -### 플랫폼별 특이사항 - -* 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 Windows it is not supported to change parent window dynamically. -* On Linux the type of modal windows will be changed to `dialog`. -* On Linux many desktop environments do not support hiding a modal window. - -## Class: BrowserWindow - -`BrowserWindow`는 [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter)를 -상속받은 클래스 입니다. - -`BrowserWindow`는 `options`를 통해 네이티브 속성을 포함한 새로운 윈도우를 생성합니다. - -### `new BrowserWindow([options])` - -`options` 객체 (optional), 사용할 수 있는 속성들: - -* `width` Integer - 윈도우의 가로 너비. 기본값은 `800`입니다. -* `height` Integer - 윈도우의 세로 높이. 기본값은 `600`입니다. -* `x` Integer (**required** y가 사용되면) - 화면을 기준으로 창 좌측을 오프셋 한 위치. - 기본값은 `화면중앙`입니다. -* `y` Integer (**required** x가 사용되면) - 화면을 기준으로 창 상단을 오프셋 한 위치. - 기본값은 `화면중앙`입니다. -* `useContentSize` Boolean - `width`와 `height`를 웹 페이지의 크기로 사용합니다. - 이 속성을 사용하면 웹 페이지의 크기에 윈도우 프레임 크기가 추가되므로 실제 창은 조금 - 더 커질 수 있습니다. 기본값은 `false`입니다. -* `center` Boolean - 윈도우를 화면 정 중앙에 위치시킵니다. -* `minWidth` Integer - 윈도우의 최소 가로 너비. 기본값은 `0`입니다. -* `minHeight` Integer - 윈도우의 최소 세로 높이. 기본값은 `0`입니다. -* `maxWidth` Integer - 윈도우의 최대 가로 너비. 기본값은 `제한없음`입니다. -* `maxHeight` Integer - 윈도우의 최대 세로 높이. 기본값은 `제한없음`입니다. -* `resizable` Boolean - 윈도우의 크기를 재조정 할 수 있는지 여부. 기본값은 `true` - 입니다. -* `movable` Boolean - 윈도우를 이동시킬 수 있는지 여부. Linux에선 구현되어있지 - 않습니다. 기본값은 `true` 입니다. -* `minimizable` Boolean - 윈도우를 최소화시킬 수 있는지 여부. Linux에선 구현되어있지 - 않습니다. 기본값은 `true` 입니다. -* `maximizable` Boolean - 윈도우를 최대화시킬 수 있는지 여부. Linux에선 구현되어있지 - 않습니다. 기본값은 `true` 입니다. -* `closable` Boolean - 윈도우를 닫을 수 있는지 여부. Linux에선 구현되어있지 않습니다. - 기본값은 `true` 입니다. -* `focusable` Boolean - 윈도우가 포커스될 수 있는지 여부입니다. 기본값은 - `true`입니다. Windows에선 `focusable: false`를 설정함으로써 암시적으로 - `skipTaskbar: true`도 설정됩니다. Linux에선 `focusable: false`를 설정함으로써 - 윈도우가 wm과 함께 반응을 중지하며 모든 작업 영역에서 윈도우가 언제나 최상단에 있게 - 됩니다. -* `alwaysOnTop` Boolean - 윈도우이 언제나 다른 창들 위에 유지되는지 여부. - 기본값은 `false`입니다. -* `fullscreen` Boolean - 윈도우의 전체화면 활성화 여부. 이 속성을 명시적으로 - `false`로 지정했을 경우, macOS에선 전체화면 버튼이 숨겨지거나 비활성됩니다. 기본값은 - `false` 입니다. -* `fullscreenable` Boolean - 윈도우가 전체화면 모드로 전환될 수 있는지 여부입니다. - 또한 macOS에선, 최대화/줌 버튼이 전체화면 모드 또는 윈도우 최대화를 실행할지 여부도 - 포함됩니다. 기본값은 `true`입니다. -* `skipTaskbar` Boolean - 작업표시줄 애플리케이션 아이콘 표시 스킵 여부. 기본값은 - `false`입니다. -* `kiosk` Boolean - Kiosk(키오스크) 모드. 기본값은 `false`입니다. -* `title` String - 기본 윈도우 제목. 기본값은 `"Electron"`입니다. -* `icon` [NativeImage](native-image.md) - 윈도우 아이콘, 생략하면 실행 파일의 - 아이콘이 대신 사용됩니다. -* `icon` [NativeImage](native-image.md) - 윈도우 아이콘. Windows에선 가장 좋은 - 시각적 효과를 얻기 위해 `ICO`를 사용하는 것을 권장하며, 또한 undefined로 남겨두면 - 실행 파일의 아이콘이 대신 사용됩니다. -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 - 윈도우가 생성되면 보여줄지 여부. 기본값은 `true`입니다. -* `frame` Boolean - `false`로 지정하면 창을 [Frameless Window](frameless-window.md) - 형태로 생성합니다. 기본값은 `true`입니다. -* `parent` BrowserWindow - 부모 윈도우를 설정합니다. 기본 값은 `null`입니다. -* `modal` Boolean - 이 윈도우가 모달 윈도우인지 여부를 설정합니다. 이 옵션은 자식 - 윈도우에서만 작동합니다. 기본값은 `false`입니다. -* `acceptFirstMouse` Boolean - 윈도우가 비활성화 상태일 때 내부 콘텐츠 클릭 시 - 활성화 되는 동시에 단일 mouse-down 이벤트를 발생시킬지 여부. 기본값은 `false`입니다. -* `disableAutoHideCursor` Boolean - 타이핑중 자동으로 커서를 숨길지 여부. 기본값은 - `false`입니다. -* `autoHideMenuBar` Boolean - `Alt`를 누르지 않는 한 애플리케이션 메뉴바를 숨길지 - 여부. 기본값은 `false`입니다. -* `enableLargerThanScreen` Boolean - 윈도우 크기가 화면 크기보다 크게 재조정 될 - 수 있는지 여부. 기본값은 `false`입니다. -* `backgroundColor` String - `#66CD00` 와 `#FFF`, `#80FFFFFF` (알파 지원됨) 같이 - 16진수로 표현된 윈도우의 배경 색. 기본값은 `#FFF` (white). -* `hasShadow` Boolean - 윈도우가 그림자를 가질지 여부를 지정합니다. 이 속성은 - macOS에서만 구현되어 있습니다. 기본값은 `true`입니다. -* `darkTheme` Boolean - 설정에 상관 없이 무조건 어두운 윈도우 테마를 사용합니다. - 몇몇 GTK+3 데스크톱 환경에서만 작동합니다. 기본값은 `false`입니다. -* `transparent` Boolean - 윈도우를 [투명화](frameless-window.md)합니다. 기본값은 - `false`입니다. -* `type` String - 특정 플랫폼에만 적용되는 윈도우의 종류를 지정합니다. 기본값은 - 일반 윈도우 입니다. 사용할 수 있는 창의 종류는 아래를 참고하세요. -* `standardWindow` Boolean - macOS의 표준 윈도우를 텍스쳐 윈도우 대신 사용합니다. - 기본 값은 `true`입니다. -* `titleBarStyle` String, macOS - 윈도우 타이틀 바 스타일을 지정합니다. 자세한 사항은 - 아래를 참고하세요. -* `thickFrame` Boolean - Windows에서 테두리 없는 윈도우를 위해 표준 윈도우 프레임을 - 추가하는 `WS_THICKFRAME` 스타일을 사용합니다. `false`로 지정하면 윈도우의 그림자와 - 애니메이션을 삭제합니다. 기본값은 `true`입니다. -* `webPreferences` Object - 웹 페이지 기능을 설정합니다. 사용할 수 있는 속성은 - 아래를 참고하세요. - -`minWidth`/`maxWidth`/`minHeight`/`maxHeight`를 통해 최소 또는 최대 윈도우 크기를 -지정한 경우, 이는 사용자만을 제약하며, `setBounds`/`setSize` 또는 `BrowserWindow`의 -생성자에서 크기 제약을 따르지 않는 윈도우 크기를 전달하는 것은 막을 수 없습니다. - -`type` 속성에서 사용할 수 있는 값과 동작은 다음과 같으며, 플랫폼에 따라 다릅니다: - -* Linux의 경우, `desktop`, `dock`, `toolbar`, `splash`, `notification` 종류를 - 사용할 수 있습니다. -* macOS의 경우, `desktop`, `textured` 종류를 사용할 수 있습니다. - * `textured`는 창에 메탈 그라디언트 외관(`NSTexturedBackgroundWindowMask`)을 - 설정합니다. - * `desktop`은 데스크탑 배경 레벨(`kCGDesktopWindowLevel - 1`)에 윈도우를 - 배치합니다. 참고로 이렇게 만들어진 윈도우는 포커스, 키보드, 마우스 이벤트를 받을 - 수 없습니다. 하지만 편법으로 `globalShortcut`을 통해 키 입력을 받을 수 있습니다. -* Windows의 경우, 가능한 타입으론 `toolbar`가 있습니다. - -`titleBarStyle` 속성은 macOS 10.10 Yosemite 이후 버전만 지원하며, 다음 3가지 종류의 -값을 사용할 수 있습니다: - -* `default` 또는 미지정: 표준 Mac 회색 불투명 스타일을 사용합니다. -* `hidden`: 타이틀 바를 숨기고 콘텐츠 전체를 윈도우 크기에 맞춥니다. - 타이틀 바는 없어지지만 표준 창 컨트롤 ("신호등 버튼")은 왼쪽 상단에 유지됩니다. -* `hidden-inset`: `hidden` 타이틀 바 속성과 함께 신호등 버튼이 윈도우 모서리로부터 - 약간 더 안쪽으로 들어가도록합니다. - -`webPreferences` 속성은 다음과 같은 속성을 가질 수 있습니다: - -* `nodeIntegration` Boolean - node(node.js) 통합 여부. 기본값은 `true`입니다. -* `preload` String - 스크립트를 지정하면 페이지 내의 다른 스크립트가 작동하기 전에 - 로드됩니다. 여기서 지정한 스크립트는 node 통합 활성화 여부에 상관없이 언제나 모든 - node API에 접근할 수 있습니다. 이 속성의 스크립트 경로는 절대 경로로 지정해야 - 합니다. node 통합이 비활성화되어있을 경우, preload 스크립트는 node의 global - 심볼들을 다시 global 스코프로 다시 포함 시킬 수 있습니다. - [여기](process.md#event-loaded)의 예시를 참고하세요. -* `session` [Session](session.md#class-session) - 페이지에서 사용할 세션을 - 지정합니다. Session 객체를 직접적으로 전달하는 대신, 파티션 문자열을 받는 - `partition` 옵션을 사용할 수도 있습니다. `session`과 `partition`이 같이 - 제공되었을 경우 `session`이 사용됩니다. 기본값은 기본 세션입니다. - * `partition` String - 페이지에서 사용할 세션을 지정합니다. 만약 `partition`이 - `persist:`로 시작하면 페이지는 지속성 세션을 사용하며 다른 모든 앱 내의 - 페이지에서 같은 `partition`을 사용할 수 있습니다. 만약 `persist:` 접두어로 - 시작하지 않으면 페이지는 인-메모리 세션을 사용합니다. 여러 페이지에서 같은 - `partition`을 지정하면 같은 세션을 공유할 수 있습니다. `partition`을 지정하지 - 않으면 애플리케이션의 기본 세션이 사용됩니다. -* `zoomFactor` Number - 페이지의 기본 줌 값을 지정합니다. 예를 들어 `300%`를 - 표현하려면 `3.0`으로 지정합니다. 기본값은 `1.0`입니다. -* `javascript` Boolean - 자바스크립트를 활성화합니다. 기본값은 `false`입니다. -* `webSecurity` Boolean - `false`로 지정하면 same-origin 정책을 비활성화합니다. - (이 속성은 보통 사람들에 의해 웹 사이트를 테스트할 때 사용합니다) 그리고 - `allowDisplayingInsecureContent`와 `allowRunningInsecureContent` 두 속성을 - 사용자가 `true`로 지정되지 않은 경우 `true`로 지정합니다. 기본값은 - `true`입니다. -* `allowDisplayingInsecureContent` Boolean - https 페이지에서 http URL에서 - 로드한 이미지 같은 리소스를 표시할 수 있도록 허용합니다. 기본값은 `false`입니다. -* `allowRunningInsecureContent` Boolean - https 페이지에서 http URL에서 로드한 - JavaScript와 CSS 또는 플러그인을 실행시킬 수 있도록 허용합니다. 기본값은 - `false`입니다. -* `images` Boolean - 이미지 지원을 활성화합니다. 기본값은 `true`입니다. -* `textAreasAreResizable` Boolean - HTML TextArea 요소의 크기를 재조정을 - 허용합니다. 기본값은 `true`입니다. -* `webgl` Boolean - WebGL 지원을 활성화합니다. 기본값은 `true`입니다. -* `webaudio` Boolean - WebAudio 지원을 활성화합니다. 기본값은 `true`입니다. -* `plugins` Boolean - 플러그인 활성화 여부를 지정합니다. 기본값은 `false`입니다. -* `experimentalFeatures` Boolean - Chrome의 실험적인 기능을 활성화합니다. - 기본값은 `false`입니다. -* `experimentalCanvasFeatures` Boolean - Chrome의 실험적인 캔버스(canvas) 기능을 - 활성화합니다. 기본값은 `false`입니다. -* `directWrite` Boolean - Windows에서 폰트 렌더링을 위해 DirectWrite를 - 사용하는지를 지정합니다. 기본값은 `true`입니다. -* `scrollBounce` Boolean - macOS에서 스크롤 튕기기 효과 (탄성 밴딩)를 활성화 합니다. - 기본값은 `false`입니다. -* `blinkFeatures` String - 활성화 할 `CSSVariables,KeyboardEventKey`같이 `,`로 - 구분된 기능 문자열들의 리스트입니다. [RuntimeEnabledFeatures.in][blink-feature-string] - 파일에서 찾을 수 있습니다. -* `disableBlinkFeatures` String - 비활성화 할 `CSSVariables,KeyboardEventKey`같이 - `,`로 구분된 기능 문자열들의 리스트입니다. [RuntimeEnabledFeatures.in][blink-feature-string] - 파일에서 찾을 수 있습니다. -* `defaultFontFamily` Object - font-family의 기본 폰트를 지정합니다. - * `standard` String - 기본값 `Times New Roman`. - * `serif` String - 기본값 `Times New Roman`. - * `sansSerif` String - 기본값 `Arial`. - * `monospace` String - 기본값 `Courier New`. -* `defaultFontSize` Integer - 기본값 `16`. -* `defaultMonospaceFontSize` Integer - 기본값 `13`. -* `minimumFontSize` Integer - 기본값 `0`. -* `defaultEncoding` String - 기본값 `ISO-8859-1`. -* `backgroundThrottling` Boolean - 페이지가 백그라운드 상태에 진입할 때 애니메이션과 - 타이머에 스로틀을 적용할지 여부입니다. 기본값은 `true`입니다. - -## Events - -`BrowserWindow` 객체는 다음과 같은 이벤트를 발생시킵니다: - -**참고:** 몇몇 이벤트는 라벨에 특정한 OS에서만 작동합니다. - -### Event: 'page-title-updated' - -Returns: - -* `event` Event - -문서의 제목이 변경될 때 발생하는 이벤트입니다. `event.preventDefault()`를 호출하여 -네이티브 윈도우의 제목이 변경되는 것을 방지할 수 있습니다. - -### Event: 'close' - -Returns: - -* `event` Event - -윈도우가 닫히기 시작할 때 발생하는 이벤트입니다. -이 이벤트는 DOM의 `beforeunload` 와 `unload` 이벤트 전에 발생합니다. -`event.preventDefault()`를 호출하여 윈도우 종료를 취소할 수 있습니다. - -보통 창을 닫아야 할지 결정하기 위해 `beforeunload` 이벤트를 사용하려고 할 것입니다. -이 이벤트는 윈도우 콘텐츠를 새로고칠 때도 발생합니다. -Electron에선 `undefined`가 아닌 이외의 값을 전달할 경우 윈도우 종료를 취소합니다. -예시는 다음과 같습니다: - -```javascript -window.onbeforeunload = (e) => { - console.log('I do not want to be closed'); - - // 일반적인 브라우저와는 달리 사용자에게 확인 창을 보여주지 않고, non-void 값을 반환하면 - // 조용히 닫기를 취소합니다. - // Dialog API를 통해 사용자가 애플리케이션을 종료할지 정할 수 있도록 확인 창을 표시하는 것을 - // 추천합니다. - e.returnValue = false; -}; -``` - -### Event: 'closed' - -윈도우 종료가 완료된 경우 발생하는 이벤트입니다. 이 이벤트가 발생했을 경우 반드시 -윈도우의 레퍼런스가 더 이상 사용되지 않도록 제거해야 합니다. - -### Event: 'unresponsive' - -웹 페이지가 응답하지 않을 때 발생하는 이벤트입니다. - -### Event: 'responsive' - -응답하지 않는 웹 페이지가 다시 응답하기 시작했을 때 발생하는 이벤트입니다. - -### Event: 'blur' - -윈도우가 포커스를 잃었을 떄 발생하는 이벤트입니다. - -### Event: 'focus' - -윈도우가 포커스를 가졌을 때 발생하는 이벤트입니다. - -### Event: 'show' - -윈도우가 보여진 상태일 때 발생하는 이벤트입니다. - -### Event: 'hide' - -윈도우가 숨겨진 상태일 때 발생하는 이벤트입니다. - -### Event: 'ready-to-show' - -웹 페이지가 완전히 랜더링되어 윈도우가 시각적인 깜빡임없이 컨텐츠를 보여줄 수 있을 때 -발생하는 이벤트입니다. - -### Event: 'maximize' - -윈도우가 최대화됐을 때 발생하는 이벤트입니다. - -### Event: 'unmaximize' - -윈도우의 최대화 상태가 해제되었을 때 발생하는 이벤트입니다. - -### Event: 'minimize' - -윈도우가 최소화됐을 때 발생하는 이벤트입니다. - -### Event: 'restore' - -윈도우가 최소화 상태에서 복구되었을 때 발생하는 이벤트입니다. - -### Event: 'resize' - -윈도우의 크기가 재조정될 때 발생하는 이벤트입니다. - -### Event: 'move' - -윈도우가 새로운 위치로 이동될 때 발생하는 이벤트입니다. - -__참고__: macOS에선 이 이벤트가 그저 `moved` 이벤트의 별칭(alias)으로 사용됩니다. - -### Event: 'moved' _macOS_ - -윈도우가 새로운 위치로 이동되었을 때 발생하는 이벤트입니다. (한 번만) - -### Event: 'enter-full-screen' - -윈도우가 풀 스크린 모드로 진입할 때 발생하는 이벤트입니다. - -### Event: 'leave-full-screen' - -윈도우가 풀 스크린 모드에서 해제될 때 발생하는 이벤트입니다. - -### Event: 'enter-html-full-screen' - -윈도우가 HTML API에 의해 풀 스크린 모드로 진입할 때 발생하는 이벤트입니다. - -### Event: 'leave-html-full-screen' - -윈도우가 HTML API에 의해 풀 스크린 모드에서 해제될 때 발생하는 이벤트입니다. - -### Event: 'app-command' _Windows_ - -Returns: - -* `event` Event -* `command` String - -[App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx)가 -호출됐을 때 발생하는 이벤트입니다. 이 이벤트는 일반적으로 키보드 미디어 키 또는 -브라우저 커맨드(기본 동작 키)에 관련되어 있습니다. 예를 들어 Windows에서 작동하는 -몇몇 마우스는 "뒤로가기" 같은 동작을 포함하고 있습니다. - -반환되는 커맨드들은 모두 소문자화되며 언더스코어(`_`)는 하이픈(`-`)으로 변경되며 -`APPCOMMAND_` 접두어는 제거됩니다. -e.g. `APPCOMMAND_BROWSER_BACKWARD` 는 `browser-backward`와 같이 반환됩니다. - -```javascript -someWindow.on('app-command', (e, cmd) => { - // 마우스의 뒤로가기 버튼을 눌렀을 때 뒤로가기 탐색을 실행합니다 - if (cmd === 'browser-backward' && someWindow.webContents.canGoBack()) { - someWindow.webContents.goBack(); - } -}); -``` - -### Event: 'scroll-touch-begin' _macOS_ - -스크롤 휠 이벤트가 동작하기 시작했을 때 발생하는 이벤트입니다. - -### Event: 'scroll-touch-end' _macOS_ - -스크롤 휠 이벤트가 동작을 멈췄을 때 발생하는 이벤트입니다. - -### Event: 'swipe' _macOS_ - -Returns: - -* `event` Event -* `direction` String - -3-손가락 스와이프가 작동할 때 발생하는 이벤트입니다. 방향은 `up`, `right`, `down`, -`left`가 될 수 있습니다. - -## Methods - -`BrowserWindow` 객체는 다음과 같은 메서드를 가지고 있습니다: - -### `BrowserWindow.getAllWindows()` - -열려있는 모든 브라우저 윈도우의 배열을 반환합니다. - -### `BrowserWindow.getFocusedWindow()` - -애플리케이션에서 포커스된 윈도우를 반환합니다. 포커스된 윈도우가 없을 경우 `null`을 -반환합니다. - -### `BrowserWindow.fromWebContents(webContents)` - -* `webContents` [WebContents](web-contents.md) - -`webContents`를 소유하고 있는 윈도우를 찾습니다. - -### `BrowserWindow.fromId(id)` - -* `id` Integer - -ID에 해당하는 윈도우를 찾습니다. - -### `BrowserWindow.addDevToolsExtension(path)` - -* `path` String - -`path`에 있는 개발자 도구 확장 기능을 추가합니다. 그리고 확장 기능의 이름을 반환합니다. - -확장 기능은 기억됩니다. 따라서 API는 단 한 번만 호출되어야 합니다. 이 API는 실제 -프로그램 작성에 사용할 수 없습니다. 만약 이미 로드된 확장 기능을 추가하려 한다면, 이 -메서드는 아무것도 반환하지 않고 콘솔에 경고가 로그됩니다. - -**참고:** 이 API는 `app` 모듈의 `ready` 이벤트가 발생하기 전까지 사용할 수 없습니다. - -### `BrowserWindow.removeDevToolsExtension(name)` - -* `name` String - -`name`에 해당하는 개발자 도구 확장 기능을 제거합니다. - -**참고:** 이 API는 `app` 모듈의 `ready` 이벤트가 발생하기 전까지 사용할 수 없습니다. - -### `BrowserWindow.getDevToolsExtensions()` - -키는 확장 기능 이름을 값은 `name`과 `version` 속성을 포함하는 객체를 가지는 객체를 -반환합니다. - -개발자 도구 확장 기능이 설치되었는지 확인하려면 다음과 같이 실행할 수 있습니다: - -```javascript -let installed = BrowserWindow.getDevToolsExtensions().hasOwnProperty('devtron') -``` - -**참고:** 이 API는 `app` 모듈의 `ready` 이벤트가 발생하기 전까지 사용할 수 없습니다. - -## Instance Properties - -`new BrowserWindow`로 생성한 객체는 다음과 같은 속성을 가지고 있습니다: - -```javascript -// `win`은 BrowserWindow의 인스턴스입니다 -let win = new BrowserWindow({width: 800, height: 600}); -``` - -### `win.webContents` - -윈도우의 `WebContents` 객체입니다. 모든 웹 페이지와 관련된 이벤트와 작업이 이 객체를 -통해 수행됩니다. - -메서드나 이벤트에 대한 자세한 내용은 [`webContents` 문서](web-contents.md)를 -참고하세요. - -### `win.id` - -윈도우의 유일 ID입니다. - -## Instance Methods - -`new BrowserWindow`로 생성한 객체는 다음과 같은 메서드들을 가지고 있습니다: - -**참고:** 몇몇 메서드들은 라벨에서 특정한 운영체제 시스템에서만 작동합니다. - -### `win.destroy()` - -윈도우를 강제로 닫습니다. 웹 페이지의 `unload` 와 `beforeunload` 이벤트는 일어나지 -않습니다. 또한 이 윈도우의 `close`도 일어나지 않습니다. 하지만 `closed` 이벤트는 -반드시 발생함을 보장합니다. - -### `win.close()` - -윈도우의 종료를 시도합니다. 이 메서드는 사용자가 윈도우의 닫기 버튼을 클릭했을 때와 -같은 효과를 냅니다. 웹 페이지는 로드가 취소되고 종료됩니다. 자세한 내용은 -[close 이벤트](#event-close)를 참고하세요. - -### `win.focus()` - -윈도우에 포커스를 맞춥니다. - -### `win.blur()` - -윈도우의 포커스를 없앱니다. - -### `win.isFocused()` - -윈도우가 포커스되었는지 여부를 반환합니다. - -### `win.show()` - -윈도우를 표시하고 포커스합니다. - -### `win.showInactive()` - -윈도우를 표시만 하고 포커스하지 않습니다. - -### `win.hide()` - -윈도우를 숨깁니다. - -### `win.isVisible()` - -윈도우가 사용자에게 표시되고 있는지 여부를 반환합니다. - -### `win.isModal()` - -현재 윈도우가 모달 윈도우인지 여부를 반환합니다. - -### `win.maximize()` - -윈도우를 최대화 시킵니다. - -### `win.unmaximize()` - -윈도우 최대화를 취소합니다. - -### `win.isMaximized()` - -윈도우가 최대화 되어있는지 여부를 반환합니다. - -### `win.minimize()` - -윈도우를 최소화 시킵니다. 어떤 플랫폼은 최소화된 윈도우가 Dock에 표시됩니다. - -### `win.restore()` - -최소화된 윈도우를 이전 상태로 되돌립니다. - -### `win.isMinimized()` - -윈도우가 최소화되었는지 여부를 반환합니다. - -### `win.setFullScreen(flag)` - -* `flag` Boolean - -윈도우의 전체화면 상태를 지정합니다. - -### `win.isFullScreen()` - -윈도우가 전체화면 모드 상태인지 여부를 반환합니다. - -### `win.setAspectRatio(aspectRatio[, extraSize])` _macOS_ - -* `aspectRatio` 유지하려 하는 콘텐츠 뷰 일부의 종횡비 -* `extraSize` Object (optional) - 종횡비를 유지하는 동안 포함되지 않을 엑스트라 크기. - * `width` Integer - * `height` Integer - -이 메서드는 윈도우의 종횡비를 유지하는 기능을 수행합니다. 엑스트라 크기는 개발자가 -픽셀로 특정한 공간이 있을 때 종횡비 계산에서 제외됩니다. 이 API는 윈도우의 크기와 -콘텐츠 사이즈의 차이를 이미 고려하고 있습니다. - -일반 윈도우에서 작동하는 HD 비디오 플레이어와 관련된 컨트롤을 고려합니다. -만약 15 픽셀의 컨트롤이 왼쪽 가장자리에 있고 25 픽셀의 컨트롤이 오른쪽 가장자리에 -있으며 50 픽셀의 컨트롤이 플레이어 밑에 있을 때 플레이어 자체가 16:9 종횡비(HD의 표준 -종횡비는 @1920x1080)를 유지하기 위해선 이 함수를 16/9, [ 40, 50 ] 인수와 함께 -호출해야 합니다. 두번째 인수 엑스트라 크기는 존재하는 크기만 관여하고 콘텐츠 뷰 내의 -크기는 관여하지 않습니다. 그저 전체 콘텐츠 뷰 내에 있는 모든 엑스트라 너비, 높이 영역이 -합해집니다. - -### `win.setBounds(options[, animate])` - -* `options` Object - - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -* `animate` Boolean (optional) _macOS_ - -윈도우를 지정한 `width`, `height`, `x`, `y`로 크기 재조정 및 이동합니다. - -### `win.getBounds()` - -윈도우의 width, height, x, y 값을 가지는 객체를 반환합니다. - -### `win.setSize(width, height[, animate])` - -* `width` Integer -* `height` Integer -* `animate` Boolean (optional) _macOS_ - -`width`와 `height` 값으로 윈도우 크기를 재조정합니다. (너비, 높이) - -### `win.getSize()` - -윈도우의 너비, 높이값을 가지는 배열을 반환합니다. - -### `win.setContentSize(width, height[, animate])` - -* `width` Integer -* `height` Integer -* `animate` Boolean (optional) _macOS_ - -윈도우 클라이언트 영역(웹 페이지)의 크기를 `width`, `height`로 재조정합니다. - -### `win.getContentSize()` - -윈도우 클라이언트 영역의 너비, 높이 크기를 배열로 반환합니다. - -### `win.setMinimumSize(width, height)` - -* `width` Integer -* `height` Integer - -윈도우의 최소 `width`, `height` 크기를 지정합니다. - -### `win.getMinimumSize()` - -윈도우의 최소 너비, 높이 크기를 배열로 반환합니다. - -### `win.setMaximumSize(width, height)` - -* `width` Integer -* `height` Integer - -윈도우의 최대 `width`, `height` 크기를 지정합니다. - -### `win.getMaximumSize()` - -윈도우의 최대 너비, 높이 크기를 배열로 반환합니다. - -### `win.setResizable(resizable)` - -* `resizable` Boolean - -사용자에 의해 윈도우의 크기가 재조정될 수 있는지를 지정합니다. - -### `win.isResizable()` - -사용자에 의해 윈도우의 크기가 재조정될 수 있는지 여부를 반환합니다. - -### `win.setMovable(movable)` _macOS_ _Windows_ - -* `movable` Boolean - -사용자에 의해 윈도우를 이동시킬 수 있는지 여부를 지정합니다. Linux에선 아무 일도 -일어나지 않습니다. - -### `win.isMovable()` _macOS_ _Windows_ - -사용자에 의해 윈도우를 이동시킬 수 있는지 여부를 반환합니다. Linux에선 항상 `true`를 -반환합니다. - -### `win.setMinimizable(minimizable)` _macOS_ _Windows_ - -* `minimizable` Boolean - -사용자에 의해 윈도우를 최소화시킬 수 있는지 여부를 지정합니다. Linux에선 아무 일도 -일어나지 않습니다. - -### `win.isMinimizable()` _macOS_ _Windows_ - -사용자에 의해 윈도우를 최소화시킬 수 있는지 여부를 반환합니다. Linux에선 항상 `true`를 -반환합니다. - -### `win.setMaximizable(maximizable)` _macOS_ _Windows_ - -* `maximizable` Boolean - -사용자에 의해 윈도우를 최대화시킬 수 있는지 여부를 지정합니다. Linux에선 아무 일도 -일어나지 않습니다. - -### `win.isMaximizable()` _macOS_ _Windows_ - -사용자에 의해 윈도우를 최대화시킬 수 있는지 여부를 반환합니다. Linux에선 항상 `true`를 -반환합니다. - -### `win.setFullScreenable(fullscreenable)` - -* `fullscreenable` Boolean - -최대화/줌 버튼이 전체화면 모드 또는 윈도우 최대화를 토글할 수 있게 할지 여부를 -지정합니다. - -### `win.isFullScreenable()` - -최대화/줌 버튼이 전체화면 모드 또는 윈도우 최대화를 토글할 수 있게 할지 여부를 -반환합니다. - -### `win.setClosable(closable)` _macOS_ _Windows_ - -* `closable` Boolean - -사용자에 의해 윈도우가 수동적으로 닫힐 수 있는지 여부를 지정합니다. Linux에선 아무 일도 -일어나지 않습니다. - -### `win.isClosable()` _macOS_ _Windows_ - -사용자에 의해 윈도우가 수동적으로 닫힐 수 있는지 여부를 반환합니다. Linux에선 항상 -`true`를 반환합니다. - -### `win.setAlwaysOnTop(flag)` - -* `flag` Boolean - -윈도우가 언제나 다른 윈도우들 위에 표시되는지 여부를 지정합니다. 이 설정을 활성화 하면 -윈도우는 포커스 될 수 없는 툴박스 윈도우가 아닌 일반 윈도우로 유지됩니다. - -### `win.isAlwaysOnTop()` - -윈도우가 언제나 다른 윈도우들 위에 표시되는지 여부를 반환합니다. - -### `win.center()` - -윈도우를 화면 정 중앙으로 이동합니다. - -### `win.setPosition(x, y[, animate])` - -* `x` Integer -* `y` Integer -* `animate` Boolean (optional) _macOS_ - -윈도우의 위치를 `x`, `y`로 이동합니다. - -### `win.getPosition()` - -윈도우의 위치를 배열로 반환합니다. - -### `win.setTitle(title)` - -* `title` String - -`title`을 네이티브 윈도우의 제목으로 지정합니다. - -### `win.getTitle()` - -윈도우의 제목을 반환합니다. - -**참고:** 웹 페이지의 제목과 네이티브 윈도우의 제목은 서로 다를 수 있습니다. - -### `win.setSheetOffset(offsetY[, offsetX])` _macOS_ - -macOS에서 시트를 부착할 위치를 지정합니다. 기본적으로 시트는 윈도우의 프레임 바로 -아래의 위치에 부착됩니다. 아마도 이 기능은 보통 다음과 같이 HTML 렌더링된 툴바 밑에 -표시하기 위해 사용할 것입니다: - -```javascript -let toolbarRect = document.getElementById('toolbar').getBoundingClientRect(); -win.setSheetOffset(toolbarRect.height); -``` - -### `win.flashFrame(flag)` - -* `flag` Boolean - -사용자가 윈도우에 관심을 가질 수 있도록 창을 깜빡이거나 이를 중지합니다. - -### `win.setSkipTaskbar(skip)` - -* `skip` Boolean - -애플리케이션 아이콘을 작업표시줄에 보이지 않도록 설정합니다. - -### `win.setKiosk(flag)` - -* `flag` Boolean - -Kiosk(키오스크) 모드를 설정합니다. - -### `win.isKiosk()` - -현재 윈도우가 kiosk 모드인지 여부를 반환합니다. - -### `win.getNativeWindowHandle()` - -`Buffer` 상의 플랫폼에 따른 윈도우 핸들을 반환합니다. - -핸들의 타입에 따라 적절히 캐스팅됩니다. Windows의 `HWND`, macOS의 `NSView*`, Linux의 -`Window` (`unsigned long`)를 예로 들 수 있습니다. - -### `win.hookWindowMessage(message, callback)` _Windows_ - -* `message` Integer -* `callback` Function - -Windows 메시지 훅을 등록합니다. `callback`은 WndProc에서 메시지를 받았을 때 -호출됩니다. - -### `win.isWindowMessageHooked(message)` _Windows_ - -* `message` Integer - -지정한 메시지가 후킹됬는지 여부를 반환합니다. - -### `win.unhookWindowMessage(message)` _Windows_ - -* `message` Integer - -지정한 메시지 훅을 등록 해제합니다. - -### `win.unhookAllWindowMessages()` _Windows_ - -모든 메시지 훅을 등록 해제합니다. - -### `win.setRepresentedFilename(filename)` _macOS_ - -* `filename` String - -윈도우 대표 파일의 경로명을 설정합니다. 파일의 아이콘이 윈도우 타이틀 바에 표시됩니다. - -### `win.getRepresentedFilename()` _macOS_ - -윈도우 대표 파일의 경로명을 반환합니다. - -### `win.setDocumentEdited(edited)` _macOS_ - -* `edited` Boolean - -윈도우의 문서가 변경되었는지 여부를 설정합니다. 그리고 `true`로 설정했을 때 타이틀 바의 -아이콘이 회색으로 표시됩니다. - -### `win.isDocumentEdited()` _macOS_ - -윈도우의 문서가 변경되었는지 여부를 반환합니다. - -### `win.focusOnWebView()` - -### `win.blurWebView()` - -### `win.capturePage([rect, ]callback)` - -`webContents.capturePage([rect, ]callback)`와 같습니다. - -### `win.loadURL(url[, options])` - -`webContents.loadURL(url[, options])` API와 같습니다. - -### `win.reload()` - -`webContents.reload` API와 같습니다. - -### `win.setMenu(menu)` _Linux_ _Windows_ - -* `menu` Menu - -지정한 `menu`를 윈도우의 메뉴로 설정합니다 `null`을 설정하면 메뉴를 제거합니다. - -### `win.setProgressBar(progress)` - -* `progress` Double - -작업표시줄에 표시되고 있는 애플리케이션 아이콘에 진행 상태를 표시합니다. [0, 1.0] -사이의 값을 지정할 수 있습니다. - -진행 상태가 < 0 이 되면 진행 상태 표시를 제거합니다. -진행 상태가 > 1 이 되면 불확정 상태 표시로 전환합니다. - -Linux 플랫폼에선 Unity 데스크톱 환경만 지원합니다. 그리고 이 기능을 사용하려면 -`*.desktop` 파일을 생성한 후 `package.json`의 `desktopName` 필드에 파일 이름을 -지정해야 합니다. 기본적으로 `app.getName().desktop`을 통해 접근합니다. - -### `win.setOverlayIcon(overlay, description)` _Windows 7+_ - -* `overlay` [NativeImage](native-image.md) - 작업표시줄 아이콘의 우측 하단에 표시될 -아이콘입니다. `null`로 지정하면 빈 오버레이가 사용됩니다 -* `description` String - 접근성 설정에 의한 스크린 리더에 제공될 설명입니다 - -현재 작업표시줄 아이콘에 16 x 16 픽셀 크기의 오버레이를 지정합니다. 보통 이 기능은 -애플리케이션의 여러 상태를 사용자에게 소극적으로 알리기 위한 방법으로 사용됩니다. - -### `win.setHasShadow(hasShadow)` _macOS_ - -* `hasShadow` Boolean - -윈도우가 그림자를 가질지 여부를 지정합니다. Windows와 Linux에선 아무 일도 일어나지 -않습니다. - -### `win.hasShadow()` _macOS_ - -윈도우가 그림자를 가지고 있는지 여부를 반환합니다. Windows와 Linux에선 항상 `true`를 -반환합니다. - -### `win.setThumbarButtons(buttons)` _Windows 7+_ - -* `buttons` - Array - -윈도우 작업표시줄 버튼 레이아웃의 미리보기 이미지 영역에 미리보기 툴바와 버튼 세트를 -추가합니다. 반환되는 `Boolean` 값은 미리보기 툴바가 성공적으로 추가됬는지를 알려줍니다. - -미리보기 이미지 영역의 제한된 크기로 인해 미리보기 툴바에 추가될 수 있는 최대 버튼의 -개수는 7개이며 이 이상 추가될 수 없습니다. 플랫폼의 제약으로 인해 미리보기 툴바는 한 번 -설정되면 삭제할 수 없습니다. 하지만 이 API에 빈 배열을 전달하여 버튼들을 제거할 수 -있습니다. - -`buttons`는 `Button` 객체의 배열입니다: - -* `Button` 객체 - * `icon` [NativeImage](native-image.md) - 미리보기 툴바에 보여질 아이콘. - * `tooltip` String (optional) - 버튼의 툴팁 텍스트. - * `flags` Array (optional) - 버튼의 특정 동작 및 상태 제어. 기본적으로 `enabled`이 - 사용됩니다. 이 속성은 다음 문자열들을 포함할 수 있습니다: - * `enabled` - 사용자가 사용할 수 있도록 버튼이 활성화 됩니다. - * `disabled` - 버튼이 비활성화 됩니다. 버튼은 표시되지만 시각적인 상태는 사용자의 - 동작에 응답하지 않는 비활성화 상태로 표시됩니다. - * `dismissonclick` - 버튼이 클릭되면 작업표시줄 버튼의 미리보기(flyout)가 즉시 - 종료됩니다. - * `nobackground` - 버튼의 테두리를 표시하지 않습니다. 이미지에만 사용할 수 있습니다. - * `hidden` - 버튼을 사용자에게 표시되지 않도록 숨깁니다. - * `noninteractive` - 버튼은 활성화되어 있지만 반응이 제거되며 버튼을 눌러도 - 눌려지지 않은 상태를 유지합니다. 이 값은 버튼을 알림의 용도로 사용하기 위해 - 만들어졌습니다. - -### `win.showDefinitionForSelection()` _macOS_ - -`webContents.showDefinitionForSelection()`와 같습니다. - -### `win.setIcon(icon)` _Windows_ _Linux_ - -* `icon` [NativeImage](native-image.md) - -윈도우 아이콘을 변경합니다. - -### `win.setAutoHideMenuBar(hide)` - -* `hide` Boolean - -메뉴 막대 자동 숨김 기능을 활성화 합니다. -숨겨진 메뉴는 사용자가 `Alt` 키를 단일 입력했을 때만 표시됩니다. - -메뉴 막대가 이미 표시되고 있을 때 `setAutoHideMenuBar(true)`를 호출한다고 해서 -메뉴가 즉시 숨겨지지는 않습니다. - -### `win.isMenuBarAutoHide()` - -메뉴 막대 자동 숨김 상태인지 여부를 반환합니다. - -### `win.setMenuBarVisibility(visible)` - -* `visible` Boolean - -메뉴 막대의 표시 여부를 설정합니다. 만약 메뉴 막대 자동 숨김 상태라면 여전히 사용자가 -`Alt` 키를 입력하여 메뉴 막대를 표시되도록 할 수 있습니다. - -**역자주:** 기본 메뉴 막대를 완전히 없애려면 `win.setMenu(null)`를 호출해야 합니다. -단순히 이 API를 사용하면 여전히 메뉴에 등록된 핫 키가 작동합니다. - -### `win.isMenuBarVisible()` - -메뉴 막대가 표시되고 있는지 여부를 반환합니다. - -### `win.setVisibleOnAllWorkspaces(visible)` - -* `visible` Boolean - -윈도우가 모든 워크스페이스에서 표시될지 여부를 설정합니다. - -**참고:** 이 API는 Windows에서 아무 일도 하지 않습니다. - -### `win.isVisibleOnAllWorkspaces()` - -윈도우가 모든 워크스페이스에서 표시될지 여부를 반환합니다. - -**참고:** 이 API는 Windows에서 언제나 false를 반환합니다. - -### `win.setIgnoreMouseEvents(ignore)` - -* `ignore` Boolean - -윈도우가 모든 마우스 이벤트를 무시하게 만듭니다. - -이 윈도우에서 일어나는 모든 마우스 이벤트가 이 윈도우 밑의 윈도우로 전달됩니다. 하지만 -이 윈도우가 포커스되어 있다면, 여전히 키보드 이벤트는 받을 수 있습니다. - -### `win.setContentProtection(enable)` _macOS_ _Windows_ - -윈도우 콘텐츠가 외부 어플리케이션에 의해 캡쳐되는 것을 막습니다. - -macOS에선 NSWindow의 sharingType을 NSWindowSharingNone로 설정합니다. -Windows에선 WDA_MONITOR와 함께 SetWindowDisplayAffinity를 호출합니다. - -### `win.setFocusable(focusable)` _Windows_ - -* `focusable` Boolean - -윈도우가 포커스될 수 있는지 여부를 변경합니다. - -### `win.setParentWindow(parent)` _Linux_ _macOS_ - -* `parent` BrowserWindow - -`parent` 인수를 현재 윈도우의 부모 윈도우로 설정합니다. `null`로 설정하면 -현재 윈도우를 상위 윈도우로 전환합니다. - -### `win.getParentWindow()` - -모든 부모 윈도우를 반환합니다. - -### `win.getChildWindows()` - -모든 자식 윈도우를 반환합니다. - -[blink-feature-string]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in diff --git a/docs-translations/ko-KR/api/chrome-command-line-switches.md b/docs-translations/ko-KR/api/chrome-command-line-switches.md deleted file mode 100644 index 9a306735ececf..0000000000000 --- a/docs-translations/ko-KR/api/chrome-command-line-switches.md +++ /dev/null @@ -1,178 +0,0 @@ -# 크롬 명령줄 스위치 지원 - -> Electron에서 지원하는 커맨드 명령줄 스위치입니다. - -애플리케이션 메인 스크립트의 [app][app] 모듈에서 [ready][ready] 이벤트가 실행되기 -전에 [app.commandLine.appendSwitch][append-switch]를 호출하면, 애플리케이션의 -명령줄 옵션을 추가로 지정할 수 있습니다: - -```javascript -const {app} = require('electron'); -app.commandLine.appendSwitch('remote-debugging-port', '8315'); -app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1'); - -app.on('ready', () => { - // Your code here -}); -``` - -## --ignore-connections-limit=`domains` - -`domains` 리스트(`,`로 구분)의 연결 제한을 무시합니다. - -## --disable-http-cache - -HTTP 요청 캐시를 비활성화합니다. - -## --disable-http2 - -HTTP/2와 SPDY/3.1 프로토콜을 비활성화합니다. - -## --remote-debugging-port=`port` - -지정한 `port`에 HTTP 기반의 리모트 디버거를 활성화합니다. (개발자 도구) - -## --js-flags=`flags` - -JS 엔진에 지정한 플래그를 전달합니다. `flags`를 메인 프로세스에서 활성화하고자 한다면, -Electron이 시작되기 전에 스위치를 전달해야 합니다. - -```bash -$ electron --js-flags="--harmony_proxies --harmony_collections" your-app -``` - -## --proxy-server=`address:port` - -시스템 설정의 프록시 서버를 무시하고 지정한 서버로 연결합니다. HTTP와 HTTPS 요청에만 -적용됩니다. - -시스템 프록시 서버 설정을 무시하고 지정한 서버로 연결합니다. 이 스위치는 HTTP와 HTTPS -그리고 WebSocket 요청에만 적용됩니다. 그리고 모든 프록시 서버가 HTTPS가 WebSocket -요청을 지원하지 않고 있을 수 있으므로 사용시 주의해야 합니다. - -## --proxy-bypass-list=`hosts` - -Electron이 세미콜론으로 구분된 호스트 리스트에서 지정한 프록시 서버를 건너뛰도록 -지시합니다. - -예시: - -```javascript -app.commandLine.appendSwitch('proxy-bypass-list', ';*.google.com;*foo.com;1.2.3.4:5678'); -``` - -위 예시는 로컬 주소(`localhost`, `127.0.0.1`, 등)와 `google.com`의 서브도메인, -`foo.com`을 접미사로 가지는 호스트, `1.2.3.4:5678` 호스트를 제외한 모든 연결에서 -프록시 서버를 사용합니다. - -## --proxy-pac-url=`url` - -지정한 `url`의 PAC 스크립트를 사용합니다. - -## --no-proxy-server - -프록시 서버를 사용하지 않습니다. 다른 프록시 서버 플래그 및 설정을 무시하고 언제나 직접 -연결을 사용합니다. - -## --host-rules=`rules` - -Hostname 맵핑 규칙을 설정합니다. (`,`로 구분) - -예시: - -* `MAP * 127.0.0.1` 강제적으로 모든 호스트네임을 127.0.0.1로 맵핑합니다 -* `MAP *.google.com proxy` 강제적으로 모든 google.com의 서브도메인을 "proxy"로 - 연결합니다 -* `MAP test.com [::1]:77` 강제적으로 "test.com"을 IPv6 루프백으로 연결합니다. - 소켓 주소의 포트 또한 77로 고정됩니다. -* `MAP * baz, EXCLUDE www.google.com` "www.google.com"을 제외한 모든 것들을 - "baz"로 맵핑합니다. - -이 맵핑은 네트워크 요청시의 endpoint를 지정합니다. (TCP 연결과 직접 연결의 호스트 -resolver, http 프록시 연결의 `CONNECT`, `SOCKS` 프록시 연결의 endpoint 호스트) - -## --host-resolver-rules=`rules` - -`--host-rules` 플래그와 비슷하지만 이 플래그는 host resolver에만 적용됩니다. - -## --auth-server-whitelist=`url` - -통합 인증을 사용하도록 설정할 쉼표로 구분된 서버의 리스트. - -예를 들어: - -``` ---auth-server-whitelist='*example.com, *foobar.com, *baz' -``` - -그리고 모든 `example.com`, `foobar.com`, `baz`로 끝나는 `url`은 통합 인증을 -사용하도록 설정됩니다. `*` 접두어가 없다면 url은 정확히 일치해야 합니다. - -## --auth-negotiate-delegate-whitelist=`url` - -필수적인 사용자 자격 증명을 보내야 할 쉼표로 구분된 서버의 리스트. -`*` 접두어가 없다면 url은 정확히 일치해야 합니다. - -## --ignore-certificate-errors - -인증서 에러를 무시합니다. - -## --ppapi-flash-path=`path` - -Pepper 플래시 플러그인의 위치를 설정합니다. - -## --ppapi-flash-version=`version` - -Pepper 플래시 플러그인의 버전을 설정합니다. - -## --log-net-log=`path` - -Net log 이벤트를 활성화하고 `path`에 로그를 기록합니다. - -## --ssl-version-fallback-min=`version` - -TLS fallback에서 사용할 SSL/TLS 최소 버전을 지정합니다. (`tls1`, `tls1.1`, `tls1.2`) - -## --cipher-suite-blacklist=`cipher_suites` - -SSL 암호화를 비활성화할 대상 목록을 지정합니다. (`,`로 구분) - -## --disable-renderer-backgrounding - -Chromium이 렌더러 프로세스의 보이지 않는 페이지의 우선순위를 낮추는 것을 방지합니다. - -이 플래그는 전역적이며 모든 렌더러 프로세스에 적용됩니다. 만약 하나의 윈도우창에만 -스로틀링을 비활성화하고 싶다면 [조용한 오디오를 재생하는][play-silent-audio] 핵을 사용할 -수 있습니다. - -## --enable-logging - -Chromium의 로그를 콘솔에 출력합니다. - -이 스위치는 애플리케이션이 로드되기 전에 분석 되므로 `app.commandLine.appendSwitch` -메서드에선 사용할 수 없습니다. 하지만 `ELECTRON_ENABLE_LOGGING` 환경 변수를 설정하면 -본 스위치를 지정한 것과 같은 효과를 낼 수 있습니다. - -## --v=`log_level` - -기본 V-logging 최대 활성화 레벨을 지정합니다. 기본값은 0입니다. 기본적으로 양수를 -레벨로 사용합니다. - -이 스위치는 `--enable-logging` 스위치를 같이 지정해야 작동합니다. - -## --vmodule=`pattern` - -`--v` 옵션에 전달된 값을 덮어쓰고 모듈당 최대 V-logging 레벨을 지정합니다. -예를 들어 `my_module=2,foo*=3`는 `my_module.*`, `foo*.*`와 같은 파일 이름 패턴을 -가진 모든 소스 코드들의 로깅 레벨을 각각 2와 3으로 설정합니다. - -또한 슬래시(`/`) 또는 백슬래시(`\`)를 포함하는 패턴은 지정한 경로에 대해 패턴을 테스트 -합니다. 예를 들어 `*/foo/bar/*=2` 표현식은 `foo/bar` 디렉터리 안의 모든 소스 코드의 -로깅 레벨을 2로 지정합니다. - -이 스위치는 `--enable-logging` 스위치를 같이 지정해야 작동합니다. - -[app]: app.md -[append-switch]: app.md#appcommandlineappendswitchswitch-value -[ready]: app.md#event-ready -[play-silent-audio]: https://github.com/atom/atom/pull/9485/files diff --git a/docs-translations/ko-KR/api/clipboard.md b/docs-translations/ko-KR/api/clipboard.md deleted file mode 100644 index 6536bf922bca0..0000000000000 --- a/docs-translations/ko-KR/api/clipboard.md +++ /dev/null @@ -1,134 +0,0 @@ -# clipboard - -> 시스템 클립보드에 복사와 붙여넣기를 수행합니다. - -다음 예시는 클립보드에 문자열을 쓰는 방법을 보여줍니다: - -```javascript -const {clipboard} = require('electron'); -clipboard.writeText('Example String'); -``` - -X Window 시스템에선 selection 클립보드도 존재합니다. 이를 사용하려면 인수 뒤에 -`selection` 문자열을 같이 지정해주어야 합니다: - -```javascript -clipboard.writeText('Example String', 'selection'); -console.log(clipboard.readText('selection')); -``` - -## Methods - -`clipboard` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -**참고:** Experimental 마크가 붙은 API는 실험적인 기능이며 차후 최신 버전에서 제거될 -수 있습니다. - -### `clipboard.readText([type])` - -* `type` String (optional) - -클립보드 콘텐츠를 `plain text`로 반환합니다. - -### `clipboard.writeText(text[, type])` - -* `text` String -* `type` String (optional) - -클립보드에 `plain text`로 문자열을 씁니다. - -### `clipboard.readHTML([type])` - -* `type` String (optional) - -클립보드 콘텐츠를 `markup`으로 반환합니다. - -### `clipboard.writeHTML(markup[, type])` - -* `markup` String -* `type` String (optional) - -클립보드에 `markup`으로 씁니다. - -### `clipboard.readImage([type])` - -* `type` String (optional) - -클립보드로부터 [NativeImage](native-image.md)로 이미지를 읽어들입니다. - -### `clipboard.writeImage(image[, type])` - -* `image` [NativeImage](native-image.md) -* `type` String (optional) - -클립보드에 `image`를 씁니다. - -### `clipboard.readRTF([type])` - -* `type` String (optional) - -클립보드로부터 RTF 형식으로 콘텐츠를 읽어옵니다. - -### `clipboard.writeRTF(text[, type])` - -* `text` String -* `type` String (optional) - -클립보드에 `text`를 RTF 형식으로 씁니다. - -### `clipboard.readBookmark()` _macOS_ _Windows_ - -클립보드로부터 북마크 형식으로 표현된 `title`와 `url` 키를 담은 객체를 반환합니다. -`title`과 `url` 값들은 북마크를 사용할 수 없을 때 빈 문자열을 포함합니다. - -### `clipboard.writeBookmark(title, url[, type])` _macOS_ _Windows_ - -* `title` String -* `url` String -* `type` String (optional) - -`title`과 `url`을 클립보드에 북마크 형식으로 씁니다. - -### `clipboard.clear([type])` - -* `type` String (optional) - -클립보드에 저장된 모든 콘텐츠를 삭제합니다. - -### clipboard.availableFormats([type]) - -클립보드의 `type`에 해당하는 지원하는 `format`을 문자열로 반환합니다. - -### `clipboard.has(data[, type])` - -* `data` String -* `type` String (optional) - -클립보드가 지정한 `data`의 형식을 지원하는지 확인합니다. - -```javascript -console.log(clipboard.has('

selection

')); -``` - -### `clipboard.read(data[, type])` _Experimental_ - -* `data` String -* `type` String (optional) - -클립보드로부터 `data`를 읽어들입니다. - -### `clipboard.write(data[, type])` _Experimental_ - -* `data` Object - * `text` String - * `html` String - * `image` [NativeImage](native-image.md) - * `rtf` String - * `bookmark` String - `text`에 있는 URL의 텍스트. -* `type` String (optional) - -```javascript -clipboard.write({text: 'test', html: 'test'}); -``` - -`data`를 클립보드에 씁니다. diff --git a/docs-translations/ko-KR/api/content-tracing.md b/docs-translations/ko-KR/api/content-tracing.md deleted file mode 100644 index 57ef5196ddbe7..0000000000000 --- a/docs-translations/ko-KR/api/content-tracing.md +++ /dev/null @@ -1,160 +0,0 @@ -# contentTracing - -> 성능상의 병목 현상과 느린 작업을 찾기 위해 Chromium의 콘텐츠 모듈에서 추적 데이터를 -수집합니다. - -이 모듈은 웹 인터페이스를 포함하고 있지 않으며 Chrome 브라우저에서 -`chrome://tracing/` 페이지를 열고 생성된 파일을 로드하면 결과를 볼 수 있습니다. - -```javascript -const {contentTracing} = require('electron'); - -const options = { - categoryFilter: '*', - traceOptions: 'record-until-full,enable-sampling' -}; - -contentTracing.startRecording(options, () => { - console.log('Tracing started'); - - setTimeout(() => { - contentTracing.stopRecording('', (path) => { - console.log('Tracing data recorded to ' + path); - }); - }, 5000); -}); -``` - -## Methods - -`content-tracing` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `contentTracing.getCategories(callback)` - -* `callback` Function - -카테고리 그룹 세트를 가져옵니다. 카테고리 그룹은 도달된 코드 경로를 변경할 수 있습니다. - -모든 child 프로세스가 `getCategories` 요청을 승인하면 `callback`이 한 번 호출되며 -인수에 카테고리 그룹의 배열이 전달됩니다. - -### `contentTracing.startRecording(options, callback)` - -* `options` Object - * `categoryFilter` String - * `traceOptions` String -* `callback` Function - -모든 프로세스에서 레코딩을 시작합니다. - -레코딩은 지역적으로 즉시 실행됩니다. 그리고 비동기로 child 프로세스는 곧 -EnableRecording 요청을 받게 됩니다. 모든 child 프로세스가 `startRecording` 요청을 -승인하면 `callback`이 한 번 호출됩니다. - -`categoryFilter`는 어떤 카테고리 그룹이 트레이싱 되어야 하는지 필터링할 수 있습니다. -필터는 `-` 접두사를 통해 특정 카테고리 그룹을 제외할 수 있습니다. 카테고리 패턴은 같은 -리스트 내에서 포함과 제외를 함께 사용할 수 없습니다. - -예시: - -* `test_MyTest*`, -* `test_MyTest*,test_OtherStuff`, -* `"-excluded_category1,-excluded_category2` - -`traceOptions`은 어떤 종류의 트레이싱을 사용할 수 있는지 지정하고 콤마로 리스트를 -구분합니다. - -사용할 수 있는 옵션은 다음과 같습니다: - -* `record-until-full` -* `record-continuously` -* `trace-to-console` -* `enable-sampling` -* `enable-systrace` - -첫번째부터 3번째까지의 옵션은 추적 레코딩 모드입니다. 이에 따라 상호 배타적입니다. -만약 레코딩 모드가 한 개 이상 지정되면 마지막 지정한 모드만 사용됩니다. 어떤 모드도 -설정되지 않았다면 `record-until-full` 모드가 기본으로 사용됩니다. - -추적 옵션은 `traceOptions`이 파싱되어 적용되기 전까지 다음과 같은 기본값이 사용됩니다. - -`record-until-full`이 기본 모드, `enable-sampling`과 `enable-systrace`옵션은 -포함되지 않음 - -## `contentTracing.stopRecording(resultFilePath, callback)` - -* `resultFilePath` String -* `callback` Function - -모든 프로세스에서 레코딩을 중지합니다. - -Child 프로세스는 일반적으로 추적 데이터와 희귀한 플러시 그리고 추적 데이터를 메인 -프로세스로 보내는 작업에 대해 캐싱 합니다. 이러한 일을 하는 이유는 IPC를 통해 추적 -데이터를 보내는 작업은 매우 비싼 연산을 동반하기 때문입니다. 우리는 추적에 의한 런타임 -오버헤드를 피하고자 합니다. 그래서 추적이 끝나면 모든 child 프로세스에 보류된 추적 -데이터를 플러시 할 것인지 물어봅니다. - -모든 child 프로세스가 `stopRecording` 요청을 승인하면 `callback`에 추적 데이터 -파일을 포함하여 한 번 호출됩니다. - -추적 데이터는 `resultFilePath` 해당 경로가 비어있는 경우에 한 해 해당 경로에 -작성되거나 임시 파일에 작성됩니다. 실제 파일 경로는 null이 아닌 이상 `callback`을 -통해 전달됩니다. - -### `contentTracing.startMonitoring(options, callback)` - -* `options` Object - * `categoryFilter` String - * `traceOptions` String -* `callback` Function - -모든 프로세스에서 모니터링을 시작합니다. - -모니터링은 지역적으로 즉시 시작됩니다. 그리고 이내 자식 프로세스들이 -`startMonitoring` 비동기 요청을 받습니다. - -모든 자식 프로세스가 `startMonitoring` 요청을 승인하면 `callback`이 한 번 호출됩니다. - -### `contentTracing.stopMonitoring(callback)` - -* `callback` Function - -모든 프로세스에서 모니터링을 중단합니다. - -모든 자식 프로세스가 `stopMonitoring` 요청을 승인하면 `callback`이 한 번 호출됩니다. - -### `contentTracing.captureMonitoringSnapshot(resultFilePath, callback)` - -* `resultFilePath` String -* `callback` Function - -현재 모니터링 추적 데이터를 가져옵니다. - -자식 프로세스들은 일반적으로 추적 데이터를 캐싱하며 드물게 플러시 하거나 메인 -프로세스로 추적 데이터를 보냅니다. 왜냐하면 IPC를 통해 추적 데이터를 보내는데에는 -많은 자원을 소비하기 때문입니다. 그리고 우리는 추적시 발생하는 불필요한 런타임 -오버헤드를 피하고자 합니다. 그래서 추적이 끝나면 반드시 비동기로 자식 프로세스들의 -보류된 추적 데이터를 플러시 할 것인지 물어봅니다. - -모든 자식 프로세스가 `captureMonitoringSnapshot` 요청을 승인하면 추적 데이터 파일을 -포함하는 `callback`이 한 번 호출됩니다. - -### `contentTracing.getTraceBufferUsage(callback)` - -* `callback` Function - -추적 버퍼 % 전체 상태의 프로세스간 최대치를 가져옵니다. TraceBufferUsage 값이 -결정되면 `callback`이 한 번 호출됩니다. - -### `contentTracing.setWatchEvent(categoryName, eventName, callback)` - -* `categoryName` String -* `eventName` String -* `callback` Function - -`callback`은 지정된 이벤트가 어떤 작업을 발생시킬 때마다 호출됩니다. - -### `contentTracing.cancelWatchEvent()` - -Watch 이벤트를 중단합니다. 만약 추적이 활성화되어 있다면 이 메서드는 watch 이벤트 -콜백과 race가 일어날 것입니다. diff --git a/docs-translations/ko-KR/api/crash-reporter.md b/docs-translations/ko-KR/api/crash-reporter.md deleted file mode 100644 index 4f9058aa217da..0000000000000 --- a/docs-translations/ko-KR/api/crash-reporter.md +++ /dev/null @@ -1,69 +0,0 @@ -# crashReporter - -> 원격 서버에 크래시 정보를 보고합니다. - -다음 예시는 윈격 서버에 애플리케이션 크래시 정보를 자동으로 보고하는 예시입니다: - -```javascript -const {crashReporter} = require('electron'); - -crashReporter.start({ - productName: 'YourName', - companyName: 'YourCompany', - submitURL: 'https://your-domain.com/url-to-submit', - autoSubmit: true -}); -``` - -서버가 크래시 리포트를 받을 수 있도록 설정하기 위해 다음과 같은 프로젝트를 사용할 수도 -있습니다: - -* [socorro](https://github.com/mozilla/socorro) -* [mini-breakpad-server](https://github.com/electron/mini-breakpad-server) - -## Methods - -`crash-reporter` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `crashReporter.start(options)` - -* `options` Object - * `companyName` String - * `submitURL` String - 크래시 리포트는 POST 방식으로 이 URL로 전송됩니다. - * `productName` String (optional) - 기본값은 `Electron` 입니다. - * `autoSubmit` Boolean - 유저의 승인 없이 자동으로 오류를 보고합니다. 기본값은 - `true` 입니다. - * `ignoreSystemCrashHandler` Boolean - 기본값은 `false` 입니다. - * `extra` Object - 크래시 리포트 시 같이 보낼 추가 정보를 지정하는 객체입니다. - 문자열로 된 속성만 정상적으로 보내집니다. 중첩된 객체는 지원되지 않습니다. - -다른 crashReporter API를 사용하기 전에 이 메서드를 먼저 호출해야 합니다. - -**참고:** macOS에선 Windows와 Linux의 `breakpad`와 달리 새로운 `crashpad` -클라이언트를 사용합니다. 오류 수집 기능을 활성화 시키려면 오류를 수집하고 싶은 메인 -프로세스나 렌더러 프로세스에서 `crashReporter.start` 메서드를 호출하여 `crashpad`를 -초기화해야 합니다. - -### `crashReporter.getLastCrashReport()` - -마지막 크래시 리포트의 날짜와 ID를 반환합니다. -이전 크래시 리포트가 없거나 Crash Reporter가 시작되지 않았을 경우 `null`이 반환됩니다. - -### `crashReporter.getUploadedReports()` - -모든 업로드된 크래시 리포트를 반환합니다. 각 보고는 날짜와 업로드 ID를 포함하고 있습니다. - -## crash-reporter 업로드 형식 - -Crash Reporter는 다음과 같은 데이터를 `submitURL`에 `multipart/form-data` `POST` 방식으로 전송합니다: - -* `ver` String - Electron의 버전. -* `platform` String - e.g. 'win32'. -* `process_type` String - e.g. 'renderer'. -* `guid` String - e.g. '5e1286fc-da97-479e-918b-6bfb0c3d1c72'. -* `_version` String - `package.json`내의 `version` 필드. -* `_productName` String - Crash Reporter의 `options` 객체에서 정의한 제품명. -* `prod` String - 기본 제품의 이름. 이 경우 Electron으로 표시됩니다. -* `_companyName` String - Crash Reporter의 `options` 객체에서 정의한 회사명. -* `upload_file_minidump` File - `minidump` 형식의 크래시 리포트 파일. -* Crash Reporter의 `options` 객체에서 정의한 `extra` 객체의 속성들. diff --git a/docs-translations/ko-KR/api/desktop-capturer.md b/docs-translations/ko-KR/api/desktop-capturer.md deleted file mode 100644 index 7093ad3b6a5a4..0000000000000 --- a/docs-translations/ko-KR/api/desktop-capturer.md +++ /dev/null @@ -1,78 +0,0 @@ -# desktopCapturer - -> 마이크, 카메라 또는 화면에서 오디오, 비디오 그리고 이미지를 캡쳐하기 위한 -`getUserMedia` 소스를 나열합니다. - -```javascript -// 렌더러 프로세스 내부 -const {desktopCapturer} = require('electron'); - -desktopCapturer.getSources({types: ['window', 'screen']}, (error, sources) => { - if (error) throw error; - for (let i = 0; i < sources.length; ++i) { - if (sources[i].name === 'Electron') { - navigator.webkitGetUserMedia({ - audio: false, - video: { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: sources[i].id, - minWidth: 1280, - maxWidth: 1280, - minHeight: 720, - maxHeight: 720 - } - } - }, gotStream, getUserMediaError); - return; - } - } -}); - -function gotStream(stream) { - document.querySelector('video').src = URL.createObjectURL(stream); -} - -function getUserMediaError(e) { - console.log('getUserMediaError'); -} -``` - -`navigator.webkitGetUserMedia` 호출에 대해 제약된 객체를 생성할 때 -`desktopCapturer`에서 소스를 사용한다면 `chromeMediaSource`은 반드시 -`"desktop"`으로 지정되어야 하며, `audio` 도 반드시 `false`로 지정되어야 합니다. - -만약 전체 데스크탑에서 오디오와 비디오 모두 캡쳐를 하고 싶을 땐 `chromeMediaSource`를 -`"screen"` 그리고 `audio`를 `true`로 지정할 수 있습니다. 이 방법을 사용하면 -`chromeMediaSourceId`를 지정할 수 없습니다. - - -## Methods - -`desktopCapturer` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `desktopCapturer.getSources(options, callback)` - -* `options` Object - * `types` Array - 캡쳐될 데스크탑 소스의 타입에 대한 리스트를 배열로 지정합니다. - 사용 가능한 타입은 `screen`과 `window`입니다. - * `thumbnailSize` Object (optional) - 섬네일 크기를 조정할 때 최대한 맞춰질 크기, - 기본값은 `{width: 150, height: 150}`입니다. -* `callback` Function - -모든 데스크탑 소스를 요청합니다. 요청의 처리가 완료되면 `callback`은 -`callback(error, sources)` 형식으로 호출됩니다. - -`sources`는 `Source` 객체의 배열입니다. 각 `Source`는 캡쳐된 화면과 독립적인 -윈도우를 표현합니다. 그리고 다음과 같은 속성을 가지고 있습니다: - -* `id` String - `navigator.webkitGetUserMedia` API에서 사용할 수 있는 캡쳐된 윈도우 - 또는 화면의 id입니다. 포맷은 `window:XX` 또는 `screen:XX`로 표현되며 `XX` 는 - 무작위로 생성된 숫자입니다. -* `name` String - 캡쳐된 화면과 윈도우에 대해 묘사된 이름입니다. 만약 소스가 - 화면이라면, `Entire Screen` 또는 `Screen `가 될 것이고 소스가 윈도우라면, - 해당 윈도우의 제목이 반환됩니다. -* `thumbnail` [NativeImage](native-image.md) - 섬네일 네이티브 이미지. - -**참고:** `source.thumbnail`의 크기는 언제나 `options`의 `thumnbailSize`와 같다고 -보장할 수 없습니다. 섬네일의 크기는 화면과 윈도우의 크기에 의존하여 조정됩니다. diff --git a/docs-translations/ko-KR/api/dialog.md b/docs-translations/ko-KR/api/dialog.md deleted file mode 100644 index 3e0624ca46d73..0000000000000 --- a/docs-translations/ko-KR/api/dialog.md +++ /dev/null @@ -1,144 +0,0 @@ -# dialog - -> 파일을 열거나 저장하고, 알림을 표시하기 위한 네이티브 시스템 대화 상자를 표시합니다. - -다음 예시는 파일과 디렉터리를 다중으로 선택하는 대화 상자를 표시하는 예시입니다: - -```javascript -let win = ...; // 대화 상자를 사용할 BrowserWindow 객체 -const {dialog} = require('electron'); -console.log(dialog.showOpenDialog({properties: ['openFile', 'openDirectory', 'multiSelections']})); -``` - -대화 상자는 Electron의 메인 스레드에서 열립니다. 만약 렌더러 프로세스에서 대화 상자 -객체를 사용하고 싶다면, `remote`를 통해 접근하는 방법을 고려해야 합니다: - -```javascript -const {dialog} = require('electron').remote; -``` - -## Methods - -`dialog` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `dialog.showOpenDialog([browserWindow, ]options[, callback])` - -* `browserWindow` BrowserWindow (optional) -* `options` Object - * `title` String - * `defaultPath` String - * `buttonLabel` String - 확인 버튼을 위한 커스텀 라벨이며, 빈칸으로 둘 경우 기본 - 라벨이 사용됩니다. - * `filters` Array - * `properties` Array - 대화 상자가 사용할 기능(모드)이 담긴 배열입니다. - 다음을 포함할 수 있습니다: `openFile`, `openDirectory`, `multiSelections`, - `createDirectory`, `showHiddenFiles`. -* `callback` Function (optional) - -사용할 대화 상자의 기능이 담긴 배열입니다. 다음을 포함할 수 있습니다: `openFile`, -`openDirectory`, `multiSelections`, `createDirectory` - -작업에 성공하면 콜백으로 유저가 선택한 파일의 경로를 포함한 배열을 반환합니다. 그 외의 -경우엔 `undefined`를 반환합니다. - -`filters`를 지정하면 유저가 선택 가능한 파일 형식을 지정할 수 있습니다. 유저가 선택할 -수 있는 타입에 제한을 두려면 다음과 같이 할 수 있습니다: - -```javascript -{ - filters: [ - {name: 'Images', extensions: ['jpg', 'png', 'gif']}, - {name: 'Movies', extensions: ['mkv', 'avi', 'mp4']}, - {name: 'Custom File Type', extensions: ['as']}, - {name: 'All Files', extensions: ['*']} - ] -} -``` - -`extensions` 배열은 반드시 와일드카드와 마침표를 제외한 파일 확장자를 포함시켜야 -합니다. (예를 들어 `'png'`는 가능하지만 `'.png'`와 `'*.png'`는 안됩니다) 모든 파일을 -보여주려면 `'*'`와 같은 와일드카드를 사용하면 됩니다. (다른 와일드카드는 지원하지 - 않습니다) - -`callback`이 전달되면 메서드가 비동기로 작동되며 결과는 `callback(filenames)`을 -통해 전달됩니다. - -**참고:** Windows와 Linux에선 파일 선택 모드, 디렉터리 선택 모드를 동시에 사용할 수 -없습니다. 이러한 이유로 `properties`를 `['openFile', 'openDirectory']`로 설정하면 -디렉터리 선택 대화 상자가 표시됩니다. - -### `dialog.showSaveDialog([browserWindow, ]options[, callback])` - -* `browserWindow` BrowserWindow (optional) -* `options` Object - * `title` String - * `defaultPath` String - * `buttonLabel` String - 확인 버튼을 위한 커스텀 라벨이며, 빈칸으로 둘 경우 기본 - 라벨이 사용됩니다. - * `filters` Array -* `callback` Function (optional) - -작업에 성공하면 콜백으로 유저가 선택한 파일의 경로를 포함한 배열을 반환합니다. 그 외엔 -`undefined`를 반환합니다. - -`filters`를 지정하면 유저가 저장 가능한 파일 형식을 지정할 수 있습니다. 사용 방법은 -`dialog.showOpenDialog`의 `filters` 속성과 같습니다. - -`callback`이 전달되면 메서드가 비동기로 작동되며 결과는 `callback(filename)`을 통해 -전달됩니다. - -### `dialog.showMessageBox([browserWindow, ]options[, callback])` - -* `browserWindow` BrowserWindow (optional) -* `options` Object - * `type` String - `"none"`, `"info"`, `"error"`, `"question"`, `"warning"` 중 - 하나를 사용할 수 있습니다. Windows에선 따로 `icon`을 설정하지 않은 이상 - "question"과 "info"는 같은 아이콘으로 표시됩니다. - * `buttons` Array - 버튼들의 라벨을 포함한 배열입니다. Windows에서 빈 배열로 둘 - 경우, "OK" 버튼 하나가 포함됩니다. - * `defaultId` Integer - 메시지 박스가 열렸을 때 기본적으로 선택될 버튼 배열의 - 버튼 인덱스입니다. - * `title` String - 대화 상자의 제목입니다. 몇몇 플랫폼에선 보이지 않을 수 있습니다. - * `message` String - 대화 상자의 본문 내용입니다. - * `detail` String - 메시지의 추가 정보입니다. - * `icon` [NativeImage](native-image.md) - * `cancelId` Integer - 유저가 대화 상자의 버튼을 클릭하지 않고 대화 상자를 취소했을 - 때 반환되는 버튼의 인덱스입니다. 기본적으로 버튼 리스트가 "cancel" 또는 "no" - 라벨을 가지고 있을 때 해당 버튼의 인덱스를 반환합니다. 따로 두 라벨이 지정되지 - 않은 경우 0을 반환합니다. macOS와 Windows에선 `cancelId` 지정 여부에 상관없이 - "Cancel" 버튼이 언제나 `cancelId`로 지정됩니다. - * `noLink` Boolean - Windows에서 Electron은 ("Cancel"이나 "Yes"와 같은) 흔히 - 사용되는 버튼을 찾으려고 시도하고 대화 상자 내에서 해당 버튼을 커맨드 링크처럼 - 만듭니다. 이 기능으로 앱을 좀 더 현대적인 Windows 앱처럼 만들 수 있습니다. 이 - 기능을 원하지 않으면 `noLink`를 true로 지정하면 됩니다. -* `callback` Function (optional) - -대화 상자를 표시합니다. `browserWindow`를 지정하면 대화 상자가 완전히 닫힐 때까지 -지정한 창을 사용할 수 없습니다. 완료 시 유저가 선택한 버튼의 인덱스를 반환합니다. - -**역자주:** 부정을 표현하는 "아니오", "취소"와 같은 한글 단어는 지원되지 않습니다. 만약 -macOS 또는 Windows에서 "확인", "취소"와 같은 순서로 버튼을 지정하게 될 때 Alt + f4로 -해당 대화 상자를 끄게 되면 "확인"을 누른 것으로 판단되어 버립니다. 이를 해결하려면 -"Cancel"을 대신 사용하거나 BrowserWindow API를 사용하여 대화 상자를 직접 구현해야 -합니다. - -`callback`이 전달되면 메서드가 비동기로 작동되며 결과는 `callback(response)`을 통해 -전달됩니다. - -### `dialog.showErrorBox(title, content)` - -에러 메시지를 보여주는 대화 상자를 표시합니다. - -이 함수는 `app` 모듈의 `ready` 이벤트가 발생하기 전까지 사용할 수 있습니다. 이 메서드는 -보통 애플리케이션이 시작되기 전에 특정한 에러를 표시하기 위해 사용됩니다. 만약 -Linux에서 `ready` 이벤트가 발생하기 전에 이 API를 호출할 경우, 메시지는 stderr를 -통해서 표시되며 GUI 대화 상자는 표시되지 않습니다. - -## Sheets - -macOS에선, `browserWindow` 인수에 `BrowserWindow` 객체 참조를 전달하면 대화 -상자가 해당 윈도우에 시트처럼 표시되도록 표현할 수 있습니다. 윈도우의 객체 참조가 -제공되지 않으면 모달 형태로 표시됩니다. - -`BrowserWindow.getCurrentWindow().setSheetOffset(offset)`을 통해 윈도우에 부착될 -시트의 위치를 조정할 수 있습니다. diff --git a/docs-translations/ko-KR/api/download-item.md b/docs-translations/ko-KR/api/download-item.md deleted file mode 100644 index 781d686360434..0000000000000 --- a/docs-translations/ko-KR/api/download-item.md +++ /dev/null @@ -1,143 +0,0 @@ -# DownloadItem - -> 원격 소스로부터의 파일 다운로드를 제어합니다. - -`DownloadItem`은 `EventEmitter`를 상속받았으며 Electron의 다운로드 아이템을 -표현합니다. 이 클래스 객체는 `Session` 클래스의 `will-download` 이벤트에 사용되며 -사용자가 다운로드 아이템을 다룰 수 있도록 도와줍니다. - -```javascript -// 메인 프로세스 -win.webContents.session.on('will-download', (event, item, webContents) => { - // Set the save path, making Electron not to prompt a save dialog. - item.setSavePath('/tmp/save.pdf') - - item.on('updated', (event, state) => { - if (state === 'interrupted') { - console.log('Download is interrupted but can be resumed') - } else if (state === 'progressing') { - if (item.isPaused()) { - console.log('Download is paused') - } else { - console.log(`Received bytes: ${item.getReceivedBytes()}`) - } - } - }) - item.once('done', (event, state) => { - if (state === 'completed') { - console.log('Download successfully') - } else { - console.log(`Download failed: ${state}`) - } - }) -}) -``` - -## Events - -### Event: 'updated' - -Returns: - -* `event` Event -* `state` String - -다운로드가 업데이트되었으며 아직 끝나지 않았을 때 발생하는 이벤트입니다. - -`state`는 다음 중 하나가 될 수 있습니다: - -* `progressing` - 다운로드가 진행중입니다. -* `interrupted` - 다운로드가 중지되었으며 다시 재개할 수 있습니다. - -### Event: 'done' - -Returns: - -* `event` Event -* `state` String - -다운로드가 종료될 때 발생하는 이벤트입니다. 이 이벤트는 다운로드 중 문제가 발생하여 -중단되거나, 모두 성공적으로 완료된 경우, `downloadItem.cancel()` 같은 메서드를 통해 -취소하는 경우의 종료 작업이 모두 포함됩니다. - -`state`는 다음 중 하나가 될 수 있습니다: - -* `completed` - 다운로드가 성공적으로 완료되었습니다. -* `cancelled` - 다운로드가 취소되었습니다. -* `interrupted` - 다운로드가 중지되었으며 다시 재개할 수 있습니다. - -## Methods - -`downloadItem` 객체는 다음과 같은 메서드를 가지고 있습니다: - -### `downloadItem.setSavePath(path)` - -* `path` String - 다운로드 아이템을 저장할 파일 경로를 지정합니다. - -이 API는 세션의 `will-download` 콜백 함수에서만 사용할 수 있습니다. 사용자가 API를 -통해 아무 경로도 설정하지 않을 경우 Electron은 기본 루틴 파일 저장을 실행합니다. -(파일 대화 상자를 엽니다) - -### `downloadItem.pause()` - -다운로드를 일시 중지합니다. - -### `downloadItem.isPaused()` - -다운로드가 일시 중지되었는지 여부를 반환합니다. - -### `downloadItem.resume()` - -중디된 다운로드를 재개합니다. - -### `downloadItem.canResume()` - -다운로드를 재개할 수 있는지 여부를 반환합니다. - -### `downloadItem.cancel()` - -다운로드를 취소합니다. - -### `downloadItem.getURL()` - -다운로드 아이템의 URL을 표현하는 문자열을 반환합니다. - -### `downloadItem.getMimeType()` - -다우로드 아이템의 MIME 타입을 표현하는 문자열을 반환합니다. - -### `downloadItem.hasUserGesture()` - -현재 다운로드가 유저 제스쳐(작업)로인한 다운로드인지 여부를 반환합니다. - -### `downloadItem.getFilename()` - -다운로드 아이템의 파일 이름을 표현하는 문자열을 반환합니다. - -**참고:** 실제 파일 이름과 로컬 디스크에 저장되는 파일의 이름은 서로 다를 수 있습니다. -예를 들어 만약 사용자가 파일을 저장할 때 파일 이름을 바꿨다면 실제 파일 이름과 저장 -파일 이름은 서로 달라지게 됩니다. - -### `downloadItem.getTotalBytes()` - -현재 아이템의 전체 다운로드 크기를 정수로 반환합니다. 크기가 unknown이면 0을 -반환합니다. - -### `downloadItem.getReceivedBytes()` - -현재 아이템의 다운로드 완료된 바이트 값을 정수로 반환합니다. - -### `downloadItem.getContentDisposition()` - -응답 헤더에서 Content-Disposition 필드를 문자열로 반환합니다. - -### `downloadItem.getState()` - -현재 상태를 `String` 타입으로 가져옵니다. - -값은 다음이 될 수 있습니다: - -* `progressing` - 다운로드가 진행중입니다. -* `completed` - 다운로드가 성공적으로 완료되었습니다. -* `cancelled` - 다운로드가 취소되었습니다. -* `interrupted` - 다운로드가 중지되었습니다. diff --git a/docs-translations/ko-KR/api/environment-variables.md b/docs-translations/ko-KR/api/environment-variables.md deleted file mode 100644 index d497edc4c8b1f..0000000000000 --- a/docs-translations/ko-KR/api/environment-variables.md +++ /dev/null @@ -1,53 +0,0 @@ -# 환경 변수 - -> 애플리케이션의 구성과 동작을 코드 변경 없이 제어합니다. - -특정 Electron 동작은 명령줄 플래그와 애플리케이션의 코드보다 먼저 초기화되어야 하므로 -환경 변수에 의해 작동합니다. - -POSIX 쉘의 예시입니다: - -```bash -$ export ELECTRON_ENABLE_LOGGING=true -$ electron -``` - -Windows 콘솔의 예시입니다: - -```powershell -> set ELECTRON_ENABLE_LOGGING=true -> electron -``` - -### `ELECTRON_RUN_AS_NODE` - -프로세스를 일반 Node.js 프로세스처럼 시작합니다. (electron 모듈 제외) - -### `ELECTRON_ENABLE_LOGGING` - -Chrome의 내부 로그를 콘솔에 출력합니다. - -### `ELECTRON_LOG_ASAR_READS` - -Electron이 ASAR 파일을 읽을 때, 읽기 오프셋의 로그를 남기고 시스템 `tmpdir`에 파일로 -저장합니다. 결과 파일은 ASAR 모듈의 파일 순서를 최적화 하는데 사용할 수 있습니다. - -### `ELECTRON_ENABLE_STACK_DUMPING` - -Electron이 크래시되면, 콘솔에 stack trace를 출력합니다. - -이 환경 변수는 `crashReporter`가 시작되지 않았을 경우 작동하지 않습니다. - -### `ELECTRON_DEFAULT_ERROR_MODE` _Windows_ - -Electron이 크래시되면 스택 출력 정보를 콘솔에 출력합니다. - -이 환경 변수는 `crashReporter`가 시작되지 않았을 경우 작동하지 않습니다. - -### `ELECTRON_NO_ATTACH_CONSOLE` _Windows_ - -현재 콘솔 세션에 소속시키지 않습니다. - -### `ELECTRON_FORCE_WINDOW_MENU_BAR` _Linux_ - -Linux의 전역 메뉴바를 사용하지 않습니다. diff --git a/docs-translations/ko-KR/api/file-object.md b/docs-translations/ko-KR/api/file-object.md deleted file mode 100644 index 898f7f75b82d9..0000000000000 --- a/docs-translations/ko-KR/api/file-object.md +++ /dev/null @@ -1,31 +0,0 @@ -# `File` 객체 - -> HTML5 `File` API를 기본적인 파일 시스템의 파일처럼 사용합니다. - -DOM의 File 인터페이스는 네이티브 파일을 추상화 합니다. 사용자가 직접 HTML5 File -API를 사용하여 작업할 때 선택된 파일의 경로를 알 수 있도록, Electron은 파일의 실제 -경로를 담은 `path` 속성을 File 인터페이스에 추가했습니다. - -다음 예시는 앱으로 드래그 앤 드롭한 파일의 실제 경로를 가져옵니다: - -```html -
- Drag your file here -
- - -``` diff --git a/docs-translations/ko-KR/api/frameless-window.md b/docs-translations/ko-KR/api/frameless-window.md deleted file mode 100644 index a9e7737c61603..0000000000000 --- a/docs-translations/ko-KR/api/frameless-window.md +++ /dev/null @@ -1,115 +0,0 @@ -# Frameless 윈도우 - -> 툴바, 테두리, 시각적인 "chrome" 없이 윈도우를 엽니다. - -Frameless 윈도우는 [창 테두리](https://developer.mozilla.org/ko/docs/Glossary/Chrome)가 -없는 윈도우를 말합니다. 이 기능은 윈도우의 일부분인 툴바와 같이 웹 페이지의 일부분이 -아닌 부분을 보이지 않도록 합니다. [`BrowserWindow`](browser-window.md) 클래스의 -옵션에서 설정할 수 있습니다. - -## Frameless 윈도우 만들기 - -Frameless 윈도우를 만드려면 [BrowserWindow](browser-window.md) 객체의 -`options` 객체에서 `frame` 옵션을 `false`로 지정하면 됩니다: - -```javascript -const {BrowserWindow} = require('electron') -let win = new BrowserWindow({width: 800, height: 600, frame: false}) -``` - -### 최신 macOS에서 사용할 수 있는 대안 - -macOS 10.10 Yosemite 이후의 최신 버전부터는 테두리가 없는 창을 만들 때 새로운 방법을 -사용할 수 있습니다. `frame` 옵션을 `false`로 지정하여 제목과 창 구성 요소를 모두 -비활성화하는 대신 새로운 `titleBarStyle` 옵션을 통해 제목만 숨기고 창 구성 요소 -("신호등 버튼")의 기능과 창 크기를 그대로 유지할 수 있습니다: - -```javascript -let win = new BrowserWindow({titleBarStyle: 'hidden'}) -``` - -## 투명한 창 만들기 - -Frameless 윈도우 창의 배경을 투명하게 만들고 싶다면 `transparent` 옵션을 `true`로 -바꿔주기만 하면됩니다: - -```javascript -let win = new BrowserWindow({transparent: true, frame: false}) -``` - -### API의 한계 - -* 투명한 영역을 통과하여 클릭할 수 없습니다. 우리는 이 문제를 해결하기 위해 API를 - 제공할 예정이며 자세한 내용은 - [이슈](https://github.com/electron/electron/issues/1335)를 참고하세요. -* 투명한 창은 크기를 조절할 수 없습니다. `resizable` 속성을 `true`로 할 경우 몇몇 - 플랫폼에선 크래시가 일어납니다. -* `blur` 필터는 웹 페이지에서만 적용됩니다. 윈도우 아래 콘텐츠에는 블러 효과를 적용할 - 방법이 없습니다. (예시: 유저의 시스템에 열린 다른 애플리케이션) -* Windows에선 DWM(데스크톱 창 관리자)가 비활성화되어 있을 경우 투명한 창이 작동하지 - 않습니다. -* Linux를 사용할 경우 [alpha channel doesn't work on some NVidia drivers](https://code.google.com/p/chromium/issues/detail?id=369209) - upstream 버그가 있는 관계로 투명한 창 기능을 사용하려면 CLI 옵션에 - `--enable-transparent-visuals --disable-gpu`을 추가해야 합니다. 이 옵션은 GPU의 - 사용을 중단하고 윈도우를 생성하는데 ARGB를 사용할 수 있도록 해줍니다. -* macOS(Mac)에선 네이티브 창에서 보여지는 그림자가 투명한 창에선 보이지 않습니다. - -## 클릭이 통과될 수 있는 윈도우 - -클릭이 통과될 수 있는 윈도우를 만드려면, i.e. 모든 마우스 이벤트를 무시하는 윈도우를 -만드려면, [win.setIgnoreMouseEvents(ignore)][ignore-mouse-events] API를 사용하여 -구현할 수 있습니다: - -```javascript -win.setIgnoreMouseEvents(true) -``` - -## 드래그 가능 위치 지정 - -기본적으로 Frameless 윈도우는 드래그 할 수 없습니다. 애플리케이션의 CSS에서 특정 -범위를 `-webkit-app-region: drag`로 지정하면 OS의 기본 타이틀 바 처럼 드래그 되도록 -할 수 있습니다. 그리고 `-webkit-app-region: no-drag`를 지정해서 드래그 불가능 영역을 -만들 수도 있습니다. 현재 사각형 형태의 범위만 지원합니다. - -창 전체를 드래그 가능하게 만드려면 `-webkit-app-region: drag`을 `body`의 스타일에 -지정하면 됩니다: - -```html - - -``` - -참고로 창 전체를 드래그 영역으로 지정할 경우 사용자가 버튼을 클릭할 수 없게 되므로 -버튼은 드래그 불가능 영역으로 지정해야 합니다: - -```css -button { - -webkit-app-region: no-drag; -} -``` - -따로 커스텀 타이틀 바를 만들어 사용할 때는 타이틀 바 내부의 모든 버튼을 드래그 불가 -영역으로 지정해야 합니다. - -## 텍스트 선택 - -Frameless 윈도우에서 텍스트가 선택되는 드래그 동작은 혼란을 야기할 수 있습니다. 예를 -들어 타이틀 바를 드래그 할 때 타이틀 바의 텍스트를 실수로 선택할 수 있습니다. 이를 -방지하기 위해 다음과 같이 드래그 영역의 텍스트 선택 기능을 비활성화해야 할 필요가 -있습니다: - -```css -.titlebar { - -webkit-user-select: none; - -webkit-app-region: drag; -} -``` - -## 컨텍스트 메뉴 - -몇몇 플랫폼에선 드래그 가능 영역이 non-client 프레임으로 처리됩니다. 이러한 플랫폼에선 -드래그 가능 영역에서 오른쪽 클릭 할 경우 시스템 메뉴가 팝업 됩니다. 이러한 이유로 -컨텍스트 메뉴 지정 시 모든 플랫폼에서 정상적으로 작동하게 하려면 커스텀 컨텍스트 메뉴를 -드래그 영역 내에 만들어선 안됩니다. - -[ignore-mouse-events]: browser-window.md#winsetignoremouseeventsignore diff --git a/docs-translations/ko-KR/api/global-shortcut.md b/docs-translations/ko-KR/api/global-shortcut.md deleted file mode 100644 index 0fe84efc03d0e..0000000000000 --- a/docs-translations/ko-KR/api/global-shortcut.md +++ /dev/null @@ -1,73 +0,0 @@ -# globalSortcut - -> 애플리케이션에 키보드 포커스가 없을 때도 키보드 이벤트를 받을 수 있도록 합니다. - -`globalShortcut` 모듈은 운영체제의 전역 키보드 단축키를 등록/해제 하는 방법을 -제공합니다. 이 모듈을 사용하여 사용자가 다양한 작업을 편하게 할 수 있도록 단축키를 -정의 할 수 있습니다. - -**참고:** 등록된 단축키는 애플리케이션이 백그라운드로 작동(창이 포커스 되지 않음) 할 -때도 계속해서 작동합니다. 이 모듈은 `app` 모듈의 `ready` 이벤트가 발생하기 전까지 -사용할 수 없습니다. - -```javascript -const {app, globalShortcut} = require('electron'); - -app.on('ready', () => { - // 'CommandOrControl+X' 단축키를 리스너에 등록합니다. - const ret = globalShortcut.register('CommandOrControl+X', () => { - console.log('CommandOrControl+X is pressed'); - }); - - if (!ret) { - console.log('registration failed'); - } - - // 단축키가 등록되었는지 확인합니다. - console.log(globalShortcut.isRegistered('CommandOrControl+X')); -}); - -app.on('will-quit', () => { - // 단축키의 등록을 해제합니다. - globalShortcut.unregister('CommandOrControl+X'); - - // 모든 단축키의 등록을 해제합니다. - globalShortcut.unregisterAll(); -}); -``` - -## Methods - -`globalShortcut` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `globalShortcut.register(accelerator, callback)` - -* `accelerator` [Accelerator](accelerator.md) -* `callback` Function - -`accelerator`의 전역 단축키를 등록합니다. 유저로부터 등록된 단축키가 눌렸을 경우 -`callback` 함수가 호출됩니다. - -accelerator가 이미 다른 애플리케이션에서 사용 중일 경우, 이 작업은 조용히 실패합니다. -이러한 동작은 애플리케이션이 전역 키보드 단축키를 가지고 충돌이 일어나지 않도록 하기 -위해 운영체제에 의해 예정된 동작입니다. - -### `globalShortcut.isRegistered(accelerator)` - -* `accelerator` [Accelerator](accelerator.md) - -지정된 `accelerator` 단축키가 등록되었는지 여부를 확인합니다. - -Accelerator가 이미 다른 애플리케이션에서 사용 중일 경우, 여전히 `false`를 반환합니다. -이러한 동작은 애플리케이션이 전역 키보드 단축키를 가지고 충돌이 일어나지 않도록 하기 -위해 운영체제에 의해 예정된 동작입니다. - -### `globalShortcut.unregister(accelerator)` - -* `accelerator` [Accelerator](accelerator.md) - -`accelerator`에 해당하는 전역 단축키를 등록 해제합니다. - -### `globalShortcut.unregisterAll()` - -모든 전역 단축키의 등록을 해제합니다. diff --git a/docs-translations/ko-KR/api/ipc-main.md b/docs-translations/ko-KR/api/ipc-main.md deleted file mode 100644 index f50949684c305..0000000000000 --- a/docs-translations/ko-KR/api/ipc-main.md +++ /dev/null @@ -1,97 +0,0 @@ -# ipcMain - -> 메인 프로세스에서 렌더러 프로세스로 비동기 통신을 합니다. - -`ipcMain` 모듈은 [EventEmitter](https://nodejs.org/api/events.html) 클래스의 -인스턴스입니다. 메인 프로세스에서 사용하면, 렌더러 프로세스(웹 페이지)에서 전달된 -동기, 비동기 메시지를 주고 받는 방법을 제공합니다. 렌더러 프로세스에서 메시지를 전달하면 -이 모듈을 통해 메시지를 받을 수 있습니다. - -## 메시지 전송 - -물론 메시지를 받는 것 말고도 메인 프로세스에서 렌더러 프로세스로 보내는 것도 가능합니다. -자세한 내용은 [webContents.send][web-contents-send]를 참고하세요. - -* 메시지를 전송할 때 이벤트 이름은 `channel`이 됩니다. -* 메시지에 동기로 응답할 땐 반드시 `event.returnValue`를 설정해야 합니다. -* 메시지를 비동기로 응답할 땐 `event.sender.send(...)` 메서드를 사용할 수 있습니다. - -다음 예시는 렌더러 프로세스와 메인 프로세스간에 메시지를 전달하고 받는 예시입니다: - -```javascript -// 메인 프로세스 -const {ipcMain} = require('electron'); -ipcMain.on('asynchronous-message', (event, arg) => { - console.log(arg); // "ping" 출력 - event.sender.send('asynchronous-reply', 'pong'); -}); - -ipcMain.on('synchronous-message', (event, arg) => { - console.log(arg); // "ping" 출력 - event.returnValue = 'pong'; -}); -``` - -```javascript -// 렌더러 프로세스 (웹 페이지) -const {ipcRenderer} = require('electron'); -console.log(ipc.sendSync('synchronous-message', 'ping')); // "pong" 출력 - -ipcRenderer.on('asynchronous-reply', (arg) => { - console.log(arg); // "pong" 출력 -}); -ipcRenderer.send('asynchronous-message', 'ping'); -``` - -## 메시지 리스닝 - -`ipcMain`은 다음과 같은 이벤트 리스닝 메서드를 가지고 있습니다: - -### `ipcMain.on(channel, listener)` - -* `channel` String -* `listener` Function - -`channel`에 대해 이벤트를 리스닝합니다. 새로운 메시지가 도착하면 `listener`가 -`listener(event, args...)` 형식으로 호출됩니다. - -### `ipcMain.once(channel, listener)` - -* `channel` String -* `listener` Function - -이벤트에 대해 한 번만 작동하는 `listener` 함수를 등록합니다. 이 `listener`는 등록된 -후 `channel`에 보내지는 메시지에 한해 호출됩니다. 호출된 이후엔 리스너가 삭제됩니다. - -### `ipcMain.removeListener(channel, listener)` - -* `channel` String -* `listener` Function - -메시지 수신을 완료한 후, 더 이상의 콜백이 필요하지 않을 때 또는 몇 가지 이유로 채널의 -메시지 전송을 멈출수 없을 때, 이 함수를 통해 지정한 채널에 대한 콜백을 삭제할 수 -있습니다. - -지정한 `channel`에 대한 리스너를 저장하는 배열에서 지정한 `listener`를 삭제합니다. - -### `ipcMain.removeAllListeners(channel)` - -* `channel` String (optional) - -이 ipc 채널에 등록된 모든 핸들러들을 삭제하거나 지정한 `channel`을 삭제합니다. - -## Event 객체 - -`callback`에서 전달된 `event` 객체는 다음과 같은 메서드와 속성을 가지고 있습니다: - -### `event.returnValue` - -이 메시지를 지정하면 동기 메시지를 전달합니다. - -### `event.sender` - -메시지를 보낸 `webContents` 객체를 반환합니다. `event.sender.send` 메서드를 통해 -비동기로 메시지를 전달할 수 있습니다. 자세한 내용은 -[webContents.send][web-contents-send]를 참고하세요. - -[web-contents-send]: web-contents.md#webcontentssendchannel-arg1-arg2- diff --git a/docs-translations/ko-KR/api/ipc-renderer.md b/docs-translations/ko-KR/api/ipc-renderer.md deleted file mode 100644 index a112e0ba44846..0000000000000 --- a/docs-translations/ko-KR/api/ipc-renderer.md +++ /dev/null @@ -1,85 +0,0 @@ -# ipcRenderer - -> 렌더러 프로세스에서 메인 프로세스로 비동기 통신을 합니다. - -`ipcRenderer` 모듈은 [EventEmitter](https://nodejs.org/api/events.html) 클래스의 -인스턴스입니다. 렌더러 프로세스에서 메인 프로세스로 동기/비동기 메시지를 주고 받는 -방법을 제공합니다. 또한 메인 프로세스로부터 받은 메시지에 응답할 수도 있습니다. - -[ipcMain](ipc-main.md)에서 코드 예시를 확인할 수 있습니다. - -## 메시지 리스닝 - -`ipcRenderer`는 다음과 같은 이벤트 리스닝 메서드를 가지고 있습니다: - -### `ipcRenderer.on(channel, listener)` - -* `channel` String -* `listener` Function - -`channel`에 대해 이벤트를 리스닝합니다. 새로운 메시지가 도착하면 `listener`가 -`listener(event, args...)` 형식으로 호출됩니다. - -### `ipcRenderer.once(channel, listener)` - -* `channel` String -* `listener` Function - -이벤트에 대해 한 번만 작동하는 `listener` 함수를 등록합니다. 이 `listener`는 등록된 -후 `channel`에 보내지는 메시지에 한해 호출됩니다. 호출된 이후엔 리스너가 삭제됩니다. - -### `ipcRenderer.removeListener(channel, listener)` - -* `channel` String -* `listener` Function - -메시지 수신을 완료한 후, 더 이상의 콜백이 필요하지 않을 때 또는 몇 가지 이유로 채널의 -메시지 전송을 멈출수 없을 때, 이 함수를 통해 지정한 채널에 대한 콜백을 삭제할 수 -있습니다. - -지정한 `channel`에 대한 리스너를 저장하는 배열에서 지정한 `listener`를 삭제합니다. - -### `ipcRenderer.removeAllListeners(channel)` - -* `channel` String (optional) - -이 ipc 채널에 등록된 모든 핸들러들을 삭제하거나 지정한 `channel`을 삭제합니다. - -## 메시지 보내기 - -`ipcRenderer`는 다음과 같은 메시지 전송 메서드를 가지고 있습니다: - -### `ipcRenderer.send(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (optional) - -`channel`을 통해 메인 프로세스에 비동기 메시지를 보냅니다. 그리고 필요에 따라 임의의 -인수를 사용할 수도 있습니다. 인수들은 내부적으로 JSON 포맷으로 직렬화 되며, 이후 함수와 -프로토타입 체인은 포함되지 않게 됩니다. - -메인 프로세스는 `ipcMain` 모듈의 `channel` 이벤트를 통해 -이벤트를 리스닝 할 수 있습니다. - -### `ipcRenderer.sendSync(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (optional) - -`channel`을 통해 메인 프로세스에 동기 메시지를 보냅니다. 그리고 필요에 따라 임의의 -인수를 사용할 수도 있습니다. 인수들은 내부적으로 JSON 포맷으로 직렬화 되며, 이후 함수와 -프로토타입 체인은 포함되지 않게 됩니다. - -메인 프로세스는 `ipcMain` 모듈을 통해 `channel` 이벤트를 리스닝 할 수 있고, -`event.returnValue`로 회신 할 수 있습니다. - -**참고:** 동기 메서드는 모든 렌더러 프로세스의 작업을 일시 중단시킵니다. 사용 목적이 -확실하지 않다면 사용하지 않는 것이 좋습니다. - -### `ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (optional) - -`ipcRenderer.send`와 비슷하지만 이벤트를 메인 프로세스 대신 호스트 페이지내의 -`` 요소로 보냅니다. diff --git a/docs-translations/ko-KR/api/locales.md b/docs-translations/ko-KR/api/locales.md deleted file mode 100644 index 468cbd752eeac..0000000000000 --- a/docs-translations/ko-KR/api/locales.md +++ /dev/null @@ -1,140 +0,0 @@ -# 로케일 - -> `app.getLocale()`에서 반환되는 로케일 값. - -Electron은 로케일을 가져오기 위해 Chromium의 `l10n_util` 라이브러리를 사용합니다. -반환될 수 있는 값은 다음과 같습니다: - - -| 언어 코드 | 언어 이름 | -|---------------|---------------| -| af | Afrikaans | -| ar-AE | Arabic (U.A.E.) | -| ar-IQ | Arabic (Iraq) | -| ar | Arabic (Standard) | -| ar-BH | Arabic (Bahrain) | -| ar-DZ | Arabic (Algeria) | -| ar-EG | Arabic (Egypt) | -| ar | Aragonese | -| ar-JO | Arabic (Jordan) | -| ar-KW | Arabic (Kuwait) | -| ar-LB | Arabic (Lebanon) | -| ar-LY | Arabic (Libya) | -| ar-MA | Arabic (Morocco) | -| ar-OM | Arabic (Oman) | -| ar-QA | Arabic (Qatar) | -| ar-SA | Arabic (Saudi Arabia) | -| ar-SY | Arabic (Syria) | -| ar-TN | Arabic (Tunisia) | -| ar-YE | Arabic (Yemen) | -| as | Assamese | -| ast | Asturian | -| az | Azerbaijani | -| be | Belarusian | -| bg | Bulgarian | -| bg | Bulgarian | -| bn | Bengali | -| br | Breton | -| bs | Bosnian | -| ca | Catalan | -| ce | Chechen | -| ch | Chamorro | -| co | Corsican | -| cr | Cree | -| cs | Czech | -| cv | Chuvash | -| da | Danish | -| de | German (Standard) | -| de-AT | German (Austria) | -| de-CH | German (Switzerland) | -| de-DE | German (Germany) | -| de-LI | German (Liechtenstein) | -| de-LU | German (Luxembourg) | -| el | Greek | -| en-AU | English (Australia) | -| en-BZ | English (Belize) | -| en | English | -| en-CA | English (Canada) | -| en-GB | English (United Kingdom) | -| en-IE | English (Ireland) | -| en-JM | English (Jamaica) | -| en-NZ | English (New Zealand) | -| en-PH | English (Philippines) | -| en-TT | English (Trinidad & Tobago) | -| en-US | English (United States) | -| en-ZA | English (South Africa) | -| en-ZW | English (Zimbabwe) | -| eo | Esperanto | -| et | Estonian | -| eu | Basque | -| fa | Persian | -| fa | Farsi | -| fa-IR | Persian/Iran | -| fi | Finnish | -| fj | Fijian | -| fo | Faeroese | -| fr-CH | French (Switzerland) | -| fr-FR | French (France) | -| fr-LU | French (Luxembourg) | -| fr-MC | French (Monaco) | -| fr | French (Standard) | -| fr-BE | French (Belgium) | -| fr-CA | French (Canada) | -| fur | Friulian | -| fy | Frisian | -| ga | Irish | -| gd-IE | Gaelic (Irish) | -| gd | Gaelic (Scots) | -| gl | Galacian | -| gu | Gujurati | -| he | Hebrew | -| hi | Hindi | -| hr | Croatian | -| ht | Haitian | -| hu | Hungarian | -| hy | Armenian | -| id | Indonesian | -| is | Icelandic | -| it-CH | Italian (Switzerland) | -| it | Italian (Standard) | -| iu | Inuktitut | -| ja | Japanese | -| ka | Georgian | -| kk | Kazakh | -| km | Khmer | -| kn | Kannada | -| ko | Korean | -| ko-KP | Korean (North Korea) | -| ko-KR | Korean (South Korea) | -| ks | Kashmiri | -| ky | Kirghiz | -| la | Latin | -| lb | Luxembourgish | -| lt | Lithuanian | -| lv | Latvian | -| mi | Maori | -| mk | FYRO Macedonian | -| ml | Malayalam | -| mo | Moldavian | -| mr | Marathi | -| ms | Malay | -| mt | Maltese | -| my | Burmese | -| nb | Norwegian (Bokmal) | -| ne | Nepali | -| ng | Ndonga | -| nl | Dutch (Standard) | -| nl-BE | Dutch (Belgian) | -| nn | Norwegian (Nynorsk) | -| no | Norwegian | -| nv | Navajo | -| oc | Occitan | -| om | Oromo | -| or | Oriya | -| sq | Albanian | -| tlh | Klingon | -| zh-TW | Chinese (Taiwan) | -| zh | Chinese | -| zh-CN | Chinese (PRC) | -| zh-HK | Chinese (Hong Kong) | -| zh-SG | Chinese (Singapore) | diff --git a/docs-translations/ko-KR/api/menu-item.md b/docs-translations/ko-KR/api/menu-item.md deleted file mode 100644 index 27ad7216c9f8b..0000000000000 --- a/docs-translations/ko-KR/api/menu-item.md +++ /dev/null @@ -1,99 +0,0 @@ -# MenuItem - -> 네이티브 애플리케이션 메뉴와 컨텍스트 메뉴에 아이템을 추가합니다. - -[`Menu`](menu.md)에서 예시를 확인할 수 있습니다. - -## Class: MenuItem - -`MenuItem` 인스턴스 객체에서 사용할 수 있는 메서드입니다: - -### new MenuItem(options) - -* `options` Object - * `click` Function - 메뉴 아이템이 클릭될 때 `click(menuItem, browserWindow, - event)` 형태로 호출 되는 콜백 함수. - * `role` String - 메뉴 아이템의 액션을 정의합니다. 이 속성을 지정하면 `click` - 속성이 무시됩니다. - * `type` String - `MenuItem`의 타입 `normal`, `separator`, `submenu`, - `checkbox` 또는 `radio`를 사용할 수 있습니다. 만약 값이 `Menu`가 아니면 - `Menu.buildFromTemplate`를 통해 자동으로 변환됩니다. - * `label` String - * `sublabel` String - * `accelerator` [Accelerator](accelerator.md) - * `icon` [NativeImage](native-image.md) - * `enabled` Boolean - 만약 `false`로 설정되면, 메뉴 아이템이 회색으로 변하며 - 클릭할 수 없게 됩니다. - * `visible` Boolean - 만약 `false`로 설정되면, 메뉴 아이템이 완전히 숨겨집니다. - * `checked` Boolean - 반드시 `checkbox` 또는 `radio` 타입의 메뉴 아이템에만 - 지정해야 합니다. - * `submenu` Menu - 반드시 `submenu` 타입의 메뉴 아이템에만 지정해야 합니다. 만약 - `submenu`가 지정되면 `type: 'submenu'`는 생략될 수 있습니다. 만약 값이 `Menu`가 - 아닐 경우 `Menu.buildFromTemplate`을 통해 자동적으로 변환됩니다. - * `id` String - 현재 메뉴 아이템에 대해 유일키를 지정합니다. 이 키는 이후 - `position` 옵션에서 사용할 수 있습니다. - * `position` String - 미리 지정한 `id`를 이용하여 메뉴 아이템의 위치를 세밀하게 - 조정합니다. - -어떠한 메뉴 아이템이 표준 롤에 일치한다면, `role`을 지정하는 것이 동작을 `click` -함수로 일일이 구현하려 시도하는 것 보다 더 좋을 수 있습니다. 빌트-인 `role` 동작은 -더 좋은 네이티브 경험을 제공할 것입니다. - -`role`을 사용하는 동안에는 `label`과 `accelerator`는 필수가 아니며 각 플랫폼에 대해 -적합한 값이 기본값으로 사용됩니다. - -`role` 속성은 다음 값을 가질 수 있습니다: - -* `undo` -* `redo` -* `cut` -* `copy` -* `paste` -* `pasteandmatchstyle` -* `selectall` -* `delete` -* `minimize` - 현재 윈도우를 최소화합니다 -* `close` - 현재 윈도우를 닫습니다 -* `quit`- 애플리케이션을 닫습니다 -* `togglefullscreen` - 현재 윈도우에서 전체 화면 모드를 토글합니다 - -macOS에서의 `role`은 다음 값을 추가로 가질 수 있습니다: - -* `about` - `orderFrontStandardAboutPanel` 액션에 대응 -* `hide` - `hide` 액션에 대응 -* `hideothers` - `hideOtherApplications` 액션에 대응 -* `unhide` - `unhideAllApplications` 액션에 대응 -* `front` - `arrangeInFront` 액션에 대응 -* `zoom` - `performZoom` 액션에 대응 -* `window` - 부 메뉴를 가지는 "Window" 메뉴 -* `help` - 부 메뉴를 가지는 "Help" 메뉴 -* `services` - 부 메뉴를 가지는 "Services" 메뉴 - -macOS에서는 `role`을 지정할 때, `label`과 `accelerator`만 MenuItem에 효과가 -적용되도록 변경되며, 다른 옵션들은 모두 무시됩니다. - -### Instance Properties - -다음은 `MenuItem`의 인스턴스에서 사용할 수 있는 속성입니다: - -#### `menuItem.enabled` - -아이템이 활성화되어있는지 여부를 표시하는 Boolean 값입니다. 이 속성은 동적으로 변경될 -수 있습니다. - -#### `menuItem.visible` - -아이템이 보여지고있는지 여부를 표시하는 Boolean 값입니다. 이 속성은 동적으로 변경될 -수 있습니다. - -#### `menuItem.checked` - -아이템이 선택되어있는지 여부를 반환하는 Boolean 값입니다. 이 속성은 동적으로 변경될 -수 있습니다. - -`checkbox` 메뉴 아이템은 선택되면 `checked` 속성을 토글합니다. - -`radio` 메뉴 아이템은 클릭되었을 때 `checked` 속성을 활성화 합니다. 그리고 -같은 메뉴의 모든 인접한 아이템에 대한 속성이 꺼집니다. - -추가적인 작업을 위해 `click` 함수를 추가할 수도 있습니다. diff --git a/docs-translations/ko-KR/api/menu.md b/docs-translations/ko-KR/api/menu.md deleted file mode 100644 index c6ba3a6bb9081..0000000000000 --- a/docs-translations/ko-KR/api/menu.md +++ /dev/null @@ -1,369 +0,0 @@ -# Menu - -> 네이티브 애플리케이션 메뉴와 컨텍스트 메뉴를 생성합니다. - -이 모듈은 메인 프로세스용 모듈이지만 `remote` 모듈을 통해 렌더러 프로세스에서도 사용할 -수 있습니다. - -각 메뉴는 여러 개의 [메뉴 아이템](menu-item.md)으로 구성되고 서브 메뉴를 가질 수도 있습니다. - -다음 예시는 웹 페이지 내에서 [remote](remote.md) 모듈을 활용하여 동적으로 메뉴를 -생성하는 예시입니다. 그리고 유저가 페이지에서 오른쪽 클릭을 할 때마다 마우스 위치에 -팝업 형태로 메뉴를 표시합니다: - -```html - - -``` - -또 하나의 예를 들자면 다음 예시는 렌더러 프로세스에서 template API를 사용하여 -애플리케이션 메뉴를 만듭니다: - -```javascript -const template = [ - { - label: 'Edit', - submenu: [ - { - role: 'undo' - }, - { - role: 'redo' - }, - { - type: 'separator' - }, - { - role: 'cut' - }, - { - role: 'copy' - }, - { - role: 'paste' - }, - { - role: 'pasteandmatchstyle' - }, - { - role: 'delete' - }, - { - role: 'selectall' - }, - ] - }, - { - label: 'View', - submenu: [ - { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click(item, focusedWindow) { - if (focusedWindow) focusedWindow.reload(); - } - }, - { - role: 'togglefullscreen' - }, - { - label: 'Toggle Developer Tools', - accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I', - click(item, focusedWindow) { - if (focusedWindow) - focusedWindow.webContents.toggleDevTools(); - } - }, - ] - }, - { - role: 'window', - submenu: [ - { - role: 'minimize' - }, - { - role: 'close' - }, - ] - }, - { - role: 'help', - submenu: [ - { - label: 'Learn More', - click() { require('electron').shell.openExternal('http://electron.atom.io'); } - }, - ] - }, -]; - -if (process.platform === 'darwin') { - const name = require('electron').remote.app.getName(); - template.unshift({ - label: name, - submenu: [ - { - role: 'about' - }, - { - type: 'separator' - }, - { - role: 'services', - submenu: [] - }, - { - type: 'separator' - }, - { - role: 'hide' - }, - { - role: 'hideothers' - }, - { - role: 'unhide' - }, - { - type: 'separator' - }, - { - role: 'quit' - }, - ] - }); - // Window menu. - template[3].submenu = [ - { - label: 'Close', - accelerator: 'CmdOrCtrl+W', - role: 'close' - }, - { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize' - }, - { - label: 'Zoom', - role: 'zoom' - }, - { - type: 'separator' - }, - { - label: 'Bring All to Front', - role: 'front' - } - ]; -} - -const menu = Menu.buildFromTemplate(template); -Menu.setApplicationMenu(menu); -``` - -## Class: Menu - -### `new Menu()` - -새로운 메뉴를 생성합니다. - -## Methods - -`menu` 클래스는 다음과 같은 메서드를 가지고 있습니다: - -### `Menu.setApplicationMenu(menu)` - -* `menu` Menu - -지정한 `menu`를 애플리케이션 메뉴로 만듭니다. macOS에선 상단바에 표시되며 Windows와 -Linux에선 각 창의 상단에 표시됩니다. - -**참고** 이 API는 `app`의 `ready` 이벤트가 발생한 이후에 호출해야 합니다. - -### `Menu.getApplicationMenu()` - -설정되어있는 어플리케이션 메뉴를 반환합니다. (`Menu`의 인스턴스) 만약 없다면 `null`을 -반환합니다. - -### `Menu.sendActionToFirstResponder(action)` _macOS_ - -* `action` String - -`action`을 애플리케이션의 first responder에 전달합니다. 이 메서드는 Cocoa 메뉴 -동작을 에뮬레이트 하는데 사용되며 보통 `MenuItem`의 `role` 속성에 사용됩니다. - -macOS의 네이티브 액션에 대해 자세히 알아보려면 -[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) -문서를 참고하세요. - -### `Menu.buildFromTemplate(template)` - -* `template` Array - -기본적으로 `template`는 [MenuItem](menu-item.md)을 생성할 때 사용하는 `options`의 -배열입니다. 사용법은 위에서 설명한 것과 같습니다. - -또한 `template`에는 다른 속성도 추가할 수 있으며 메뉴가 만들어질 때 해당 메뉴 아이템의 -프로퍼티로 변환됩니다. - -## Instance Methods - -`menu` 객체는 다음과 같은 인스턴스 메서드를 가지고 있습니다: - -### `menu.popup([browserWindow, x, y, positioningItem])` - -* `browserWindow` BrowserWindow (optional) - 기본값은 `null`입니다. -* `x` Number (optional) - 기본값은 -1입니다. -* `y` Number (만약 `x`를 지정한 경우 **필수 항목**) - 기본값은 -1입니다. -* `positioningItem` Number (optional) _macOS_ - 메뉴 팝업 시 마우스 커서에 바로 - 위치시킬 메뉴 아이템의 인덱스. 기본값은 -1입니다. - -메뉴를 `browserWindow` 내부 팝업으로 표시합니다. 옵션으로 메뉴를 표시할 `(x,y)` -좌표를 지정할 수 있습니다. 따로 좌표를 지정하지 않은 경우 마우스 커서 위치에 표시됩니다. -`positioningItem` 속성은 메뉴 팝업 시 마우스 커서에 바로 위치시킬 메뉴 아이템의 -인덱스입니다. (macOS에서만 지원합니다) - -### `menu.append(menuItem)` - -* `menuItem` MenuItem - -메뉴의 리스트 끝에 `menuItem`을 삽입합니다. - -### `menu.insert(pos, menuItem)` - -* `pos` Integer -* `menuItem` MenuItem - -`pos` 위치에 `menuItem`을 삽입합니다. - -## Instance Properties - -`menu` 객체는 또한 다음과 같은 속성을 가지고 있습니다: - -### `menu.items` - -메뉴가 가지고 있는 메뉴 아이템들의 배열입니다. - -## macOS 애플리케이션 메뉴에 대해 알아 둬야 할 것들 - -macOS에선 Windows, Linux와 달리 완전히 다른 애플리케이션 메뉴 스타일을 가지고 있습니다. -그래서 애플리케이션을 네이티브처럼 작동할 수 있도록 하기 위해 다음 몇 가지 유의 사항을 -숙지해야 합니다. - -### 기본 메뉴 - -macOS엔 `Services`나 `Windows`와 같은 많은 시스템 지정 기본 메뉴가 있습니다. 기본 -메뉴를 만들려면 반드시 다음 리스트 중 한 가지를 선택하여 메뉴의 `role`로 지정해야 -합니다. 그러면 Electron이 자동으로 인식하여 해당 메뉴를 기본 메뉴로 만듭니다: - -* `window` -* `help` -* `services` - -### 메뉴 아이템 기본 동작 - -macOS는 몇가지 메뉴 아이템에 대해 `About xxx`, `Hide xxx`, `Hide Others`와 같은 -기본 동작을 제공하고 있습니다. 메뉴 아이템의 기본 동작을 지정하려면 반드시 메뉴 -아이템의 `role` 속성을 지정해야 합니다. - -### 메인 메뉴의 이름 - -macOS에선 지정한 애플리케이션 메뉴에 상관없이 메뉴의 첫번째 라벨은 언제나 애플리케이션의 -이름이 됩니다. 애플리케이션 이름을 변경하려면 앱 번들내의 `Info.plist` 파일을 수정해야 -합니다. 자세한 내용은 [About Information Property List Files][AboutInformationPropertyListFiles] 문서를 참고하세요. - -## 지정한 브라우저 윈도우에 메뉴 설정 (*Linux* *Windows*) - -브라우저 윈도우의 [`setMenu` 메서드][setMenu]는 어떤 브라우저 윈도우의 메뉴를 설정할 -수 있습니다. - -## 메뉴 아이템 위치 - -`Menu.buildFromTemplate`로 메뉴를 만들 때 `position`과 `id`를 사용해서 아이템의 -위치를 지정할 수 있습니다. - -`MenuItem`의 `position` 속성은 `[placement]=[id]`와 같은 형식을 가지며 -`placement`는 `before`, `after`, `endof` 속성 중 한가지를 사용할 수 있고 `id`는 -메뉴 아이템이 가지는 유일 ID 입니다: - -* `before` - 이 아이템을 지정한 id 이전의 위치에 삽입합니다. 만약 참조된 아이템이 - 없을 경우 메뉴의 맨 뒤에 삽입됩니다. -* `after` - 이 아이템을 지정한 id 다음의 위치에 삽입합니다. 만약 참조된 아이템이 - 없을 경우 메뉴의 맨 뒤에 삽입됩니다. -* `endof` - 이 아이템을 id의 논리 그룹에 맞춰서 각 그룹의 항목 뒤에 삽입합니다. - (그룹은 분리자 아이템에 의해 만들어집니다) 만약 참조된 아이템의 분리자 그룹이 - 존재하지 않을 경우 지정된 id로 새로운 분리자 그룹을 만든 후 해당 그룹의 뒤에 - 삽입됩니다. - -위치를 지정한 아이템의 뒤에 위치가 지정되지 않은 아이템이 있을 경우 각 아이템의 위치가 -지정되기 전까지 모든 아이템이 위치가 지정된 아이템의 뒤에 삽입됩니다. 따라서 위치를 -이동하고 싶은 특정 그룹의 아이템들이 있을 경우 해당 그룹의 맨 첫번째 메뉴 아이템의 -위치만을 지정하면 됩니다. - -### 예시 - -메뉴 템플릿: - -```javascript -[ - {label: '4', id: '4'}, - {label: '5', id: '5'}, - {label: '1', id: '1', position: 'before=4'}, - {label: '2', id: '2'}, - {label: '3', id: '3'} -] -``` - -메뉴: - -``` -- 1 -- 2 -- 3 -- 4 -- 5 -``` - -메뉴 템플릿: - -```javascript -[ - {label: 'a', position: 'endof=letters'}, - {label: '1', position: 'endof=numbers'}, - {label: 'b', position: 'endof=letters'}, - {label: '2', position: 'endof=numbers'}, - {label: 'c', position: 'endof=letters'}, - {label: '3', position: 'endof=numbers'} -] -``` - -메뉴: - -``` -- --- -- a -- b -- c -- --- -- 1 -- 2 -- 3 -``` - -[AboutInformationPropertyListFiles]: https://developer.apple.com/library/ios/documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html -[setMenu]: ./browser-window.md#winsetmenumenu-linux-windows diff --git a/docs-translations/ko-KR/api/native-image.md b/docs-translations/ko-KR/api/native-image.md deleted file mode 100644 index dfdc180b6c789..0000000000000 --- a/docs-translations/ko-KR/api/native-image.md +++ /dev/null @@ -1,169 +0,0 @@ -# nativeImage - -> PNG 또는 JPG 파일을 사용하여 트레이, 독, 애플리케이션 아이콘을 생성합니다. - -Electron은 파일 경로 또는 `nativeImage` 인스턴스를 통해 이미지를 사용할 수 있는 API를 -가지고 있습니다. `null`을 전달할 경우 빈 이미지가 생성됩니다. - -예를 들어 트레이 메뉴를 만들거나 윈도우의 아이콘을 설정할 때 다음과 같이 파일 경로를 -전달하여 이미지를 사용할 수 있습니다: - -```javascript -const appIcon = new Tray('/Users/somebody/images/icon.png'); -let win = new BrowserWindow({icon: '/Users/somebody/images/window.png'}); -``` - -이 예시는 클립보드로부터 가져온 `nativeImage`로 트레이 메뉴를 생성합니다: - -```javascript -const image = clipboard.readImage(); -const appIcon = new Tray(image); -``` - -## 지원하는 포맷 - -현재 `PNG` 와 `JPEG` 이미지 포맷을 지원하고 있습니다. -손실 없는 이미지 압축과 투명도 지원을 위해 `PNG` 사용을 권장합니다. - -Windows에서는 파일 경로로부터 `ICO` 포맷도 사용할 수 있으며, 가장 좋은 시각적 효과를 -얻기 위해 최소한 아이콘에 다음 사이즈를 포함하는 것을 권장합니다: - -* 16x16 -* 32x32 -* 64x64 -* 256x256 - -## 고해상도 이미지 - -플랫폼이 high-DPI를 지원하는 경우 `@2x`와 같이 이미지의 파일명 뒤에 접미사를 추가하여 -고해상도 이미지로 지정할 수 있습니다. - -예를 들어 `icon.png` 라는 기본 해상도의 이미지를 기준으로 크기를 두 배로 늘린 이미지를 -`icon@2x.png` 처럼 지정하면 고해상도 이미지로 처리됩니다. - -서로 다른 해상도(DPI)의 이미지를 같이 지원하고 싶다면 다중 해상도의 이미지를 접미사를 -붙여 한 폴더에 같이 넣으면 됩니다. 이 이미지를 사용(로드)할 땐 따로 접미사를 붙이지 -않습니다: - -```text -images/ -├── icon.png -├── icon@2x.png -└── icon@3x.png -``` - - -```javascript -let appIcon = new Tray('/Users/somebody/images/icon.png'); -``` - -지원하는 DPI 접미사는 다음과 같습니다: - -* `@1x` -* `@1.25x` -* `@1.33x` -* `@1.4x` -* `@1.5x` -* `@1.8x` -* `@2x` -* `@2.5x` -* `@3x` -* `@4x` -* `@5x` - -## 템플릿 이미지 - -템플릿 이미지는 검은색과 명확한 색상(알파 채널)으로 이루어져 있습니다. 템플릿 이미지는 -단독 이미지로 사용되지 않고 다른 콘텐츠와 혼합되어 최종 외관 만드는데 사용됩니다. - -가장 일반적으로 템플릿 이미지는 밝고 어두운 테마 색상으로 변경할 수 있는 메뉴 바 아이콘 -등에 사용되고 있습니다. - -**참고:** 템플릿 이미지는 macOS 운영체제만 지원합니다. - -템플릿 이미지를 지정하려면 다음 예시와 같이 파일명에 `Template` 문자열을 추가해야 -합니다: - -* `xxxTemplate.png` -* `xxxTemplate@2x.png` - -## Methods - -`nativeImage` 클래스는 다음과 같은 메서드를 가지고 있습니다: - -### `nativeImage.createEmpty()` - -빈 `nativeImage` 인스턴스를 만듭니다. - -### `nativeImage.createFromPath(path)` - -* `path` String - -`path`로부터 이미지를 로드하여 새로운 `nativeImage` 인스턴스를 만듭니다. - -```javascript -const nativeImage = require('electron').nativeImage; - -let image = nativeImage.createFromPath('/Users/somebody/images/icon.png'); -``` - -### `nativeImage.createFromBuffer(buffer[, scaleFactor])` - -* `buffer` [Buffer][buffer] -* `scaleFactor` Double (optional) - -`buffer`로부터 이미지를 로드하여 새로운 `nativeImage` 인스턴스를 만듭니다. -`scaleFactor`의 기본값은 1.0 입니다. - -### `nativeImage.createFromDataURL(dataURL)` - -* `dataURL` String - -`dataURL`로부터 이미지를 로드하여 새로운 `nativeImage` 인스턴스를 만듭니다. - -## Instance Methods - -`nativeImage` 인스턴스 객체에서 사용할 수 있는 메서드입니다. - -### `image.toPNG()` - -`PNG` 이미지를 인코딩한 데이터를 [Buffer][buffer]로 반환합니다. - -### `image.toJPEG(quality)` - -* `quality` Integer (**required**) 0 - 100 사이의 값 - -`JPEG` 이미지를 인코딩한 데이터를 [Buffer][buffer]로 반환합니다. - -### `image.toDataURL()` - -이미지를 data URL로 반환합니다. - -### `image.getNativeHandle()` _macOS_ - -이미지의 네이티브 핸들 밑에 있는 C 포인터를 담은 [Buffer][buffer]을 반환합니다. -macOS에선, `NSImage` 인스턴스가 반환됩니다. - -참고로 반환된 포인터는 복사본이 아닌 네이티브 이미지의 밑에 있는 약한 포인터이며, -따라서 반드시 관련된 `nativeImage` 인스턴스가 확실하게 유지되고 있는지를 인지해야 -합니다. - -### `image.isEmpty()` - -이미지가 비었는지 확인합니다. - -### `image.getSize()` - -이미지의 사이즈를 반환합니다. - -### `image.setTemplateImage(option)` - -* `option` Boolean - -해당 이미지를 템플릿 이미지로 설정합니다. - -### `image.isTemplateImage()` - -이미지가 템플릿 이미지인지 확인합니다. - -[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer diff --git a/docs-translations/ko-KR/api/power-monitor.md b/docs-translations/ko-KR/api/power-monitor.md deleted file mode 100644 index 860ac5eecbd4f..0000000000000 --- a/docs-translations/ko-KR/api/power-monitor.md +++ /dev/null @@ -1,38 +0,0 @@ -# powerMonitor - -> 파워의 상태 변경을 모니터링합니다. - -이 모듈은 메인 프로세스에서만 사용할 수 있습니다. `app` 모듈의 `ready` 이벤트가 -발생한 이후에만 사용할 수 없습니다. - -예시: - -```javascript -const {app} = require('electron'); - -app.on('ready', () => { - require('electron').powerMonitor.on('suspend', () => { - console.log('절전모드로 진입합니다!'); - }); -}); -``` - -## Events - -`power-monitor` 모듈은 다음과 같은 이벤트를 가지고 있습니다: - -## Event: `suspend` - -시스템이 절전모드로 진입할 때 발생하는 이벤트입니다. - -## Event: `resume` - -시스템의 절전모드가 해제될 때 발생하는 이벤트입니다. - -## Event: `on-ac` _Windows_ - -시스템이 AC 어뎁터 충전기를 사용하기 시작할 때 발생하는 이벤트입니다. - -## Event: `on-battery` _Windows_ - -시스템이 배터리를 사용하기 시작할 때 발생하는 이벤트입니다. diff --git a/docs-translations/ko-KR/api/power-save-blocker.md b/docs-translations/ko-KR/api/power-save-blocker.md deleted file mode 100644 index baa174498e27d..0000000000000 --- a/docs-translations/ko-KR/api/power-save-blocker.md +++ /dev/null @@ -1,55 +0,0 @@ -# powerSaveBlocker - -> 시스템이 저전력 (슬립) 모드로 진입하는 것을 막습니다. - -예시: - -```javascript -const {powerSaveBlocker} = require('electron'); - -const id = powerSaveBlocker.start('prevent-display-sleep'); -console.log(powerSaveBlocker.isStarted(id)); - -powerSaveBlocker.stop(id); -``` - -## Methods - -`powerSaveBlocker` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `powerSaveBlocker.start(type)` - -* `type` String - Power save blocker 종류 - * `prevent-app-suspension` - 저전력 모드 등으로 인한 애플리케이션 작동 중단을 - 방지합니다. 시스템을 항시 활성화 상태로 만듭니다. 하지만 화면은 자동으로 꺼질 수 - 있습니다. 사용 예시: 파일 다운로드, 음악 재생 등. - * `prevent-display-sleep`- 슬립 모드 등으로 인한 애플리케이션의 작동 중단을 - 방지합니다. 시스템을 항시 활성화 상태로 만들고 슬립 모드(화면 꺼짐)를 방지합니다. - 사용 예시: 비디오 재생 등. - -시스템이 저전력 모드(슬립)로 진입하는 것을 막기 시작합니다. 정수로 된 식별 ID를 -반환합니다. - -**참고:** `prevent-display-sleep` 모드는 `prevent-app-suspension` 보다 우선 순위가 -높습니다. 두 모드 중 가장 높은 우선 순위의 모드만 작동합니다. 다시 말해 -`prevent-display-sleep` 모드는 언제나 `prevent-app-suspension` 모드의 효과를 -덮어씌웁니다. - -예를 들어 A-요청이 `prevent-app-suspension` 모드를 사용하고 B-요청이 -`prevent-display-sleep`를 사용하는 API 호출이 있었다 하면 `prevent-display-sleep` -모드를 사용하는 B의 작동이 중단(stop)되기 전까지 작동하다 B가 중단되면 -`prevent-app-suspension` 모드를 사용하는 A가 작동하기 시작합니다. - -### `powerSaveBlocker.stop(id)` - -* `id` Integer - `powerSaveBlocker.start`로부터 반환되는 power save blocker 식별 -ID. - -설정한 power save blocker를 중지합니다. - -### `powerSaveBlocker.isStarted(id)` - -* `id` Integer - `powerSaveBlocker.start`로부터 반환되는 power save blocker 식별 -ID. - -지정한 id의 `powerSaveBlocker`가 실행 중인지 확인합니다. diff --git a/docs-translations/ko-KR/api/process.md b/docs-translations/ko-KR/api/process.md deleted file mode 100644 index d7f27bc33dd24..0000000000000 --- a/docs-translations/ko-KR/api/process.md +++ /dev/null @@ -1,141 +0,0 @@ -# process - -> process 객체에 대한 확장 기능. - -`process` 객체는 Electron에서 약간 추가적인 기능이 있으며 API는 다음과 같습니다: - -## Events - -### Event: 'loaded' - -Electron 내부 초기화 스크립트의 로드가 완료되고, 웹 페이지나 메인 스크립트를 로드하기 -시작할 때 발생하는 이벤트입니다. - -이 이벤트는 preload 스크립트를 통해 node 통합이 꺼져있는 전역 스코프에 node의 전역 -심볼들을 다시 추가할 때 사용할 수 있습니다: - -```javascript -// preload.js -const _setImmediate = setImmediate; -const _clearImmediate = clearImmediate; -process.once('loaded', () => { - global.setImmediate = _setImmediate; - global.clearImmediate = _clearImmediate; -}); -``` - -## Properties - -### `process.noAsar` - -Setting this to `true` can disable the support for `asar` archives in Node's -built-in modules. - -### `process.type` - -Current process's type, can be `"browser"` (i.e. main process) or `"renderer"`. - -### `process.versions.electron` - -Electron's version string. - -### `process.versions.chrome` - -Chrome's version string. - -### `process.resourcesPath` - -Path to the resources directory. - -### `process.mas` - -For Mac App Store build, this property is `true`, for other builds it is -`undefined`. - -### `process.windowsStore` - -If the app is running as a Windows Store app (appx), this property is `true`, -for otherwise it is `undefined`. - -### `process.defaultApp` - -When app is started by being passed as parameter to the default app, this -property is `true` in the main process, otherwise it is `undefined`. - -## Methods - -The `process` object has the following method: - -### `process.crash()` - -Causes the main thread of the current process crash. - -### `process.hang()` - -Causes the main thread of the current process hang. - -### `process.setFdLimit(maxDescriptors)` _macOS_ _Linux_ - -* `maxDescriptors` Integer - -Sets the file descriptor soft limit to `maxDescriptors` or the OS hard -limit, whichever is lower for the current process. - -### `process.getProcessMemoryInfo()` - -Returns an object giving memory usage statistics about the current process. Note -that all statistics are reported in Kilobytes. - -* `workingSetSize` - The amount of memory currently pinned to actual physical - RAM. -* `peakWorkingSetSize` - The maximum amount of memory that has ever been pinned - to actual physical RAM. -* `privateBytes` - The amount of memory not shared by other processes, such as - JS heap or HTML content. -* `sharedBytes` - The amount of memory shared between processes, typically - memory consumed by the Electron code itself - -### `process.getSystemMemoryInfo()` - -Returns an object giving memory usage statistics about the entire system. Note -that all statistics are reported in Kilobytes. - -* `total` - The total amount of physical memory in Kilobytes available to the - system. -* `free` - The total amount of memory not being used by applications or disk - cache. - -On Windows / Linux: - -* `swapTotal` - The total amount of swap memory in Kilobytes available to the - system. -* `swapFree` - The free amount of swap memory in Kilobytes available to the - system. - ----------------------------------------- - -## Properties - -### `process.noAsar` - -이 속성을 `true`로 지정하면 Node 빌트인 모듈의 `asar` 아카이브 지원을 비활성화 시킬 -수 있습니다. - -## Methods - -`process` 객체는 다음과 같은 메서드를 가지고 있습니다: - -### `process.crash()` - -현재 프로세스의 메인 스레드에 크래시를 일으킵니다. - -### `process.hang()` - -현재 프로세스의 주 스레드를 중단시킵니다. - -### `process.setFdLimit(maxDescriptors)` _macOS_ _Linux_ - -* `maxDescriptors` Integer - -현재 프로세스 파일 디스크립터의 제한 값을 소프트 제한 `maxDescriptors`의 값이나 OS 하드 -제한 중 낮은 값으로 설정합니다. diff --git a/docs-translations/ko-KR/api/protocol.md b/docs-translations/ko-KR/api/protocol.md deleted file mode 100644 index 97a47c632dc03..0000000000000 --- a/docs-translations/ko-KR/api/protocol.md +++ /dev/null @@ -1,222 +0,0 @@ -# protocol - -> 커스텀 프로토콜을 등록하거나 이미 존재하능 프로토콜의 요청의 동작을 변경합니다. - -다음 예시는 `file://` 프로토콜과 비슷한 일을 하는 커스텀 프로토콜을 설정합니다: - -```javascript -const {app, protocol} = require('electron'); -const path = require('path'); - -app.on('ready', () => { - protocol.registerFileProtocol('atom', function (request, callback) { - const url = request.url.substr(7); - callback({path: path.normalize(__dirname + '/' + url)}); - }, function (error) { - if (error) - console.error('Failed to register protocol'); - }); -}); -``` - -**참고:** 모든 메서드는 따로 표기하지 않는 한 `app` 모듈의 `ready` 이벤트가 발생한 -이후에만 사용할 수 있습니다. - -## Methods - -`protocol` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `protocol.registerStandardSchemes(schemes)` - -* `schemes` Array - 표준 스킴으로 등록할 커스텀 스킴 리스트 - -표준 스킴의 형식은 RFC 3986 [일반 URI 문법](https://tools.ietf.org/html/rfc3986#section-3) -표준을 따릅니다. 예를 들어 `http`와 `https` 같은 표준 스킴과 `file`과 같은 표준이 -아닌 스킴이 있습니다. - -표준 스킴으로 등록하면, 상대, 절대 경로의 리소스를 올바르게 취할 수 있습니다. 다른 -경우엔 스킴이 상대 경로 URL에 대한 분석 기능이 제외된 `file` 프로토콜과 같이 -작동합니다. - -예를 들어 다음과 같은 페이지에서 표준 스킴 등록 절차 없이 커스텀 프로토콜을 사용하여 -이미지를 로드하려 했을 때, 표준 스킴으로 등록되지 않은 상대 경로 URL을 인식하지 못하고 -로드에 실패하게 됩니다: - -```html - - - -``` - -따라서 커스텀 프로토콜을 등록하여 `http` 프로토콜을 덮어 쓰려면, 표준 스킴으로 -등록해야만 합니다: - -```javascript -protocol.registerStandardSchemes(['atom']); -app.on('ready', () => { - protocol.registerHttpProtocol('atom', ...); -}); -``` - -**참고:** 이 메서드는 `app` 모듈의 `ready` 이벤트가 발생하기 이전에만 사용할 수 -있습니다. - -### `protocol.registerServiceWorkerSchemes(schemes)` - -* `schemes` Array - 서비스 워커를 제어하기 위해 등록될 커스텀 스킴. - -### `protocol.registerFileProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`scheme`에 파일을 응답으로 보내는 프로토콜을 등록합니다. `handler`는 `scheme`와 함께 -`request`가 생성될 때 `handler(request, callback)` 형식으로 호출됩니다. -`completion` 콜백은 `scheme`가 성공적으로 등록되었을 때 `completion(null)` 형식으로 -호출되고, 등록에 실패했을 땐 `completion(error)` 형식으로 에러 내용을 담아 호출됩니다. - -* `request` Object - * `url` String - * `referrer` String - * `method` String - * `uploadData` Array (optional) -* `callback` Function - -The `uploadData` is an array of `data` objects: - -* `data` Object - * `bytes` Buffer - Content being sent. - * `file` String - Path of file being uploaded. - -`request`를 처리할 때 반드시 파일 경로 또는 `path` 속성을 포함하는 객체를 인수에 -포함하여 `callback`을 호출해야 합니다. 예: `callback(filePath)` 또는 -`callback({path: filePath})`. - -만약 `callback`이 아무 인수도 없이 호출되거나 숫자나 `error` 프로퍼티를 가진 객체가 -인수로 전달될 경우 `request`는 지정한 `error` 코드(숫자)를 출력합니다. 사용할 수 있는 -에러 코드는 [네트워크 에러 목록][net-error]에서 확인할 수 있습니다. - -기본적으로 `scheme`은 `http:`와 같이 처리됩니다. `file:`과 같이 "일반적인 URI 문법" -과는 다르게 인식되는 프로토콜은 `protocol.registerStandardSchemes`을 사용하여 표준 -스킴으로 처리되도록 할 수 있습니다. - -### `protocol.registerBufferProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`Buffer`를 응답으로 전송하는 `scheme`의 프로토콜을 등록합니다. - -사용법은 `callback`이 반드시 `Buffer` 객체 또는 `data`, `mimeType`, `charset` -속성을 포함하는 객체와 함께 호출되어야 한다는 점을 제외하면 `registerFileProtocol`과 -사용법이 같습니다. - -예시: - -```javascript -protocol.registerBufferProtocol('atom', (request, callback) => { - callback({mimeType: 'text/html', data: new Buffer('
Response
')}); -}, (error) => { - if (error) - console.error('Failed to register protocol'); -}); -``` - -### `protocol.registerStringProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`String`을 응답으로 전송할 `scheme`의 프로토콜을 등록합니다. - -사용법은 `callback`이 반드시 `String` 또는 `data`, `mimeType`, `charset` 속성을 -포함하는 객체와 함께 호출되어야 한다는 점을 제외하면 `registerFileProtocol`과 -사용법이 같습니다. - -### `protocol.registerHttpProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -HTTP 요청을 응답으로 전송할 `scheme`의 프로토콜을 등록합니다. - -사용법은 `callback`이 반드시 `url`, `method`, `referrer`, `uploadData`와 -`session` 속성을 포함하는 `redirectRequest` 객체와 함께 호출되어야 한다는 점을 -제외하면 `registerFileProtocol`과 사용법이 같습니다. - -* `redirectRequest` Object - * `url` String - * `method` String - * `session` Object (optional) - * `uploadData` Object (optional) - -기본적으로 HTTP 요청은 현재 세션을 재사용합니다. 만약 서로 다른 세션에 요청을 보내고 -싶으면 `session`을 `null`로 지정해야 합니다. - -POST 요청에는 반드시 `uploadData` 객체가 제공되어야 합니다. - -* `uploadData` object - * `contentType` String - 콘텐츠의 MIME 타입. - * `data` String - 전송할 콘텐츠. - -### `protocol.unregisterProtocol(scheme[, completion])` - -* `scheme` String -* `completion` Function (optional) - -`scheme`의 커스텀 프로토콜 등록을 해제합니다. - -### `protocol.isProtocolHandled(scheme, callback)` - -* `scheme` String -* `callback` Function - -`scheme`에 동작(handler)이 등록되어 있는지 여부를 확인합니다. `callback`으로 -결과(boolean)가 반환됩니다. - -### `protocol.interceptFileProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`scheme` 프로토콜을 가로채고 `handler`를 파일 전송에 대한 새로운 동작으로 사용합니다. - -### `protocol.interceptStringProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`scheme` 프로토콜을 가로채고 `handler`를 문자열 전송에 대한 새로운 동작으로 사용합니다. - -### `protocol.interceptBufferProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`scheme` 프로토콜을 가로채고 `handler`를 `Buffer` 전송에 대한 새로운 동작으로 -사용합니다. - -### `protocol.interceptHttpProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -`scheme` 프로토콜을 가로채고 `handler`를 HTTP 프로토콜의 요청에 대한 새로운 동작으로 -사용합니다. - -### `protocol.uninterceptProtocol(scheme[, completion])` - -* `scheme` String -* `completion` Function (optional) - -가로챈 `scheme`를 삭제하고 기본 핸들러로 복구합니다. - -[net-error]: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h diff --git a/docs-translations/ko-KR/api/remote.md b/docs-translations/ko-KR/api/remote.md deleted file mode 100644 index 763637f81ae44..0000000000000 --- a/docs-translations/ko-KR/api/remote.md +++ /dev/null @@ -1,157 +0,0 @@ -# remote - -> 메인 프로세스 모듈을 렌더러 프로세스에서 사용합니다. - -`remote` 모듈은 메인 프로세스와 렌더러 프로세스(웹 페이지) 사이의 inter-process -(IPC) 통신을 간단하게 추상화 한 모듈입니다. - -Electron의 메인 프로세스에선 GUI와 관련 있는(`dialog`, `menu`등) 모듈만 사용할 수 -있습니다. 렌더러 프로세스에서 이러한 모듈들을 사용하려면 `ipc` 모듈을 통해 메인 -프로세스와 inter-process 통신을 해야 합니다. 또한, `remote` 모듈을 사용하면 -inter-process 통신을 하지 않고도 간단한 API를 통해 직접 메인 프로세스의 모듈과 -메서드를 사용할 수 있습니다. 이 개념은 Java의 [RMI][rmi]와 비슷합니다. - -다음 예시는 렌더러 프로세스에서 브라우저 창을 만드는 예시입니다: - -```javascript -const {BrowserWindow} = require('electron').remote; - -let win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('https://github.com'); -``` - -**참고:** 반대로 메인 프로세스에서 렌더러 프로세스에 접근 하려면 [webContents.executeJavascript](web-contents.md#webcontentsexecutejavascriptcode-usergesture-callback) -메서드를 사용하면 됩니다. - -## Remote 객체 - -`remote` 모듈로부터 반환된 각 객체(메서드 포함)는 메인 프로세스의 객체를 추상화 한 -객체입니다. (우리는 그것을 remote 객체 또는 remote 함수라고 부릅니다) Remote 모듈의 -메서드를 호출하거나, 객체에 접근하거나, 생성자로 객체를 생성하는 등의 작업은 실질적으로 -동기형 inter-process 메시지를 보냅니다. - -위의 예시에서 사용한 두 `BrowserWindow`와 `win`은 remote 객체입니다. 그리고 -`new BrowserWindow`이 생성하는 `BrowserWindow` 객체는 렌더러 프로세스에서 생성되지 -않습니다. 대신에 이 `BrowserWindow` 객체는 메인 프로세스에서 생성되며 렌더러 -프로세스에 `win` 객체와 같이 이에 대응하는 remote 객체를 반환합니다. - -참고로 remote 객체가 처음 참조될 때 표시되는 -[enumerable 속성](https://developer.mozilla.org/ko/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)은 -remote를 통해서만 접근할 수 있습니다. - -## Remote 객체의 생명 주기 - -Electron은 렌더러 프로세스의 remote 객체가 살아있는 한(다시 말해서 GC(garbage -collection)가 일어나지 않습니다) 대응하는 메인 프로세스의 객체는 릴리즈되지 않습니다. -Remote 객체가 GC 되려면 대응하는 메인 프로세스 내부 객체의 참조가 해제되어야만 합니다. - -만약 remote 객체가 렌더러 프로세스에서 누수가 생겼다면 (예시: 맵에 저장하고 할당 -해제하지 않음) 대응하는 메인 프로세스의 객체도 누수가 생깁니다. 그래서 remote 객체를 -사용할 땐 메모리 누수가 생기지 않도록 매우 주의해서 사용해야 합니다. - -참고로 문자열, 숫자와 같은 원시 값 타입은 복사에 의한 참조로 전달됩니다. - -## 메인 프로세스로 콜백 넘기기 - -메인 프로세스의 코드는 `remote` 모듈을 통해 렌더러 프로세스가 전달하는 콜백 함수를 -받을 수 있습니다. 하지만 이 작업은 반드시 주의를 기울여 사용해야 합니다. - -첫째, 데드락을 피하기 위해 메인 프로세스로 전달된 콜백들은 비동기로 호출됩니다. 이러한 -이유로 메인 프로세스에 전달된 콜백의 반환 값을 내부 함수에서 언제나 정상적으로 받을 -것이라고 예측해선 안됩니다. - -예를 들어 메인 프로세스에서 `Array.map` 같은 메서드를 사용할 때 렌더러 프로세스에서 -전달된 함수를 사용해선 안됩니다: - -```javascript -// mapNumbers.js 메인 프로세스 -exports.withRendererCallback = (mapper) => { - return [1,2,3].map(mapper); -; - -exports.withLocalCallback = () => { - return [1,2,3].map(x => x + 1); -}; -``` - -```javascript -// 렌더러 프로세스 -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] -``` - -보다시피 동기적인 렌더러 콜백 함수의 반환 값은 예상되지 않은 값입니다. 그리고 메인 -프로세스에서 처리한 함수의 반환 값과 일치하지 않습니다. - -둘째, 콜백들은 메인 프로세스로 전달, 호출된 이후에도 자동으로 함수의 참조가 릴리즈 되지 -않습니다. 함수 참조는 메인 프로세스에서 GC가 일어나기 전까지 계속 프로세스에 남아있게 -됩니다. - -다음 코드를 보면 느낌이 올 것입니다. 이 예시는 remote 객체에 `close` 이벤트 콜백을 -등록합니다: - -```javascript -const remote = require('remote'); - -remote.getCurrentWindow().on('close', () => { - // blabla... -}); -``` - -하지만 이 코드와 같이 등록된 이벤트는 명시적으로 제거하지 않는 이상 콜백 함수의 참조가 -계속해서 메인 프로세스에 남아있게 됩니다. 만약 명시적으로 콜백을 제거하지 않으면 매 번 -창을 새로고침 할 때마다 콜백을 새로 설치합니다. 게다가 이전 콜백이 제거되지 않고 -계속해서 쌓이면서 메모리 누수가 발생합니다. - -설상가상으로 이전에 등록된 콜백의 컨텍스트가 릴리즈 되고 난 후 (e.g. 페이지 새로고침) -`close` 이벤트가 발생하면 예외가 발생하고 메인 프로세스가 작동 중지됩니다. - -이러한 문제를 피하려면 렌더러 프로세스에서 메인 프로세스로 넘긴 함수의 참조를 사용 후 -확실하게 제거해야 합니다. 작업 후 이벤트 콜백을 포함하여 책임 있게 함수의 참조를 -제거하거나 메인 프로세스에서 렌더러 프로세스가 종료될 때 내부적으로 함수 참조를 -제거하도록 설계해야 합니다. - -## 메인 프로세스의 빌트인 모듈에 접근 - -메인 프로세스의 빌트인 모듈은 `remote` 모듈에 getter로 등록되어 있습니다. 따라서 -`remote` 모듈을 `electron` 모듈처럼 직접 사용할 수 있습니다. - -```javascript -const app = remote.app; -``` - -## Methods - -`remote` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `remote.require(module)` - -* `module` String - -메인 프로세스의 `require(module)` API를 실행한 후 결과 객체를 반환합니다. - -### `remote.getCurrentWindow()` - -현재 웹 페이지가 들어있는 [`BrowserWindow`](browser-window.md) 객체를 반환합니다. - -### `remote.getCurrentWebContents()` - -현재 웹 페이지의 [`WebContents`](web-contents.md) 객체를 반환합니다. - -### `remote.getGlobal(name)` - -* `name` String - -메인 프로세스의 전역 변수(`name`)를 가져옵니다. (예시: `global[name]`) - -### `remote.process` - -메인 프로세스의 `process` 객체를 반환합니다. `remote.getGlobal('process')`와 -같습니다. 하지만 캐시 됩니다. - -[rmi]: http://en.wikipedia.org/wiki/Java_remote_method_invocation diff --git a/docs-translations/ko-KR/api/screen.md b/docs-translations/ko-KR/api/screen.md deleted file mode 100644 index ff59230453394..0000000000000 --- a/docs-translations/ko-KR/api/screen.md +++ /dev/null @@ -1,136 +0,0 @@ -# screen - -> 화면 크기, 디스플레이, 커서 위치 등의 정보를 가져옵니다. - -이 모듈은 `app` 모듈의 `ready` 이벤트가 발생하기 전까지 사용할 수 없습니다. (호출 또는 -모듈 포함) - -`screen`은 [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter)를 -상속 받았습니다. - -**참고:** 렌더러 / DevTools에선 이미 DOM 속성이 `window.screen`을 가지고 있으므로 -`screen = require('screen')` 형식으로 모듈을 사용할 수 없습니다. - -다음 예시는 화면 전체를 채우는 윈도우 창을 생성합니다: - - -```javascript -const electron = require('electron') -const {app, BrowserWindow} = electron - -let win - -app.on('ready', () => { - const {width, height} = electron.screen.getPrimaryDisplay().workAreaSize - win = new BrowserWindow({width, height}) -}); -``` - -다음 예시는 확장 디스플레이에 윈도우를 생성합니다: - -```javascript -const electron = require('electron') -const {app, BrowserWindow} = require('electron') - -let win - -app.on('ready', () => { - let displays = electron.screen.getAllDisplays() - let externalDisplay = displays.find((display) => { - return display.bounds.x !== 0 || display.bounds.y !== 0 - }) - - if (externalDisplay) { - win = new BrowserWindow({ - x: externalDisplay.bounds.x + 50, - y: externalDisplay.bounds.y + 50 - }) - } -}) -``` - -## `Display` 객체 - -`Display` 객체는 시스템에 연결된 물리적인 디스플레이를 표현합니다. 헤드레스(headless) -시스템에선 가짜 `Display` 객체가 보여지거나 리모트(remote), 가상 디스플레이에 -해당하게 됩니다. - -* `display` object - * `id` Integer - 디스플레이에 관련된 유일 식별자. - * `rotation` Integer - 값은 0, 90, 180, 270이 될 수 있고, 각 값은 시계 방향을 - 기준으로 0, 90, 180, 270도의 화면 회전 상태를 표현합니다. - * `scaleFactor` Number - 기기의 픽셀 스케일 크기. - * `touchSupport` String - 터치 스크린의 여부, `available`, `unavailable`, - `unknown` 값으로 반환됩니다. - * `bounds` Object - * `size` Object - * `workArea` Object - * `workAreaSize` Object - -## Events - -`screen` 모듈은 다음과 같은 이벤트를 가지고 있습니다: - -### Event: 'display-added' - -Returns: - -* `event` Event -* `newDisplay` Object - -새로운 디스플레이가 추가되면 발생하는 이벤트입니다. - -### Event: 'display-removed' - -Returns: - -* `event` Event -* `oldDisplay` Object - -기존의 디스플레이가 제거되면 발생하는 이벤트입니다. - -### Event: 'display-metrics-changed' - -Returns: - -* `event` Event -* `display` Object -* `changedMetrics` Array - -`display`에서 하나 또는 다수의 매트릭스가 변경될 때 발생하는 이벤트입니다. -`changedMetrics`는 변경에 대한 정보를 담은 문자열의 배열입니다. -`bounds`, `workArea`, `scaleFactor`, `rotation`등이 변경될 수 있습니다. - -## Methods - -`screen` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `screen.getCursorScreenPoint()` - -현재 마우스 포인터의 절대 위치를 반환합니다. - -### `screen.getPrimaryDisplay()` - -기본 디스플레이를 반환합니다. - -### `screen.getAllDisplays()` - -사용 가능한 모든 디스플레이를 배열로 반환합니다. - -### `screen.getDisplayNearestPoint(point)` - -* `point` Object - * `x` Integer - * `y` Integer - -지정한 좌표에 가까운 디스플레이를 반환합니다. - -### `screen.getDisplayMatching(rect)` - -* `rect` Object - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -지정한 범위에 가장 가깝게 교차한 디스플레이를 반환합니다. diff --git a/docs-translations/ko-KR/api/session.md b/docs-translations/ko-KR/api/session.md deleted file mode 100644 index 626ca240db071..0000000000000 --- a/docs-translations/ko-KR/api/session.md +++ /dev/null @@ -1,603 +0,0 @@ -# session - -> 브라우저 세션, 쿠키, 캐시, 프록시 설정 등을 관리합니다. - -`session` 모듈은 새로운 `Session` 객체를 만드는데 사용할 수 있습니다. - -또한 [`WebContents`](web-contents.md)의 `session` 속성이나 `session` 모듈을 통해 현재 존재하는 페이지의 `session`에 접근할 수 있습니다. - -```javascript -const {session, BrowserWindow} = require('electron') - -let win = new BrowserWindow({width: 800, height: 600}) -win.loadURL('http://github.com') - -let ses = win.webContents.session -``` - -## Methods - -`session` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### session.fromPartition(partition) - -* `partition` String - -`partition` 문자열로 부터 새로운 `Session` 인스턴스를 만들어 반환합니다. - -`partition`이 `persist:`로 시작하면 페이지는 지속성 세션을 사용하며 다른 모든 앱 내의 -페이지에서 같은 `partition`을 사용할 수 있습니다. 만약 `persist:` 접두어로 시작하지 -않으면 페이지는 인-메모리 세션을 사용합니다. `partition`을 지정하지 않으면 애플리케이션의 -기본 세션이 반환됩니다. - -## Properties - -`session` 모듈은 다음과 같은 속성을 가지고 있습니다: - -### session.defaultSession - -애플리케이션의 기본 세션 객체를 반환합니다. - -## Class: Session - -`session` 모듈을 사용하여 `Session` 객체를 생성할 수 있습니다: - -```javascript -const session = require('electron').session; - -const ses = session.fromPartition('persist:name'); - ``` - -### Instance Events - -`Session` 객체는 다음과 같은 이벤트를 가지고 있습니다: - -#### Event: 'will-download' - -* `event` Event -* `item` [DownloadItem](download-item.md) -* `webContents` [WebContents](web-contents.md) - -Electron의 `webContents`에서 `item`을 다운로드할 때 발생하는 이벤트입니다. - -`event.preventDefault()` 메서드를 호출하면 다운로드를 취소하고, 프로세스의 다음 -틱부터 `item`을 사용할 수 없게 됩니다. - -```javascript -session.defaultSession.on('will-download', (event, item, webContents) => { - event.preventDefault(); - require('request')(item.getURL(), (data) => { - require('fs').writeFileSync('/somewhere', data); - }); -}); -``` - -### Instance Methods - -`Session` 객체는 다음과 같은 메서드를 가지고 있습니다: - -#### `ses.getCacheSize(callback)` - -* `callback` Function - * `size` Integer - 바이트로 표현된 캐시 크기 - -세션의 현재 캐시 크기를 반환합니다. - -#### `ses.clearCache(callback)` - -* `callback` Function - 작업이 완료되면 호출됩니다. - -세션의 HTTP 캐시를 비웁니다. - -#### `ses.clearStorageData([options, ]callback)` - -* `options` Object (optional), proprties: - * `origin` String - `scheme://host:port`와 같은 `window.location.origin` 규칙을 - 따르는 origin 문자열. - * `storages` Array - 비우려는 스토리지의 종류, 다음과 같은 타입을 포함할 수 있습니다: - `appcache`, `cookies`, `filesystem`, `indexdb`, `local storage`, - `shadercache`, `websql`, `serviceworkers` - * `quotas` Array - 비우려는 할당의 종류, 다음과 같은 타입을 포함할 수 있습니다: - `temporary`, `persistent`, `syncable`. -* `callback` Function - 작업이 완료되면 호출됩니다. - -웹 스토리지의 데이터를 비웁니다. - -#### `ses.flushStorageData()` - -디스크에 사용되지 않은 DOMStorage 데이터를 모두 덮어씌웁니다. - -#### `ses.setProxy(config, callback)` - -* `config` Object - * `pacScript` String - PAC 파일과 관련된 URL입니다. - * `proxyRules` String - 사용할 프록시의 규칙을 나타냅니다. -* `callback` Function - 작업이 완료되면 호출됩니다. - -프록시 설정을 적용합니다. - -`pacScript`와 `proxyRules`이 같이 제공되면 `proxyRules` 옵션은 무시되며 `pacScript` -컨픽만 적용됩니다. - -`proxyRules`는 다음과 같은 규칙을 따릅니다: - -``` -proxyRules = schemeProxies[";"] -schemeProxies = ["="] -urlScheme = "http" | "https" | "ftp" | "socks" -proxyURIList = [","] -proxyURL = ["://"][":"] -``` - -예시: - -* `http=foopy:80;ftp=foopy2` - http:// URL에 `foopy:80` HTTP 프록시를 사용합니다. - `foopy2:80` 는 ftp:// URL에 사용됩니다. -* `foopy:80` - 모든 URL에 `foopy:80` 프록시를 사용합니다. -* `foopy:80,bar,direct://` - 모든 URL에 `foopy:80` HTTP 프록시를 사용합니다. - 문제가 발생하여 `foopy:80`를 사용할 수 없는 경우 `bar`를 대신 사용하여 장애를 - 복구하며 그 다음 문제가 생긴 경우 프록시를 사용하지 않습니다. -* `socks4://foopy` - 모든 URL에 `foopy:1000` SOCKS v4 프록시를 사용합니다. -* `http=foopy,socks5://bar.com` - http:// URL에 `foopy` HTTP 프록시를 사용합니다. - 문제가 발생하여 `foopy`를 사용할 수 없는 경우 SOCKS5 `bar.com` 프록시를 대신 - 사용합니다. -* `http=foopy,direct://` - http:// URL에 `foopy` HTTP 프록시를 사용합니다. 그리고 - 문제가 발생하여 `foopy`를 사용할 수 없는 경우 프록시를 사용하지 않습니다. -* `http=foopy;socks=foopy2` - http:// URL에 `foopy` HTTP 프록시를 사용합니다. - 그리고 `socks4://foopy2` 프록시를 다른 모든 URL에 사용합니다. - -#### `ses.resolveProxy(url, callback)` - -* `url` URL -* `callback` Function - -`url`의 프록시 정보를 해석합니다. `callback`은 요청이 수행되었을 때 -`callback(proxy)` 형태로 호출됩니다. - -#### `ses.setDownloadPath(path)` - -* `path` String - 다운로드 위치 - -다운로드 저장 위치를 지정합니다. 기본 다운로드 위치는 각 애플리케이션 데이터 디렉터리의 -`Downloads` 폴더입니다. - -#### `ses.enableNetworkEmulation(options)` - -* `options` Object - * `offline` Boolean - 네트워크의 오프라인 상태 여부 - * `latency` Double - 밀리세컨드 단위의 RTT - * `downloadThroughput` Double - Bps 단위의 다운로드 주기 - * `uploadThroughput` Double - Bps 단위의 업로드 주기 - -제공된 설정으로 `session`의 네트워크를 에뮬레이트합니다. - -```javascript -// 50kbps의 처리량과 함께 500ms의 레이턴시로 GPRS 연결을 에뮬레이트합니다. -window.webContents.session.enableNetworkEmulation({ - latency: 500, - downloadThroughput: 6400, - uploadThroughput: 6400 -}); - -// 네트워크가 끊긴 상태를 에뮬레이트합니다. -window.webContents.session.enableNetworkEmulation({offline: true}); -``` - -#### `ses.disableNetworkEmulation()` - -활성화된 `session`의 에뮬레이션을 비활성화합니다. 기본 네트워크 설정으로 돌아갑니다. - -#### `ses.setCertificateVerifyProc(proc)` - - * `proc` Function - -`session`에 인증서의 유효성을 확인하는 프로세스(proc)를 등록합니다. `proc`은 서버 -인증서 유효성 검증 요청이 들어왔을 때 언제나 `proc(hostname, certificate, callback)` -형식으로 호출됩니다. `callback(true)`을 호출하면 인증을 승인하고 `callback(false)`를 -호출하면 인증을 거부합니다. - -`setCertificateVerifyProc(null)`을 호출하면 기본 검증 프로세스로 되돌립니다. - -```javascript -myWindow.webContents.session.setCertificateVerifyProc((hostname, cert, callback) => { - if (hostname === 'github.com') - callback(true); - else - callback(false); -}); -``` -#### `ses.setPermissionRequestHandler(handler)` - -* `handler` Function - * `webContents` Object - [WebContents](web-contents.md) 권한을 요청. - * `permission` String - 'media', 'geolocation', 'notifications', - 'midiSysex', 'pointerLock', 'fullscreen', 'openExternal'의 나열. - * `callback` Function - 권한 허용 및 거부. - -`session`의 권한 요청에 응답을 하는데 사용하는 핸들러를 설정합니다. -`callback(true)`를 호출하면 권한 제공을 허용하고 `callback(false)`를 -호출하면 권한 제공을 거부합니다. - -```javascript -session.fromPartition(partition).setPermissionRequestHandler((webContents, permission, callback) => { - if (webContents.getURL() === host) { - if (permission === 'notifications') { - callback(false); // 거부됨. - return; - } - } - - callback(true); -}); -``` - -#### `ses.clearHostResolverCache([callback])` - -* `callback` Function (optional) - 작업이 완료되면 호출됩니다. - -호스트 리소버(resolver) 캐시를 지웁니다. - -#### `ses.allowNTLMCredentialsForDomains(domains)` - -* `domains` String - 통합 인증을 사용하도록 설정할 쉼표로 구분된 서버의 리스트. - -동적으로 HTTP NTML 또는 Negotiate 인증을 위해 언제나 자격 증명을 보낼지 여부를 -설정합니다. - -```javascript -// 통합 인증을 위해 `example.com`, `foobar.com`, `baz`로 끝나는 -// 모든 url을 지정합니다. -session.defaultSession.allowNTLMCredentialsForDomains('*example.com, *foobar.com, *baz') - -// 통합 인증을 위해 모든 url을 지정합니다. -session.defaultSession.allowNTLMCredentialsForDomains('*') -``` - -#### `ses.setUserAgent(userAgent[, acceptLanguages])` - -* `userAgent` String -* `acceptLanguages` String (optional) - -현재 세션에 대해 `userAgent`와 `acceptLanguages`를 덮어씁니다. - -`acceptLanguages`는 반드시 쉼표로 구분된 순서에 맞춘 언어 코드의 리스트여야 하며 -예를 들면 `"en-US,fr,de,ko,zh-CN,ja"` 입니다. - -이는 현재 존재하는 `WebContents`에 적용되지 않으며 각 `WebContents`는 -`webContents.setUserAgent`를 사용하여 세션 전체의 유저 에이전트를 덮어쓸 수 있습니다. - -#### `ses.getUserAgent()` - -현재 세션의 유저 에이전트를 표현하는 `String`을 반환합니다. - -### Instance Properties - -다음은 `Session` 인스턴스에서 사용할 수 있는 속성들입니다: - -#### `ses.cookies` - -현재 세션의 `Cookies` 클래스 인스턴스를 반환합니다. - -#### `ses.webRequest` - -현재 세션의 `WebRequest` 클래스 인스턴스를 반환합니다. - -#### `ses.protocol` - -현재 세션의 [protocol](protocol.md) 모듈 인스턴스를 반환합니다. - -```javascript -const {app, session} = require('electron') -const path = require('path') - -app.on('ready', function () { - const protocol = session.fromPartition(partitionName).protocol - protocol.registerFileProtocol('atom', function (request, callback) { - var url = request.url.substr(7) - callback({path: path.normalize(__dirname + '/' + url)}) - }, function (error) { - if (error) - console.error('Failed to register protocol') - }) -}) -``` - -## Class: Cookies - -`Cookies` 클래스는 쿠키를 탐색하고 조작하는 방법을 제공합니다. `Cookies` 클래스의 -인스턴스는 반드시 `Session` 클래스의 `cookies` 속성에서 접근해야 합니다. - -예를 들어: - -```javascript -// 모든 쿠키를 요청합니다. -session.defaultSession.cookies.get({}, (error, cookies) => { - console.log(cookies); -}); - -// url에 관련된 쿠키를 모두 가져옵니다. -session.defaultSession.cookies.get({url: 'http://www.github.com'}, (error, cookies) => { - console.log(cookies); -}); - -// 지정한 쿠키 데이터를 설정합니다. -// 동일한 쿠키가 있으면 해당 쿠키를 덮어씁니다. -const cookie = {url: 'http://www.github.com', name: 'dummy_name', value: 'dummy'}; -session.defaultSession.cookies.set(cookie, (error) => { - if (error) - console.error(error); -}); -``` - -### Instance Methods - -다음은 `Cookies` 객체에서 사용할 수 있는 메서드들입니다: - -#### `ses.cookies.get(filter, callback)` - -* `filter` Object - * `url` String (optional) - `url`에 해당하는 쿠키를 취득합니다. 이 속성을 - 생략하면 모든 url에서 찾습니다. - * `name` String (optional) - 쿠키의 이름입니다. - * `domain` String (optional) - 도메인 또는 서브 도메인에 일치하는 쿠키를 - 취득합니다. - * `path` String (optional) - `path`에 일치하는 쿠키를 취득합니다. - * `secure` Boolean (optional) - 보안 속성에 따라 쿠키를 필터링합니다. - * `session` Boolean (optional) - 세션 또는 지속성 쿠키를 필터링합니다. -* `callback` Function - -`details` 객체에서 묘사한 모든 쿠키를 요청합니다. 모든 작업이 끝나면 `callback`이 -`callback(error, cookies)` 형태로 호출됩니다. - -`cookies`는 `cookie` 객체의 배열입니다. - -* `cookie` Object - * `name` String - 쿠키의 이름. - * `value` String - 쿠키의 값. - * `domain` String - 쿠키의 도메인. - * `hostOnly` String - 쿠키가 호스트 전용인가에 대한 여부. - * `path` String - 쿠키의 경로. - * `secure` Boolean - 쿠키가 안전한 것으로 표시되는지에 대한 여부. - * `httpOnly` Boolean - 쿠키가 HTTP로만 표시되는지에 대한 여부. - * `session` Boolean - 쿠키가 세션 쿠키 또는 만료일이 있는 영구 쿠키인지에 대한 - 여부. - * `expirationDate` Double - (Option) UNIX 시간으로 표시되는 쿠키의 만료일에 - 대한 초 단위 시간. 세션 쿠키는 지원되지 않음. - -#### `ses.cookies.set(details, callback)` - -* `details` Object - * `url` String - 쿠키에 대한 `url` 링크. - * `name` String - 쿠키의 이름입니다. 기본적으로 비워두면 생략됩니다. - * `value` String - 쿠키의 값입니다. 기본적으로 비워두면 생략됩니다. - * `domain` String - 쿠키의 도메인입니다. 기본적으로 비워두면 생략됩니다. - * `path` String - 쿠키의 경로입니다. 기본적으로 비워두면 생략됩니다. - * `secure` Boolean - 쿠키가 안전한 것으로 표시되는지에 대한 여부입니다. 기본값은 - false입니다. - * `httpOnly` Boolean - 쿠키가 Http 전용으로 표시되는지에 대한 여부입니다. 기본값은 - false입니다. - * `expirationDate` Double (optional) - UNIX 시간으로 표시되는 쿠키의 만료일에 - 대한 초 단위 시간입니다. 생략되면 쿠키가 세션 쿠기가 되며 세션 사이에 유지되지 - 않게 됩니다. -* `callback` Function - -`details` 객체에 따라 쿠키를 설정합니다. 작업이 완료되면 `callback`이 -`callback(error)` 형태로 호출됩니다. - -#### `ses.cookies.remove(url, name, callback)` - -* `url` String - 쿠키와 관련된 URL입니다. -* `name` String - 지울 쿠키의 이름입니다. -* `callback` Function - -`url`과 `name`에 일치하는 쿠키를 삭제합니다. 작업이 완료되면 `callback`이 -`callback()` 형식으로 호출됩니다. - -## Class: WebRequest - -`WebRequest` 클래스는 생명 주기의 다양한 단계에서 요청의 콘텐츠를 조작하거나 가로채는 -방법을 제공합니다. `WebRequest` 클래스는 반드시 `Session` 클래스의 `webRequest` -속성에서 접근해야 합니다. - -`WebRequest`의 메서드는 선택적인 `filter`와 `listener` 속성을 허용하며 `listener`는 -API의 이벤트가 발생했을 때 `listener(details)` 형식으로 호출되고, `details`는 요청에 -관한 내용을 표현하는 객체입니다. `listener`에 `null`을 전달하면 이벤트의 구독을 -해제합니다. - -`filter`는 `urls` 속성을 가진 객체입니다. 이 속성은 URL 규칙의 배열이며 URL 규칙에 -일치하지 않는 요청을 모두 거르는데 사용됩니다. 만약 `filter`가 생략되면 모든 요청을 -여과 없이 통과시킵니다. - -어떤 `listener`의 이벤트들은 `callback`을 같이 전달하는데, 이벤트 처리시 -`listener`의 작업을 완료한 후 `response` 객체를 포함하여 호출해야 합니다. - -다음은 요청에 `User-Agent` 헤더를 추가하는 예시입니다: - -```javascript -// 다음 url에 대한 User Agent를 조작합니다. -const filter = { - urls: ['https://*.github.com/*', '*://electron.github.io'] -} - -session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => { - details.requestHeaders['User-Agent'] = "MyAgent" - callback({cancel: false, requestHeaders: details.requestHeaders}) -}) -``` - -### Instance Methods - -다음은 `WebRequest` 객체에서 사용할 수 있는 메서드들입니다: - -#### `webRequest.onBeforeRequest([filter, ]listener)` - -* `filter` Object -* `listener` Function - -요청이 발생하면 `listener`가 `listener(details, callback)` 형태로 호출됩니다. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `uploadData` Array (optional) -* `callback` Function - -`uploadData`는 `data` 객체의 배열입니다: - -* `data` Object - * `bytes` Buffer - 전송될 콘텐츠. - * `file` String - 업로드될 파일의 경로. - -`callback`은 `response` 객체와 함께 호출되어야 합니다: - -* `response` Object - * `cancel` Boolean (optional) - * `redirectURL` String (optional) - 원래 요청은 전송과 완료가 방지되지만 이 - 속성을 지정하면 해당 URL로 리다이렉트됩니다. - -#### `webRequest.onBeforeSendHeaders([filter, ]listener)` - -* `filter` Object -* `listener` Function - -HTTP 요청을 보내기 전 요청 헤더를 사용할 수 있을 때 `listener`가 -`listener(details, callback)` 형태로 호출됩니다. 이 이벤트는 서버와의 TCP 연결이 -완료된 후에 발생할 수도 있지만 http 데이터가 전송되기 전에 발생합니다. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `requestHeaders` Object -* `callback` Function - -`callback`은 `response` 객체와 함께 호출되어야 합니다: - -* `response` Object - * `cancel` Boolean (optional) - * `requestHeaders` Object (optional) - 이 속성이 제공되면, 요청은 이 헤더로 - 만들어 집니다. - -#### `webRequest.onSendHeaders([filter, ]listener)` - -* `filter` Object -* `listener` Function - -서버에 요청이 전송되기 바로 전에 `listener`가 `listener(details)` 형태로 호출됩니다. -이전 `onBeforeSendHeaders`의 response와 다른점은 리스너가 호출되는 시간으로 볼 수 -있습니다. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `requestHeaders` Object - -#### `webRequest.onHeadersReceived([filter, ]listener)` - -* `filter` Object -* `listener` Function - -요청의 HTTP 응답 헤더를 받았을 때 `listener`가 `listener(details, callback)` 형태로 -호출됩니다. - -* `details` Object - * `id` String - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `statusLine` String - * `statusCode` Integer - * `responseHeaders` Object -* `callback` Function - -`callback`은 `response` 객체와 함께 호출되어야 합니다: - -* `response` Object - * `cancel` Boolean - * `responseHeaders` Object (optional) - 이 속성이 제공되면 서버는 이 헤더와 - 함께 응답합니다. - * `statusLine` String (optional) - `responseHeaders`를 덮어쓸 땐, 헤더의 상태를 - 변경하기 위해 반드시 지정되어야 합니다. 그렇지 않은 경우, 기존의 응답 헤더의 상태가 - 사용됩니다. - -#### `webRequest.onResponseStarted([filter, ]listener)` - -* `filter` Object -* `listener` Function - -요청 본문의 첫 번째 바이트를 받았을 때 `listener`가 `listener(details)` 형태로 -호출됩니다. 이는 HTTP 요청에서 상태 줄과 요청 헤더가 사용 가능한 상태를 의미합니다. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `responseHeaders` Object - * `fromCache` Boolean - 응답을 디스크 캐시에서 가져올지에 대한 여부. - * `statusCode` Integer - * `statusLine` String - -#### `webRequest.onBeforeRedirect([filter, ]listener)` - -* `filter` Object -* `listener` Function - -서버에서 시작된 리다이렉트가 발생했을 때 `listener`가 `listener(details)` 형태로 -호출됩니다. - -* `details` Object - * `id` String - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `redirectURL` String - * `statusCode` Integer - * `ip` String (optional) - 요청이 실질적으로 전송될 서버 아이피 주소. - * `fromCache` Boolean - * `responseHeaders` Object - -#### `webRequest.onCompleted([filter, ]listener)` - -* `filter` Object -* `listener` Function - -요청이 완료되면 `listener`가 `listener(details)` 형태로 호출됩니다. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `responseHeaders` Object - * `fromCache` Boolean - * `statusCode` Integer - * `statusLine` String - -#### `webRequest.onErrorOccurred([filter, ]listener)` - -* `filter` Object -* `listener` Function - -에러가 발생하면 `listener`가 `listener(details)` 형태로 호출됩니다. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `fromCache` Boolean - * `error` String - 에러 설명. diff --git a/docs-translations/ko-KR/api/shell.md b/docs-translations/ko-KR/api/shell.md deleted file mode 100644 index 2079fa0829e0b..0000000000000 --- a/docs-translations/ko-KR/api/shell.md +++ /dev/null @@ -1,52 +0,0 @@ -# shell - -> 파일과 URL을 각 기본 애플리케이션을 통해 관리합니다. - -`shell` 모듈은 데스크톱 환경 통합에 관련한 유틸리티를 제공하는 모듈입니다. - -다음 예시는 설정된 URL을 유저의 기본 브라우저로 엽니다: - -```javascript -const {shell} = require('electron'); - -shell.openExternal('https://github.com'); -``` - -## Methods - -`shell` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `shell.showItemInFolder(fullPath)` - -* `fullPath` String - -지정한 파일을 탐색기에서 보여줍니다. 가능한 경우 탐색기 내에서 파일을 선택합니다. - -### `shell.openItem(fullPath)` - -* `fullPath` String - -지정한 파일을 데스크톱 기본 프로그램으로 엽니다. - -### `shell.openExternal(url[, options])` - -* `url` String -* `options` Object (optional) _macOS_ - * `activate` Boolean - `true`로 설정하면 애플리케이션을 바로 활성화 상태로 - 실행합니다. 기본값은 `true`입니다. - -제공된 외부 프로토콜 URL을 기반으로 데스크톱의 기본 프로그램으로 엽니다. (예를 들어 -mailto: URL은 유저의 기본 이메일 에이전트로 URL을 엽니다.) 애플리케이션이 해당 URL을 -열 수 있을 때 `true`를 반환합니다. 아니라면 `false`를 반환합니다. - -**역자주:** 탐색기로 폴더만 표시하려면 `'file://경로'`와 같이 지정하여 열 수 있습니다. - -### `shell.moveItemToTrash(fullPath)` - -* `fullPath` String - -지정한 파일을 휴지통으로 이동합니다. 작업의 성공여부를 boolean 형으로 리턴합니다. - -### `shell.beep()` - -비프음을 재생합니다. diff --git a/docs-translations/ko-KR/api/synopsis.md b/docs-translations/ko-KR/api/synopsis.md deleted file mode 100644 index 4b38c7a2f5b20..0000000000000 --- a/docs-translations/ko-KR/api/synopsis.md +++ /dev/null @@ -1,75 +0,0 @@ -# 개요 - -> Node.js와 Electron API를 사용하는 방법. - -Electron은 모든 [Node.js의 built-in 모듈](http://nodejs.org/api/)과 third-party -node 모듈을 완벽하게 지원합니다. ([네이티브 모듈](../tutorial/using-native-node-modules.md) -포함) - -또한 Electron은 네이티브 데스크톱 애플리케이션을 개발 할 수 있도록 추가적인 built-in -모듈을 제공합니다. 몇몇 모듈은 메인 프로세스에서만 사용할 수 있고 어떤 모듈은 렌더러 -프로세스(웹 페이지)에서만 사용할 수 있습니다. 또한 두 프로세스 모두 사용할 수 있는 -모듈도 있습니다. - -기본적인 규칙으로 [GUI][gui]와 저 수준 시스템에 관련된 모듈들은 오직 메인 -프로세스에서만 사용할 수 있습니다. [메인 프로세스 vs. 렌더러 프로세스](../tutorial/quick-start.md#메인-프로세스) -컨셉에 익숙해야 모듈을 다루기 쉬우므로 관련 문서를 읽어 보는 것을 권장합니다. - -메인 프로세스 스크립트는 일반 Node.js 스크립트와 비슷합니다: - -```javascript -const {app, BrowserWindow} = require('electron'); - -let win = null; - -app.on('ready', () => { - win = new BrowserWindow({width: 800, height: 600}); - win.loadURL('https://github.com'); -}); -``` - -렌더러 프로세스도 예외적인 node module들을 사용할 수 있다는 점을 제외하면 일반 웹 -페이지와 크게 다를게 없습니다: - -```html - - - - - - -``` - -애플리케이션을 실행하려면 [앱 실행하기](../tutorial/quick-start.md#앱 실행하기) -문서를 참고하기 바랍니다. - -## 분리 할당 - -0.37 버전부터, [분리 할당][destructuring-assignment]을 통해 빌트인 모듈을 더 -직관적으로 사용할 수 있습니다: - -```javascript -const {app, BrowserWindow} = require('electron'); -``` - -모든 `electron` 모듈이 필요하다면, 먼저 require한 후 각 독립적인 모듈을 -`electron`에서 분리 할당함으로써 모듈을 사용할 수 있습니다. - -```javascript -const electron = require('electron'); -const {app, BrowserWindow} = electron; - ``` - -위 코드는 다음과 같습니다: - -```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; -``` - -[gui]: https://en.wikipedia.org/wiki/Graphical_user_interface -[destructuring-assignment]: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment diff --git a/docs-translations/ko-KR/api/system-preferences.md b/docs-translations/ko-KR/api/system-preferences.md deleted file mode 100644 index d8170b73cf3e5..0000000000000 --- a/docs-translations/ko-KR/api/system-preferences.md +++ /dev/null @@ -1,101 +0,0 @@ -# systemPreferences - -> 시스템 설정을 가져옵니다. - -```javascript -const {systemPreferences} = require('electron'); -console.log(systemPreferences.isDarkMode()); -``` - -## Methods - -### `systemPreferences.isDarkMode()` _macOS_ - -이 메서드는 시스템이 어두운 모드 상태인 경우 `true`를 반환하고 아닐 경우 `false`를 -반환합니다. - -### `systemPreferences.subscribeNotification(event, callback)` _macOS_ - -* `event` String -* `callback` Function - -macOS의 네이티브 알림을 구독하며, 해당하는 `event`가 발생하면 `callback`이 -`callback(event, userInfo)` 형태로 호출됩니다. `userInfo`는 알림과 함께 전송되는 -사용자 정보 딕셔너리를 포함하는 객체입니다. - -구독자의 `id`가 반환되며 `event`를 구독 해제할 때 사용할 수 있습니다. - -이 API는 후드에서 `NSDistributedNotificationCenter`를 구독하며, `event`의 예시 -값은 다음과 같습니다: - -* `AppleInterfaceThemeChangedNotification` -* `AppleAquaColorVariantChanged` -* `AppleColorPreferencesChangedNotification` -* `AppleShowScrollBarsSettingChanged` - -### `systemPreferences.unsubscribeNotification(id)` _macOS_ - -* `id` Integer - -`id`와 함께 구독자를 제거합니다. - -### `systemPreferences.subscribeLocalNotification(event, callback)` _macOS_ - -`subscribeNotification`와 같지만, 로컬 기본값으로 `NSNotificationCenter`를 -사용합니다. 다음과 같은 이벤트에 필수적입니다: - -* `NSUserDefaultsDidChangeNotification` - -### `systemPreferences.unsubscribeLocalNotification(id)` _macOS_ - -`unsubscribeNotification`와 같지만, `NSNotificationCenter`에서 구독자를 제거합니다. - -### `systemPreferences.getUserDefault(key, type)` _macOS_ - -* `key` String -* `type` String - `string`, `boolean`, `integer`, `float`, `double`, `url`, - `array`, `dictionary` 값이 될 수 있습니다. - -시스템 설정에서 `key`에 해당하는 값을 가져옵니다. - -macOS에선 API가 `NSUserDefaults`를 읽어들입니다. 유명한 `key`와 `type`은 다음과 -같습니다: - -* `AppleInterfaceStyle: string` -* `AppleAquaColorVariant: integer` -* `AppleHighlightColor: string` -* `AppleShowScrollBars: string` -* `NSNavRecentPlaces: array` -* `NSPreferredWebServices: dictionary` -* `NSUserDictionaryReplacementItems: array` - -### `systemPreferences.isAeroGlassEnabled()` _Windows_ - -이 메서드는 [DWM 컴포지션][dwm-composition] (Aero Glass)가 활성화 되어있을 때 -`true`를 반환합니다. 아닌 경우 `false`를 반환합니다. - -다음은 투명한 윈도우를 만들지, 일반 윈도우를 만들지를 판단하여 윈도우를 생성하는 -예시입니다 (투명한 윈도우는 DWM 컴포지션이 비활성화되어있을 시 작동하지 않습니다): - -```javascript -let browserOptions = {width: 1000, height: 800}; - -// 플랫폼이 지원하는 경우에만 투명 윈도우를 생성. -if (process.platform !== 'win32' || systemPreferences.isAeroGlassEnabled()) { - browserOptions.transparent = true; - browserOptions.frame = false; -} - -// 원도우 생성 -let win = new BrowserWindow(browserOptions); - -// 페이지 로드. -if (browserOptions.transparent) { - win.loadURL('file://' + __dirname + '/index.html'); -} else { - // 투명 윈도우 상태가 아니라면, 기본적인 스타일 사용 - win.loadURL('file://' + __dirname + '/fallback.html'); -} -``` - -[dwm-composition]:https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx diff --git a/docs-translations/ko-KR/api/tray.md b/docs-translations/ko-KR/api/tray.md deleted file mode 100644 index 46f790cd76514..0000000000000 --- a/docs-translations/ko-KR/api/tray.md +++ /dev/null @@ -1,213 +0,0 @@ -# Tray - -> 아이콘과 컨텍스트 메뉴를 시스템 알림 영역에 추가합니다. - -```javascript -const {app, Menu, Tray} = require('electron') - -let tray = null -app.on('ready', () => { - tray = new Tray('/path/to/my/icon') // 현재 애플리케이션 디렉터리를 기준으로 하려면 `__dirname + '/images/tray.png'` 형식으로 입력해야 합니다. - const contextMenu = Menu.buildFromTemplate([ - {label: 'Item1', type: 'radio'}, - {label: 'Item2', type: 'radio'}, - {label: 'Item3', type: 'radio', checked: true}, - {label: 'Item4', type: 'radio'} - ]); - tray.setToolTip('이것은 나의 애플리케이션 입니다!') - tray.setContextMenu(contextMenu) -}) -``` - -__플랫폼별 한계:__ - -* Linux에서는 앱 알림 표시기(app indicator)가 지원되면 해당 기능을 사용합니다. 만약 - 지원하지 않으면 `GtkStatusIcon`을 대신 사용합니다. -* Linux 배포판이 앱 알림 표시기만 지원하고 있다면 `libappindicator1`를 설치하여 - 트레이 아이콘이 작동하도록 만들 수 있습니다. -* 앱 알림 표시기는 컨텍스트 메뉴를 가지고 있을 때만 보입니다. -* Linux에서 앱 표시기가 사용될 경우, `click` 이벤트는 무시됩니다. -* Windows에선 가장 좋은 시각적 효과를 얻기 위해 `ICO` 아이콘을 사용하는 것을 - 권장합니다. -* Linux에서 각각 개별 `MenuItem`의 변경을 적용하려면 `setContextMenu`를 다시 - 호출해야 합니다. 예를 들면: - -```javascript -contextMenu.items[2].checked = false -appIcon.setContextMenu(contextMenu) -``` - -이러한 이유로 Tray API가 모든 플랫폼에서 똑같이 작동하게 하고 싶다면 `click` 이벤트에 -의존해선 안되며 언제나 컨텍스트 메뉴를 포함해야 합니다. - -## Class: Tray - -`Tray`는 [EventEmitter][event-emitter]를 상속 받았습니다. - -### `new Tray(image)` - -* `image` [NativeImage](native-image.md) - -전달된 `image`를 이용하여 트레이 아이콘을 만듭니다. - -### Instance Events - -`Tray` 모듈은 다음과 같은 이벤트를 가지고 있습니다: - -#### Event: 'click' - -* `event` Event - * `altKey` Boolean - * `shiftKey` Boolean - * `ctrlKey` Boolean - * `metaKey` Boolean -* `bounds` Object _macOS_ _Windows_ - 트레이 아이콘의 범위 - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -트레이 아이콘이 클릭될 때 발생하는 이벤트입니다. - -#### Event: 'right-click' _macOS_ _Windows_ - -* `event` Event - * `altKey` Boolean - * `shiftKey` Boolean - * `ctrlKey` Boolean - * `metaKey` Boolean -* `bounds` Object - 트레이 아이콘의 범위 - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -트레이 아이콘을 오른쪽 클릭될 때 호출 됩니다. - -#### Event: 'double-click' _macOS_ _Windows_ - -* `event` Event - * `altKey` Boolean - * `shiftKey` Boolean - * `ctrlKey` Boolean - * `metaKey` Boolean -* `bounds` Object - 트레이 아이콘의 범위 - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -트레이 아이콘이 더블 클릭될 때 발생하는 이벤트입니다. - -#### Event: 'balloon-show' _Windows_ - -풍선 팝업이 보여질 때 발생하는 이벤트입니다. - -#### Event: 'balloon-click' _Windows_ - -풍선 팝업이 클릭될 때 발생하는 이벤트입니다. - -#### Event: 'balloon-closed' _Windows_ - -풍선 팝업이 시간이 지나 사라지거나 유저가 클릭하여 닫을 때 발생하는 이벤트입니다. - -#### Event: 'drop' _macOS_ - -드래그 가능한 아이템이 트레이 아이콘에 드롭되면 발생하는 이벤트입니다. - -#### Event: 'drop-files' _macOS_ - -* `event` Event -* `files` Array - 드롭된 파일의 경로 - -트레이 아이콘에 파일이 드롭되면 발생하는 이벤트입니다. - -#### Event: 'drag-enter' _macOS_ - -트레이 아이콘에 드래그 작업이 시작될 때 발생하는 이벤트입니다. - -#### Event: 'drag-leave' _macOS_ - -트레이 아이콘에 드래그 작업이 종료될 때 발생하는 이벤트입니다. - -#### Event: 'drag-end' _macOS_ - -트레이 아이콘에 드래그 작업이 종료되거나 다른 위치에서 종료될 때 발생하는 이벤트입니다. - -### Instance Methods - -`Tray` 클래스는 다음과 같은 메서드를 가지고 있습니다: - -#### `tray.destroy()` - -트레이 아이콘을 즉시 삭제시킵니다. - -#### `tray.setImage(image)` - -* `image` [NativeImage](native-image.md) - -`image`를 사용하여 트레이 아이콘의 이미지를 설정합니다. - -#### `tray.setPressedImage(image)` _macOS_ - -* `image` [NativeImage](native-image.md) - -`image`를 사용하여 트레이 아이콘이 눌렸을 때의 이미지를 설정합니다. - -#### `tray.setToolTip(toolTip)` - -* `toolTip` String - -트레이 아이콘의 툴팁 텍스트를 설정합니다. - -#### `tray.setTitle(title)` _macOS_ - -* `title` String - -상태바에서 트레이 아이콘 옆에 표시되는 제목 텍스트를 설정합니다. - -#### `tray.setHighlightMode(highlight)` _macOS_ - -* `highlight` Boolean - -트레이 아이콘이 클릭됐을 때 아이콘의 배경이 파란색으로 하이라이트 될지 여부를 지정합니다. -기본값은 true입니다. - -#### `tray.displayBalloon(options)` _Windows_ - -* `options` Object - * `icon` [NativeImage](native-image.md) - * `title` String - * `content` String - -트레이에 풍선 팝업을 생성합니다. - -#### `tray.popUpContextMenu([menu, position])` _macOS_ _Windows_ - -* `menu` Menu (optional) -* `position` Object (optional) - 팝업 메뉴의 위치 - * `x` Integer - * `y` Integer - -트레이 아이콘의 컨텍스트 메뉴를 팝업시킵니다. `menu`가 전달되면, `menu`가 트레이 -아이콘의 컨텍스트 메뉴 대신 표시됩니다. - -`position`은 Windows에서만 사용할 수 있으며 기본값은 (0, 0)입니다. - -### `tray.setContextMenu(menu)` - -* `menu` Menu - -트레이에 컨텍스트 메뉴를 설정합니다. - -### `tray.getBounds()` _macOS_ _Windows_ - -이 트레이 아이콘의 `bounds`를 `Object` 형식으로 반환합니다. - -* `bounds` Object - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -[event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter diff --git a/docs-translations/ko-KR/api/web-contents.md b/docs-translations/ko-KR/api/web-contents.md deleted file mode 100644 index 8a0796f136964..0000000000000 --- a/docs-translations/ko-KR/api/web-contents.md +++ /dev/null @@ -1,1068 +0,0 @@ -# webContents - -> 웹 페이지를 렌더링하고 제어합니다. - -`webContents`는 [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter)를 -상속받았습니다. 웹 페이지의 렌더링과 관리를 책임지며 -[`BrowserWindow`](browser-window.md)의 속성입니다. 다음은 `webContents` 객체에 -접근하는 예시입니다: - -```javascript -const {BrowserWindow} = require('electron'); - -let win = new BrowserWindow({width: 800, height: 1500}); -win.loadURL('http://github.com'); - -let webContents = win.webContents; -``` - -## Events - -`webContents` 객체는 다음과 같은 이벤트들을 발생시킵니다: - -### Event: 'did-finish-load' - -탐색 작업이 끝났을 때 발생하는 이벤트입니다. 브라우저의 탭의 스피너가 멈추고 `onload` -이벤트가 발생했을 때를 말합니다. - -### Event: 'did-fail-load' - -Returns: - -* `event` Event -* `errorCode` Integer -* `errorDescription` String -* `validatedURL` String -* `isMainFrame` Boolean - -이 이벤트는 `did-finish-load`와 비슷하나, 로드가 실패했거나 취소되었을 때 발생합니다. -예를 들면 `window.stop()`이 실행되었을 때 발생합니다. 발생할 수 있는 전체 에러 코드의 -목록과 설명은 [여기서](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) -확인할 수 있습니다. 참고로 리다이렉트 응답은 `errorCode` -3과 함께 발생합니다; 이 -에러는 명시적으로 무시할 수 있습니다. - -### Event: 'did-frame-finish-load' - -Returns: - -* `event` Event -* `isMainFrame` Boolean - -프레임(Frame)이 탐색을 끝냈을 때 발생하는 이벤트입니다. - -### Event: 'did-start-loading' - -브라우저 탭의 스피너가 회전을 시작한 때와 같은 시점에 대응하는 이벤트입니다. - -### Event: 'did-stop-loading' - -브라우저 탭의 스피너가 회전을 멈추었을 때와 같은 시점에 대응하는 이벤트입니다. - -### Event: 'did-get-response-details' - -Returns: - -* `event` Event -* `status` Boolean -* `newURL` String -* `originalURL` String -* `httpResponseCode` Integer -* `requestMethod` String -* `referrer` String -* `headers` Object -* `resourceType` String - -요청한 리소스에 관련된 자세한 정보를 사용할 수 있을 때 발생하는 이벤트입니다. -`status`는 리소스를 다운로드하기 위한 소켓 연결을 나타냅니다. - -### Event: 'did-get-redirect-request' - -Returns: - -* `event` Event -* `oldURL` String -* `newURL` String -* `isMainFrame` Boolean -* `httpResponseCode` Integer -* `requestMethod` String -* `referrer` String -* `headers` Object - -리소스를 요청하는 동안에 리다이렉트 응답을 받았을 때 발생하는 이벤트입니다. - -### Event: 'dom-ready' - -Returns: - -* `event` Event - -주어진 프레임의 문서가 로드되었을 때 발생하는 이벤트입니다. - -### Event: 'page-favicon-updated' - -Returns: - -* `event` Event -* `favicons` Array - URL 배열 - -페이지가 favicon(파비콘) URL을 받았을 때 발생하는 이벤트입니다. - -### Event: 'new-window' - -Returns: - -* `event` Event -* `url` String -* `frameName` String -* `disposition` String - `default`, `foreground-tab`, `background-tab`, - `new-window`, `other`중 하나일 수 있습니다. -* `options` Object - 새로운 `BrowserWindow` 객체를 만들 때 사용되는 옵션 객체입니다. - -페이지가 `url`에 대하여 새로운 윈도우를 열기위해 요청한 경우 발생하는 이벤트입니다. -`window.open`이나 ``과 같은 외부 링크에 의해 요청될 수 있습니다. - -기본값으로 `BrowserWindow`는 `url`을 기반으로 생성됩니다. - -`event.preventDefault()`를 호출하면 새로운 창이 생성되는 것을 방지할 수 있습니다. - -### Event: 'will-navigate' - -Returns: - -* `event` Event -* `url` String - -사용자 또는 페이지가 새로운 페이지로 이동할 때 발생하는 이벤트입니다. -`window.location` 객체가 변경되거나 사용자가 페이지의 링크를 클릭했을 때 발생합니다. - -이 이벤트는 `webContents.loadURL`과 `webContents.back` 같은 API를 이용한 -프로그램적으로 시작된 탐색에 대해서는 발생하지 않습니다. - -이 이벤트는 앵커 링크를 클릭하거나 `window.location.hash`의 값을 변경하는 등의 페이지 -내 탐색시엔 발생하지 않습니다. 대신 `did-navigate-in-page` 이벤트를 사용해야 합니다. - -`event.preventDefault()`를 호출하면 탐색을 방지할 수 있습니다. - -### Event: 'did-navigate' - -Returns: - -* `event` Event -* `url` String - -탐색이 완료되면 발생하는 이벤트입니다. - -이 이벤트는 앵커 링크를 클릭하거나 `window.location.hash`의 값을 변경하는 등의 페이지 -내 탐색시엔 발생하지 않습니다. 대신 `did-navigate-in-page` 이벤트를 사용해야 합니다. - -### Event: 'did-navigate-in-page' - -Returns: - -* `event` Event -* `url` String - -페이지 내의 탐색이 완료되면 발생하는 이벤트입니다. - -페이지 내의 탐색이 발생하면 페이지 URL이 변경되지만 페이지 밖으로의 탐색은 일어나지 -않습니다. 예를 들어 앵커 링크를 클릭했을 때, 또는 DOM `hashchange` 이벤트가 발생했을 -때로 볼 수 있습니다. - -### Event: 'crashed' - -렌더러 프로세스가 예기치 못하게 종료되었을 때 발생되는 이벤트입니다. - -### Event: 'plugin-crashed' - -Returns: - -* `event` Event -* `name` String -* `version` String - -플러그인 프로세스가 예기치 못하게 종료되었을 때 발생되는 이벤트입니다. - -### Event: 'destroyed' - -`webContents`가 소멸될 때 발생되는 이벤트입니다. - -### Event: 'devtools-opened' - -개발자 도구가 열렸을 때 발생되는 이벤트입니다. - -### Event: 'devtools-closed' - -개발자 도구가 닫혔을 때 발생되는 이벤트입니다. - -### Event: 'devtools-focused' - -개발자 도구에 포커스가 가거나 개발자 도구가 열렸을 때 발생되는 이벤트입니다. - -### Event: 'certificate-error' - -Returns: - -* `event` Event -* `url` URL -* `error` String - 에러 코드 -* `certificate` Object - * `data` Buffer - PEM 인코딩된 데이터 - * `issuerName` String -* `callback` Function - -`url`에 대한 `certificate` 인증서의 유효성 검증에 실패했을 때 발생하는 이벤트입니다. - -사용법은 [`app`의 `certificate-error` 이벤트](app.md#event-certificate-error)와 -같습니다. - -### Event: 'select-client-certificate' - -Returns: - -* `event` Event -* `url` URL -* `certificateList` [Objects] - * `data` Buffer - PEM 인코딩된 데이터 - * `issuerName` String - 인증서 발급자 이름 -* `callback` Function - -클라이언트 인증이 요청되었을 때 발생하는 이벤트입니다. - -사용법은 [`app`의 `select-client-certificate` 이벤트](app.md#event-select-client-certificate)와 -같습니다. - -### Event: 'login' - -Returns: - -* `event` Event -* `request` Object - * `method` String - * `url` URL - * `referrer` URL -* `authInfo` Object - * `isProxy` Boolean - * `scheme` String - * `host` String - * `port` Integer - * `realm` String -* `callback` Function - -`webContents`가 기본 인증을 수행하길 원할 때 발생되는 이벤트입니다. - -[`app`의 `login`이벤트](app.md#event-login)와 사용 방법은 같습니다. - -### Event: 'found-in-page' - -Returns: - -* `event` Event -* `result` Object - * `requestId` Integer - * `finalUpdate` Boolean - 더 많은 응답이 따르는 경우를 표시합니다. - * `activeMatchOrdinal` Integer (optional) - 활성화 일치의 위치. - * `matches` Integer (optional) - 일치하는 개수. - * `selectionArea` Object (optional) - 첫 일치 부위의 좌표. - -[`webContents.findInPage`](web-contents.md#webcontentsfindinpage) 요청의 결과를 -사용할 수 있을 때 발생하는 이벤트입니다. - -### Event: 'media-started-playing' - -미디어가 재생되기 시작할 때 발생하는 이벤트입니다. - -### Event: 'media-paused' - -미디어가 중지되거나 재생이 완료되었을 때 발생하는 이벤트입니다. - -### Event: 'did-change-theme-color' - -페이지의 테마 색이 변경될 때 발생하는 이벤트입니다. 이 이벤트는 보통 meta 태그에 -의해서 발생합니다: - -```html - -``` - -### Event: 'update-target-url' - -Returns: - -* `event` Event -* `url` String - -마우스나 키보드를 사용해 링크에 포커스할 때 발생하는 이벤트입니다. - -### Event: 'cursor-changed' - -Returns: - -* `event` Event -* `type` String -* `image` NativeImage (optional) -* `scale` Float (optional) - -커서 종류가 변경될 때 발생하는 이벤트입니다. `type` 인수는 다음 값이 될 수 있습니다: -`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`, `custom`. - -만약 `type` 인수가 `custom` 이고 `image` 인수가 `NativeImage`를 통한 커스텀 -커서를 지정했을 때, 해당 이미지로 커서가 변경됩니다. 또한 `scale` 인수는 이미지의 -크기를 조정합니다. - -### Event: 'context-menu' - -Returns: - -* `event` Event -* `params` Object - * `x` Integer - x 좌표 - * `y` Integer - y 좌표 - * `linkURL` String - 컨텍스트 메뉴가 호출된 노드를 둘러싸는 링크의 URL. - * `linkText` String - 링크에 연관된 텍스트. 콘텐츠의 링크가 이미지인 경우 빈 - 문자열이 됩니다. - * `pageURL` String - 컨텍스트 메뉴가 호출된 상위 수준 페이지의 URL. - * `frameURL` String - 컨텍스트 메뉴가 호출된 서브 프레임의 URL. - * `srcURL` String - 컨텍스트 메뉴가 호출된 요소에 대한 소스 URL. 요소와 소스 URL은 - 이미지, 오디오, 비디오입니다. - * `mediaType` String - 컨텍스트 메뉴가 호출된 노드의 종류. 값은 `none`, `image`, - `audio`, `video`, `canvas`, `file` 또는 `plugin`이 될 수 있습니다. - * `hasImageContent` Boolean - 컨텍스트 메뉴가 내용이 있는 이미지에서 호출되었는지 - 여부. - * `isEditable` Boolean - 컨텍스트를 편집할 수 있는지 여부. - * `selectionText` String - 컨텍스트 메뉴가 호출된 부분에 있는 선택된 텍스트. - * `titleText` String - 컨텍스트 메뉴가 호출된 선택된 제목 또는 알림 텍스트. - * `misspelledWord` String - 만약 있는 경우, 커서가 가르키는 곳에서 발생한 오타. - * `frameCharset` String - 메뉴가 호출된 프레임의 문자열 인코딩. - * `inputFieldType` String - 컨텍스트 메뉴가 입력 필드에서 호출되었을 때, 그 필드의 - 종류. 값은 `none`, `plainText`, `password`, `other` 중 한 가지가 될 수 있습니다. - * `menuSourceType` String - 컨텍스트 메뉴를 호출한 입력 소스. 값은 `none`, - `mouse`, `keyboard`, `touch`, `touchMenu` 중 한 가지가 될 수 있습니다. - * `mediaFlags` Object - 컨텍스트 메뉴가 호출된 미디어 요소에 대한 플래그. 자세한 - 사항은 아래를 참고하세요. - * `editFlags` Object - 이 플래그는 렌더러가 어떤 행동을 이행할 수 있는지 여부를 - 표시합니다. 자세한 사항은 아래를 참고하세요. - -`mediaFlags`는 다음과 같은 속성을 가지고 있습니다: - -* `inError` Boolean - 미디어 객체가 크래시되었는지 여부. -* `isPaused` Boolean - 미디어 객체가 일시중지되었는지 여부. -* `isMuted` Boolean - 미디어 객체가 음소거되었는지 여부. -* `hasAudio` Boolean - 미디어 객체가 오디오를 가지고 있는지 여부. -* `isLooping` Boolean - 미디어 객체가 루프중인지 여부. -* `isControlsVisible` Boolean - 미디어 객체의 컨트롤이 보이는지 여부. -* `canToggleControls` Boolean - 미디어 객체의 컨트롤을 토글할 수 있는지 여부. -* `canRotate` Boolean - 미디어 객체를 돌릴 수 있는지 여부. - -`editFlags`는 다음과 같은 속성을 가지고 있습니다: - -* `canUndo` Boolean - 렌더러에서 실행 취소할 수 있는지 여부. -* `canRedo` Boolean - 렌더러에서 다시 실행할 수 있는지 여부. -* `canCut` Boolean - 렌더러에서 잘라내기를 실행할 수 있는지 여부. -* `canCopy` Boolean - 렌더러에서 복사를 실행할 수 있는지 여부. -* `canPaste` Boolean - 렌더러에서 붙여넣기를 실행할 수 있는지 여부. -* `canDelete` Boolean - 렌더러에서 삭제를 실행할 수 있는지 여부. -* `canSelectAll` Boolean - 렌더러에서 모두 선택을 실행할 수 있는지 여부. - -새로운 컨텍스트 메뉴의 제어가 필요할 때 발생하는 이벤트입니다. - -### Event: 'select-bluetooth-device' - -Returns: - -* `event` Event -* `devices` [Objects] - * `deviceName` String - * `deviceId` String -* `callback` Function - * `deviceId` String - -`navigator.bluetooth.requestDevice`의 호출에 의해 블루투스 기기가 선택되어야 할 때 -발생하는 이벤트입니다. `navigator.bluetooth` API를 사용하려면 `webBluetooth`가 -활성화되어 있어야 합니다. 만약 `event.preventDefault`이 호출되지 않으면, 첫 번째로 -사용 가능한 기기가 선택됩니다. `callback`은 반드시 선택될 `deviceId`와 함께 -호출되어야 하며, 빈 문자열을 `callback`에 보내면 요청이 취소됩니다. - -```javascript -app.commandLine.appendSwitch('enable-web-bluetooth') - -app.on('ready', () => { - webContents.on('select-bluetooth-device', (event, deviceList, callback) => { - event.preventDefault() - let result = deviceList.find((device) => { - return device.deviceName === 'test' - }) - if (!result) { - callback('') - } else { - callback(result.deviceId) - } - }) -}) -``` - -## Instance Methods - -`webContents`객체는 다음과 같은 인스턴스 메서드들을 가지고 있습니다. - -### `webContents.loadURL(url[, options])` - -* `url` URL -* `options` Object (optional) - * `httpReferrer` String - HTTP 레퍼러 url. - * `userAgent` String - 요청을 시작한 유저 에이전트. - * `extraHeaders` String - "\n"로 구분된 Extra 헤더들. - -윈도우에 웹 페이지 `url`을 로드합니다. `url`은 `http://`, `file://`과 같은 -프로토콜 접두사를 가지고 있어야 합니다. 만약 반드시 http 캐시를 사용하지 않고 로드해야 -하는 경우 `pragma` 헤더를 사용할 수 있습니다. - -```javascript -const options = {extraHeaders: 'pragma: no-cache\n'}; -webContents.loadURL(url, options) -``` - -### `webContents.downloadURL(url)` - -* `url` URL - -`url`의 리소스를 탐색 없이 다운로드를 시작합니다. `session`의 `will-download` -이벤트가 발생합니다. - -### `webContents.getURL()` - -현재 웹 페이지의 URL을 반환합니다. - -```javascript -let win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('http://github.com'); - -let currentURL = win.webContents.getURL(); -``` - -### `webContents.getTitle()` - -현재 웹 페이지의 제목을 반환합니다. - -### `webContents.isLoading()` - -현재 웹 페이지가 리소스를 로드중인지 여부를 반환합니다. - -### `webContents.isLoadingMainFrame()` - -메인 프레임이 여전히 로딩중인지 여부를 반환합니다. (내부 iframe 또는 frame 포함) - -### `webContents.isWaitingForResponse()` - -현재 웹 페이지가 페이지의 메인 리소스로부터 첫 응답을 기다리고있는지 여부를 반환합니다. - -### `webContents.stop()` - -대기중인 탐색 작업을 모두 멈춥니다. - -### `webContents.reload()` - -현재 웹 페이지를 새로고침합니다. - -### `webContents.reloadIgnoringCache()` - -현재 웹 페이지의 캐시를 무시한 채로 새로고침합니다. - -### `webContents.canGoBack()` - -브라우저가 이전 웹 페이지로 돌아갈 수 있는지 여부를 반환합니다. - -### `webContents.canGoForward()` - -브라우저가 다음 웹 페이지로 이동할 수 있는지 여부를 반환합니다. - -### `webContents.canGoToOffset(offset)` - -* `offset` Integer - -웹 페이지가 `offset`로 이동할 수 있는지 여부를 반환합니다. - -### `webContents.clearHistory()` - -탐색 기록을 삭제합니다. - -### `webContents.goBack()` - -브라우저가 이전 웹 페이지로 이동하게 합니다. - -### `webContents.goForward()` - -브라우저가 다음 웹 페이지로 이동하게 합니다. - -### `webContents.goToIndex(index)` - -* `index` Integer - -브라우저가 지정된 절대 웹 페이지 인덱스로 탐색하게 합니다. - -### `webContents.goToOffset(offset)` - -* `offset` Integer - -"current entry"에서 지정된 offset으로 탐색합니다. - -### `webContents.isCrashed()` - -렌더러 프로세스가 예기치 않게 종료되었는지 여부를 반환합니다. - -### `webContents.setUserAgent(userAgent)` - -* `userAgent` String - -현재 웹 페이지의 유저 에이전트를 덮어씌웁니다. - -### `webContents.getUserAgent()` - -현재 웹 페이지의 유저 에이전트 문자열을 반환합니다. - -### `webContents.insertCSS(css)` - -* `css` String - -CSS 코드를 현재 웹 페이지에 삽입합니다. - -### `webContents.executeJavaScript(code[, userGesture, callback])` - -* `code` String -* `userGesture` Boolean (optional) -* `callback` Function (optional) - 스크립트의 실행이 완료되면 호출됩니다. - * `result` - -페이지에서 자바스크립트 코드를 실행합니다. - -기본적으로 `requestFullScreen`와 같은 몇몇 HTML API들은 사용자의 조작에 의해서만 -호출될 수 있습니다. `userGesture`를 `true`로 설정하면 이러한 제약을 무시할 수 -있습니다. - -### `webContents.setAudioMuted(muted)` - -* `muted` Boolean - -현재 웹 페이지의 소리를 음소거합니다. - -### `webContents.isAudioMuted()` - -현재 페이지가 음소거 되어있는지 여부를 반환합니다. - -### `webContents.undo()` - -웹 페이지에서 `undo` 편집 커맨드를 실행합니다. - -### `webContents.redo()` - -웹 페이지에서 `redo` 편집 커맨드를 실행합니다. - -### `webContents.cut()` - -웹 페이지에서 `cut` 편집 커맨드를 실행합니다. - -### `webContents.copy()` - -웹 페이지에서 `copy` 편집 커맨드를 실행합니다. - -### `webContents.paste()` - -웹 페이지에서 `paste` 편집 커맨드를 실행합니다. - -### `webContents.pasteAndMatchStyle()` - -웹 페이지에서 `pasteAndMatchStyle` 편집 커맨드를 실행합니다. - -### `webContents.delete()` - -웹 페이지에서 `delete` 편집 커맨드를 실행합니다. - -### `webContents.selectAll()` - -웹 페이지에서 `selectAll` 편집 커맨드를 실행합니다. - -### `webContents.unselect()` - -웹 페이지에서 `unselect` 편집 커맨드를 실행합니다. - -### `webContents.replace(text)` - -* `text` String - -웹 페이지에서 `replace` 편집 커맨드를 실행합니다. - -### `webContents.replaceMisspelling(text)` - -* `text` String - -웹 페이지에서 `replaceMisspelling` 편집 커맨드를 실행합니다. - -### `webContents.insertText(text)` - -* `text` String - -포커스된 요소에 `text`를 삽입합니다. - -### `webContents.findInPage(text[, options])` - -* `text` String - 찾을 콘텐츠, 반드시 공백이 아니여야 합니다. -* `options` Object (optional) - * `forward` Boolean - 앞에서부터 검색할지 뒤에서부터 검색할지 여부입니다. 기본값은 - `true`입니다. - * `findNext` Boolean - 작업을 계속 처리할지 첫 요청만 처리할지 여부입니다. 기본값은 - `false`입니다. - * `matchCase` Boolean - 검색이 대소문자를 구분할지 여부입니다. 기본값은 - `false`입니다. - * `wordStart` Boolean - 단어의 시작 부분만 볼 지 여부입니다. 기본값은 - `false`입니다. - * `medialCapitalAsWordStart` Boolean - `wordStart`와 합쳐질 때, 소문자 또는 - 비문자가 따라붙은 대문자로 일치가 시작하는 경우 단어 중간의 일치를 허용합니다. - 여러가지 다른 단어 내의 일치를 허용합니다. 기본값은 `false`입니다. - -웹 페이지에서 `text`에 일치하는 모든 대상을 찾는 요청을 시작하고 요청에 사용된 요청을 -표현하는 `정수(integer)`를 반환합니다. 요청의 결과는 -[`found-in-page`](web-contents.md#event-found-in-page) 이벤트를 통해 취득할 수 -있습니다. - -### `webContents.stopFindInPage(action)` - -* `action` String - [`webContents.findInPage`](web-contents.md#webcontentfindinpage) - 요청이 종료되었을 때 일어날 수 있는 작업을 지정합니다. - * `clearSelection` - 선택을 취소합니다. - * `keepSelection` - 선택을 일반 선택으로 변경합니다. - * `activateSelection` - 포커스한 후 선택된 노드를 클릭합니다. - -제공된 `action`에 대한 `webContents`의 모든 `findInPage` 요청을 중지합니다. - -```javascript -webContents.on('found-in-page', (event, result) => { - if (result.finalUpdate) - webContents.stopFindInPage('clearSelection'); -}); - -const requestId = webContents.findInPage('api'); -``` - -### `webContents.capturePage([rect, ]callback)` - -* `rect` Object (optional) - 캡쳐할 페이지의 영역 - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer -* `callback` Function - -페이지의 스크린샷을 `rect`에 설정한 만큼 캡처합니다. 캡처가 완료되면 `callback`이 -`callback(image)` 형식으로 호출됩니다. `image`는 [NativeImage](native-image.md)의 -인스턴스이며 스크린샷 데이터를 담고있습니다. `rect`를 생략하면 페이지 전체를 캡처합니다. - -### `webContents.hasServiceWorker(callback)` - -* `callback` Function - -ServiceWorker가 등록되어있는지 확인하고 `callback`에 대한 응답으로 boolean 값을 -반환합니다. - -### `webContents.unregisterServiceWorker(callback)` - -* `callback` Function - -ServiceWorker가 존재하면 모두 등록을 해제하고 JS Promise가 만족될 때 `callback`에 -대한 응답으로 boolean을 반환하거나 JS Promise가 만족되지 않을 때 `false`를 반환합니다. - -### `webContents.print([options])` - -`options` Object (optional) - * `silent` Boolean - 사용자에게 프린트 설정을 묻지 않습니다. 기본값을 `false`입니다. - * `printBackground` Boolean - 웹 페이지의 배경 색과 이미지를 출력합니다. 기본값은 - `false`입니다. - -윈도우의 웹 페이지를 프린트합니다. `silent`가 `true`로 지정되어있을 땐, Electron이 -시스템의 기본 프린터와 기본 프린터 설정을 가져옵니다. - -웹 페이지에서 `window.print()`를 호출하는 것은 -`webContents.print({silent: false, printBackground: false})`를 호출하는 것과 -같습니다. - -### `webContents.printToPDF(options, callback)` - -* `options` Object - * `marginsType` Integer - 사용할 마진의 종류를 지정합니다. 0 부터 2 사이 값을 사용할 - 수 있고 각각 기본 마진, 마진 없음, 최소 마진입니다. - * `pageSize` String - 생성되는 PDF의 페이지 크기를 지정합니다. 값은 `A3`, `A4`, - `A5`, `Legal`, `Letter`, `Tabloid` 또는 마이크론 단위의 `height` & `width`가 - 포함된 객체를 사용할 수 있습니다. - * `printBackground` Boolean - CSS 배경을 프린트할지 여부를 정합니다. - * `printSelectionOnly` Boolean - 선택된 영역만 프린트할지 여부를 정합니다. - * `landscape` Boolean - landscape을 위해선 `true`를, portrait를 위해선 `false`를 - 사용합니다. -* `callback` Function - `(error, data) => {}` - -Chromium의 미리보기 프린팅 커스텀 설정을 이용하여 윈도우의 웹 페이지를 PDF로 -프린트합니다. - -`callback`은 작업이 완료되면 `callback(error, data)` 형식으로 호출됩니다. `data`는 -생성된 PDF 데이터를 담고있는 `Buffer`입니다. - -기본으로 비어있는 `options`은 다음과 같이 여겨지게 됩니다: - -```javascript -{ - marginsType: 0, - printBackground: false, - printSelectionOnly: false, - landscape: false -} -``` - -다음은 `webContents.printToPDF`의 예시입니다: - -```javascript -const {BrowserWindow} = require('electron'); -const fs = require('fs'); - -let win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('http://github.com'); - -win.webContents.on('did-finish-load', () => { - // 기본 프린트 옵션을 사용합니다 - win.webContents.printToPDF({}, (error, data) => { - if (error) throw error; - fs.writeFile('/tmp/print.pdf', data, (error) => { - if (error) - throw error; - console.log('Write PDF successfully.'); - }); - }); -}); -``` - -### `webContents.addWorkSpace(path)` - -* `path` String - -특정 경로를 개발자 도구의 워크스페이스에 추가합니다. 반드시 개발자 도구의 생성이 완료된 -이후에 사용해야 합니다. - -```javascript -win.webContents.on('devtools-opened', () => { - win.webContents.addWorkSpace(__dirname); -}); -``` - -### `webContents.removeWorkSpace(path)` - -* `path` String - -특정 경로를 개발자 도구의 워크스페이스에서 제거합니다. - -### `webContents.openDevTools([options])` - -* `options` Object (optional) - * `detach` Boolean - 새 창에서 개발자 도구를 엽니다. - * `mode` String - 개발자 도구 표시 상태를 지정합니다. 옵션은 "right", "bottom", - "undocked", "detach"가 될 수 있습니다. 기본값은 마지막 표시 상태를 - 사용합니다. `undocked` 모드에선 다시 도킹할 수 있습니다. 하지만 `detach` - 모드에선 할 수 없습니다. - -개발자 도구를 엽니다. - -### `webContents.closeDevTools()` - -개발자 도구를 닫습니다. - -### `webContents.isDevToolsOpened()` - -개발자 도구가 열려있는지 여부를 반환합니다. - -### `webContents.isDevToolsFocused()` - -개발자 도구에 포커스 되어있는지 여부를 반환합니다. - -### `webContents.toggleDevTools()` - -개발자 도구를 토글합니다. - -### `webContents.inspectElement(x, y)` - -* `x` Integer -* `y` Integer - -(`x`, `y`)위치의 요소를 조사합니다. - -### `webContents.inspectServiceWorker()` - -서비스 워커 컨텍스트(service worker context)를 위한 개발자 도구를 엽니다. - -### `webContents.send(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (optional) - -`channel`을 통하여 렌더러 프로세스에 비동기 메시지를 보냅니다. 임의의 인수를 보낼수도 -있습니다. 인수들은 내부적으로 JSON 포맷으로 직렬화 되며, 이후 함수와 프로토타입 체인은 -포함되지 않게 됩니다. - -렌더러 프로세스는 `ipcRenderer` 모듈을 통하여 `channel`를 리스닝하여 메시지를 처리할 -수 있습니다. - -메인 프로세스에서 렌더러 프로세스로 메시지를 보내는 예시 입니다: - -```javascript -// In the main process. -let win = null; -app.on('ready', () => { - 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 - - - - - - -``` - -### `webContents.enableDeviceEmulation(parameters)` - -`parameters` Object, properties: - -* `screenPosition` String - 에뮬레이트 할 화면 종료를 지정합니다 - (기본값: `desktop`) - * `desktop` - * `mobile` -* `screenSize` Object - 에뮬레이트 화면의 크기를 지정합니다 (screenPosition == - mobile) - * `width` Integer - 에뮬레이트 화면의 너비를 지정합니다 - * `height` Integer - 에뮬레이트 화면의 높이를 지정합니다 -* `viewPosition` Object - 화면에서 뷰의 위치 (screenPosition == mobile) (기본값: - `{x: 0, y: 0}`) - * `x` Integer - 좌상단 모서리로부터의 x 축의 오프셋 - * `y` Integer - 좌상단 모서리로부터의 y 축의 오프셋 -* `deviceScaleFactor` Integer - 디바이스의 스케일 팩터(scale factor)를 지정합니다. - (0일 경우 기본 디바이스 스케일 팩터를 기본으로 사용합니다. 기본값: `0`) -* `viewSize` Object - 에뮬레이트 된 뷰의 크기를 지정합니다 (빈 값은 덮어쓰지 않는 - 다는 것을 의미합니다) - * `width` Integer - 에뮬레이트 된 뷰의 너비를 지정합니다 - * `height` Integer - 에뮬레이트 된 뷰의 높이를 지정합니다 -* `fitToView` Boolean - 에뮬레이트의 뷰가 사용 가능한 공간에 맞추어 스케일 다운될지를 - 지정합니다 (기본값: `false`) -* `offset` Object - 사용 가능한 공간에서 에뮬레이트 된 뷰의 오프셋을 지정합니다 (fit - to view 모드 외에서) (기본값: `{x: 0, y: 0}`) - * `x` Float - 좌상단 모서리에서 x 축의 오프셋을 지정합니다 - * `y` Float - 좌상단 모서리에서 y 축의 오프셋을 지정합니다 -* `scale` Float - 사용 가능한 공간에서 에뮬레이드 된 뷰의 스케일 (fit to view 모드 - 외에서, 기본값: `1`) - -`parameters`로 디바이스 에뮬레이션을 사용합니다. - -### `webContents.disableDeviceEmulation()` - -`webContents.enableDeviceEmulation`로 활성화된 디바이스 에뮬레이선을 비활성화 합니다. - -### `webContents.sendInputEvent(event)` - -* `event` Object - * `type` String (**required**) - 이벤트의 종류. 다음 값들을 사용할 수 있습니다: - `mouseDown`, `mouseUp`, `mouseEnter`, `mouseLeave`, `contextMenu`, - `mouseWheel`, `mouseMove`, `keyDown`, `keyUp`, `char`. - * `modifiers` Array - 이벤트의 수정자(modifier)들에 대한 배열. 다음 값들을 포함 - 할 수 있습니다: `shift`, `control`, `alt`, `meta`, `isKeypad`, `isAutoRepeat`, - `leftButtonDown`, `middleButtonDown`, `rightButtonDown`, `capsLock`, - `numLock`, `left`, `right`. - -Input `event`를 웹 페이지로 전송합니다. - -키보드 이벤트들에 대해서는 `event` 객체는 다음 속성들을 사용할 수 있습니다: - -* `keyCode` String (**required**) - 키보드 이벤트가 발생할 때 보내질 문자. - [Accelerator](accelerator.md)의 올바른 키 코드만 사용해야 합니다. - -마우스 이벤트들에 대해서는 `event` 객체는 다음 속성들을 사용할 수 있습니다: - -* `x` Integer (**required**) -* `y` Integer (**required**) -* `button` String - 눌린 버튼. 다음 값들이 가능합니다. `left`, `middle`, `right` -* `globalX` Integer -* `globalY` Integer -* `movementX` Integer -* `movementY` Integer -* `clickCount` Integer - -`mouseWheel` 이벤트에 대해서는 `event` 객체는 다음 속성들을 사용할 수 있습니다: - -* `deltaX` Integer -* `deltaY` Integer -* `wheelTicksX` Integer -* `wheelTicksY` Integer -* `accelerationRatioX` Integer -* `accelerationRatioY` Integer -* `hasPreciseScrollingDeltas` Boolean -* `canScroll` Boolean - -### `webContents.beginFrameSubscription([onlyDirty ,]callback)` - -* `onlyDirty` Boolean (optional) - 기본값은 `false`입니다. -* `callback` Function - -캡처된 프레임과 프레젠테이션 이벤트를 구독하기 시작합니다. `callback`은 -프레젠테이션 이벤트가 발생했을 때 `callback(frameBuffer, dirtyRect)` 형태로 -호출됩니다. - -`frameBuffer`는 raw 픽셀 데이터를 가지고 있는 `Buffer` 객체입니다. 많은 장치에서 -32비트 BGRA 포맷을 사용하여 효율적으로 픽셀 데이터를 저장합니다. 하지만 실질적인 -데이터 저장 방식은 프로세서의 엔디안 방식에 따라서 달라집니다. (따라서 현대의 많은 -프로세서에선 little-endian 방식을 사용하므로 위의 포맷을 그대로 표현합니다. 하지만 -몇몇 프로세서는 big-endian 방식을 사용하는데, 이 경우 32비트 ARGB 포맷을 사용합니다) - -`dirtyRect`는 페이지의 어떤 부분이 다시 그려졌는지를 표현하는 `x, y, width, height` -속성을 포함하는 객체입니다. 만약 `onlyDirty`가 `true`로 지정되어 있으면, -`frameBuffer`가 다시 그려진 부분만 포함합니다. `onlyDirty`의 기본값은 `false`입니다. - -### `webContents.endFrameSubscription()` - -프레임 프레젠테이션 이벤트들에 대한 구독을 중지합니다. - -### `webContents.startDrag(item)` - -* `item` object - * `file` String - * `icon` [NativeImage](native-image.md) - -현재 진행중인 드래그-드롭에 `item`을 드래그 중인 아이템으로 설정합니다. `file`은 -드래그될 파일의 절대 경로입니다. 그리고 `icon`은 드래그 도중 커서 밑에 표시될 -이미지입니다. - -### `webContents.savePage(fullPath, saveType, callback)` - -* `fullPath` String - 전체 파일 경로. -* `saveType` String - 저장 종류를 지정합니다. - * `HTMLOnly` - 페이지의 HTML만 저장합니다. - * `HTMLComplete` - 페이지의 완성된 HTML을 저장합니다. - * `MHTML` - 페이지의 완성된 HTML을 MHTML로 저장합니다. -* `callback` Function - `(error) => {}`. - * `error` Error - -만약 페이지를 저장하는 프로세스가 성공적으로 끝났을 경우 true를 반환합니다. - -```javascript -win.loadURL('https://github.com'); - -win.webContents.on('did-finish-load', () => { - win.webContents.savePage('/tmp/test.html', 'HTMLComplete', (error) => { - if (!error) - console.log('Save page successfully'); - }); -}); -``` - -### `webContents.showDefinitionForSelection()` _macOS_ - -페이지에서 선택된 단어에 대한 사전 검색 결과 팝업을 표시합니다. - -## Instance Properties - -`WebContents`객체들은 다음 속성들을 가지고 있습니다: - -### `webContents.id` - -이 WebContents의 유일 ID. - -### `webContents.session` - -이 webContents에서 사용하는 [session](session.md) 객체를 반환합니다. - -### `webContents.hostWebContents` - -현재 `WebContents`를 소유하는 `WebContents`를 반환합니다. - -### `webContents.devToolsWebContents` - -이 `WebContents`에 대한 개발자 도구의 `WebContents`를 가져옵니다. - -**참고:** 사용자가 절대로 이 객체를 저장해서는 안 됩니다. 개발자 도구가 닫혔을 때, -`null`이 반환될 수 있습니다. - -### `webContents.debugger` - -디버거 API는 [원격 디버깅 프로토콜][rdp]에 대한 대체 수송자 역할을 합니다. - -```javascript -try { - win.webContents.debugger.attach('1.1'); -} catch(err) { - console.log('Debugger attach failed : ', err); -}; - -win.webContents.debugger.on('detach', (event, reason) => { - console.log('Debugger detached due to : ', reason); -}); - -win.webContents.debugger.on('message', (event, method, params) => { - if (method === 'Network.requestWillBeSent') { - if (params.request.url === 'https://www.github.com') - win.webContents.debugger.detach(); - } -}); - -win.webContents.debugger.sendCommand('Network.enable'); -``` - -#### `webContents.debugger.attach([protocolVersion])` - -* `protocolVersion` String (optional) - 요쳥할 디버깅 프로토콜의 버전. - -`webContents`에 디버거를 부착합니다. - -#### `webContents.debugger.isAttached()` - -디버거가 `webContents`에 부착되어 있는지 여부를 반환합니다. - -#### `webContents.debugger.detach()` - -`webContents`로부터 디버거를 분리시킵니다. - -#### `webContents.debugger.sendCommand(method[, commandParams, callback])` - -* `method` String - 메서드 이름, 반드시 원격 디버깅 프로토콜에 의해 정의된 메서드중 - 하나가 됩니다. -* `commandParams` Object (optional) - 요청 인수를 표현한 JSON 객체. -* `callback` Function (optional) - 응답 - * `error` Object - 커맨드의 실패를 표시하는 에러 메시지. - * `result` Object - 원격 디버깅 프로토콜에서 커맨드 설명의 'returns' 속성에 의해 - 정의된 응답 - -지정한 커맨드를 디버깅 대상에게 전송합니다. - -#### Event: 'detach' - -* `event` Event -* `reason` String - 디버거 분리 사유. - -디버깅 세션이 종료될 때 발생하는 이벤트입니다. `webContents`가 닫히거나 개발자 도구가 -부착된 `webContents`에 대해 호출될 때 발생합니다. - -#### Event: 'message' - -* `event` Event -* `method` String - 메서드 이름. -* `params` Object - 원격 디버깅 프로토콜의 'parameters' 속성에서 정의된 이벤트 인수 - -디버깅 타겟이 관련 이벤트를 발생시킬 때 마다 발생하는 이벤트입니다. - -[rdp]: https://developer.chrome.com/devtools/docs/debugger-protocol diff --git a/docs-translations/ko-KR/api/web-frame.md b/docs-translations/ko-KR/api/web-frame.md deleted file mode 100644 index f7841248f3b61..0000000000000 --- a/docs-translations/ko-KR/api/web-frame.md +++ /dev/null @@ -1,142 +0,0 @@ -# webFrame - -> 현재 웹 페이지의 렌더링 상태를 커스터마이즈합니다. - -다음 예시는 현재 페이지를 200% 줌 합니다: - -```javascript -const {webFrame} = require('electron'); - -webFrame.setZoomFactor(2); -``` - -## Methods - -`webFrame` 모듈은 다음과 같은 메서드를 가지고 있습니다: - -### `webFrame.setZoomFactor(factor)` - -* `factor` Number - Zoom 값 - -지정한 값으로 페이지를 줌 합니다. 줌 값은 퍼센트를 100으로 나눈 값입니다. -(예시: 300% = 3.0) - -### `webFrame.getZoomFactor()` - -현재 줌 값을 반환합니다. - -### `webFrame.setZoomLevel(level)` - -* `level` Number - Zoom level - -지정한 레벨로 줌 레벨을 변경합니다. 0은 "기본 크기" 입니다. 그리고 각각 레벨 값을 -올리거나 내릴 때마다 20%씩 커지거나 작아지고 기본 크기의 50%부터 300%까지 조절 제한이 -있습니다. - -### `webFrame.getZoomLevel()` - -현재 줌 레벨을 반환합니다. - -### `webFrame.setZoomLevelLimits(minimumLevel, maximumLevel)` - -* `minimumLevel` Number -* `maximumLevel` Number - -줌 레벨의 최대, 최소치를 지정합니다. - -### `webFrame.setSpellCheckProvider(language, autoCorrectWord, provider)` - -* `language` String -* `autoCorrectWord` Boolean -* `provider` Object - -Input field나 text area에 철자 검사(spell checking) 제공자를 설정합니다. - -`provider`는 반드시 전달된 단어의 철자가 맞았는지 검사하는 `spellCheck` 메소드를 -가지고 있어야 합니다. - -[node-spellchecker][spellchecker]를 철자 검사 제공자로 사용하는 예시입니다: - -```javascript -webFrame.setSpellCheckProvider('en-US', true, { - spellCheck(text) { - return !(require('spellchecker').isMisspelled(text)); - } -}); -``` - -### `webFrame.registerURLSchemeAsSecure(scheme)` - -* `scheme` String - -`scheme`을 보안 스킴으로 등록합니다. - -보안 스킴은 혼합된 콘텐츠 경고를 발생시키지 않습니다. 예를 들어 `https` 와 `data`는 -네트워크 공격자로부터 손상될 가능성이 없기 때문에 보안 스킴이라고 할 수 있습니다. - -### `webFrame.registerURLSchemeAsBypassingCSP(scheme)` - -* `scheme` String - -현재 페이지 콘텐츠의 보안 정책에 상관없이 `scheme`로부터 리소스가 로드됩니다. - -### `webFrame.registerURLSchemeAsPrivileged(scheme)` - - * `scheme` String - -`scheme`를 보안된 스킴으로 등록합니다. 리소스에 대해 보안 정책을 우회하며, -ServiceWorker의 등록과 fetch API를 사용할 수 있도록 지원합니다. - -### `webFrame.insertText(text)` - -* `text` String - -포커스된 요소에 `text`를 삽입합니다. - -### `webFrame.executeJavaScript(code[, userGesture])` - -* `code` String -* `userGesture` Boolean (optional) - 기본값은 `false` 입니다. - -페이지에서 `code`를 실행합니다. - -브라우저 윈도우에서 어떤 `requestFullScreen` 같은 HTML API는 사용자의 승인이 -필요합니다. `userGesture`를 `true`로 설정하면 이러한 제약을 제거할 수 있습니다. - -### `webFrame.getResourceUsage()` - -Blink의 내부 메모리 캐시 사용 정보를 담고있는 객체를 반환합니다. - -```javascript -console.log(webFrame.getResourceUsage()) -``` - -다음이 출력됩니다: - -```javascript -{ - images: { - count: 22, - size: 2549, - liveSize: 2542, - decodedSize: 478, - purgedSize: 0, - purgeableSize: 0 - }, - cssStyleSheets: { /* same with "images" */ }, - xslStyleSheets: { /* same with "images" */ }, - fonts: { /* same with "images" */ }, - other: { /* same with "images" */ }, -} -``` - -### `webFrame.clearCache()` - -사용하지 않는 메모리 비우기를 시도합니다. (이전 페이지의 이미지 등) - -참고로 맹목적으로 이 메서드를 호출하는 것은 이 빈 캐시를 다시 채워야하기 때문에 -Electron을 느리게 만듭니다. 따라서 이 메서드는 페이지가 예상했던 것 보다 실질적으로 더 -적은 메모리를 사용하게 만드는 애플리케이션 이벤트가 발생했을 때만 호출해야 합니다. -(i.e. 아주 무거운 페이지에서 거의 빈 페이지로 이동한 후 계속 유지할 경우) - -[spellchecker]: https://github.com/atom/node-spellchecker diff --git a/docs-translations/ko-KR/api/web-view-tag.md b/docs-translations/ko-KR/api/web-view-tag.md deleted file mode 100644 index 6170556570e3b..0000000000000 --- a/docs-translations/ko-KR/api/web-view-tag.md +++ /dev/null @@ -1,811 +0,0 @@ -# `` 태그 - -> 외부 웹 콘텐츠를 고립된 프레임과 프로세스에서 표시합니다. - -`guest` 콘텐츠(웹 페이지)를 Electron 앱 페이지에 삽입하기 위해 `webview` 태그를 -사용할 수 있습니다. 게스트 콘텐츠는 `webview` 컨테이너에 담겨 대상 페이지에 삽입되고 -해당 페이지에선 게스트 콘텐츠의 배치 및 렌더링 과정을 조작할 수 있습니다. - -`iframe`과는 달리 `webview`는 애플리케이션과 분리된 프로세스에서 작동합니다. -이는 웹 페이지와 같은 권한을 가지지 않고 앱과 임베디드(게스트) 콘텐츠간의 모든 -상호작용이 비동기로 작동한다는 것을 의미합니다. 따라서 임베디드 콘텐츠로부터 -애플리케이션을 안전하게 유지할 수 있습니다. - -보안상의 이유로, `webview`는 `nodeIntegration`이 활성화된 `BrowserWindow`에서만 사용할 수 있습니다. - -## 예시 - -웹 페이지를 애플리케이션에 삽입하려면 `webview` 태그를 사용해 원하는 타겟 페이지에 -추가하면 됩니다. (게스트 콘텐츠가 앱 페이지에 추가 됩니다) 간단한 예로 `webview` -태그의 `src` 속성에 페이지를 지정하고 css 스타일을 이용해서 컨테이너의 외관을 설정할 -수 있습니다: - -```html - -``` - -게스트 콘텐츠를 조작하기 위해 자바스크립트로 `webview` 태그의 이벤트를 리스닝 하여 -응답을 받을 수 있습니다. 다음 예시를 참고하세요: 첫번째 리스너는 페이지 로딩 시작시의 -이벤트를 확인하고 두번째 리스너는 페이지의 로딩이 끝난시점을 확인합니다. 그리고 -페이지를 로드하는 동안 "loading..." 메시지를 표시합니다. - -```html - -``` - -## CSS 스타일링 참고 - -주의할 점은 `webview` 태그의 스타일은 전통적인 flexbox 레이아웃을 사용했을 때 자식 -`object` 요소가 해당 `webview` 컨테이너의 전체 높이와 넓이를 확실히 채우도록 -내부적으로 `display:flex;`를 사용합니다. (v0.36.11 부터) 따라서 인라인 레이아웃을 -위해 `display:inline-flex;`를 쓰지 않는 한, 기본 `display:flex;` CSS 속성을 -덮어쓰지 않도록 주의해야 합니다. - -`webview`는 `hidden` 또는 `display: none;` 속성을 사용할 때 발생하는 문제를 한 가지 -가지고 있습니다. 자식 `browserplugin` 객체 내에서 비정상적인 랜더링 동작을 발생시킬 수 -있으며 웹 페이지가 로드되었을 때, `webview`가 숨겨지지 않았을 때, 반대로 그냥 바로 -다시 보이게 됩니다. `webview`를 숨기는 방법으로 가장 권장되는 방법은 `width` & -`height`를 0으로 지정하는 CSS를 사용하는 것이며 `flex`를 통해 0px로 요소를 수축할 수 -있도록 합니다. - -```html - -``` - -## 태그 속성 - -`webview` 태그는 다음과 같은 속성을 가지고 있습니다: - -### `src` - -```html - -``` - -지정한 URL을 페이지 소스로 사용합니다. 이 속성을 지정할 경우 `webview`의 최상위 -페이지가 됩니다. - -`src`에 같은 페이지를 지정하면 페이지를 새로고침합니다. - -`src` 속성은 `data:text/plain,Hello, world!` 같은 data URL도 사용할 수 있습니다. - -### `autosize` - -```html - -``` - -"on" 으로 지정하면 `webview` 컨테이너는 `minwidth`, `minheight`, `maxwidth`, -`maxheight`에 맞춰서 자동으로 크기를 조절합니다. 이 속성들은 `autosize`가 -활성화되어있지 않는 한 프레임에 영향을 주지 않습니다. `autosize`가 활성화 되어있으면 -`webview` 컨테이너의 크기는 각각의 지정한 최대, 최소값에 따라 조절됩니다. - -### `nodeintegration` - -```html - -``` - -"on"으로 지정하면 `webview` 페이지 내에서 `require`와 `process 객체`같은 node.js -API를 사용할 수 있습니다. 이를 지정하면 내부에서 로우레벨 리소스에 접근할 수 있습니다. - -**참고:** Node 통합 기능은 `webview`에서 부모 윈도우가 해당 옵션이 비활성화되어있는 -경우 항상 비활성화됩니다. - -### `plugins` - -```html - -``` - -"on"으로 지정하면 `webview` 내부에서 브라우저 플러그인을 사용할 수 있습니다. - -### `preload` - -```html - -``` - -페이지가 로드되기 전에 실행할 스크립트를 지정합니다. 스크립트 URL은 `file:` 또는 -`asar:` 프로토콜 중 하나를 반드시 사용해야 합니다. 왜냐하면 페이지 내에서 `require`를 -사용하여 스크립트를 로드하기 때문입니다. - -페이지가 nodeintegration을 활성화 하지 않아도 지정한 스크립트는 정상적으로 작동합니다. -하지만 스크립트 내에서 사용할 수 있는 global 객체는 스크립트 작동이 끝나면 삭제됩니다. - -### `httpreferrer` - -```html - -``` - -페이지의 referrer URL을 설정합니다. - -### `useragent` - -```html - -``` - -페이지의 `User-Agent`를 설정합니다. 페이지가 로드된 후엔 `setUserAgent` 메소드를 -사용해서 변경할 수 있습니다. - -### `disablewebsecurity` - -```html - -``` - -"on"으로 지정하면 페이지의 웹 보안을 해제합니다. - -### `partition` - -```html - - -``` - -페이지에서 사용하는 세션을 설정합니다. -만약 `partition` 속성이 `persist:` 접두사를 시작하면 같은 `partition` 속성을 가진 -앱 내 모든 페이지가 공유하는 영구 세션을 사용합니다. `persist:` 접두사가 없을 경우 -페이지는 인 메모리 세션을 사용합니다. 동일한 `partition`을 지정하여 다중 페이지에서 -동일한 세션을 공유할 수 있도록 할 수 있습니다. 만약 `partition`이 지정되지 않으면 앱의 -기본 세션을 사용합니다. - -이 값은 첫 탐색 이전에만 지정할 수 있습니다. 즉. 작동중인 렌더러 프로세스의 세션은 -변경할 수 없습니다. 이후 이 값을 바꾸려고 시도하면 DOM 예외를 발생시킵니다. - -### `allowpopups` - -```html - -``` - -"on"으로 지정하면 페이지에서 새로운 창을 열 수 있도록 허용합니다. - -### `blinkfeatures` - -```html - -``` - -활성화할 blink 기능을 지정한 `,`로 구분된 문자열의 리스트입니다. 지원하는 기능 -문자열의 전체 목록은 [RuntimeEnabledFeatures.in][blink-feature-string] 파일에서 -찾을 수 있습니다. - -### `disableblinkfeatures` - -```html - -``` - -비활성화할 blink 기능을 지정한 `,`로 구분된 문자열의 리스트입니다. 지원하는 기능 -문자열의 전체 목록은 [RuntimeEnabledFeatures.in][blink-feature-string] 파일에서 -찾을 수 있습니다. - -## Methods - -`webview` 태그는 다음과 같은 메서드를 가지고 있습니다: - -**참고:** 태그 객체의 메서드는 페이지 로드가 끝난 뒤에만 사용할 수 있습니다. - -**예시** - -```javascript -webview.addEventListener('dom-ready', () => { - webview.openDevTools(); -}); -``` - -### `.loadURL(url[, options])` - -* `url` URL -* `options` Object (optional) - * `httpReferrer` String - HTTP 레퍼러 url. - * `userAgent` String - 요청을 시작한 유저 에이전트. - * `extraHeaders` String - "\n"로 구분된 Extra 헤더들. - -Webview에 웹 페이지 `url`을 로드합니다. `url`은 `http://`, `file://`과 같은 -프로토콜 접두사를 가지고 있어야 합니다. - -### `.getURL()` - -페이지의 URL을 반환합니다. - -### `.getTitle()` - -페이지의 제목을 반환합니다. - -### `.isLoading()` - -페이지가 아직 리소스를 로딩하고 있는지 확인합니다. 불린 값을 반환합니다. - -### `.isWaitingForResponse()` - -페이지가 메인 리소스의 첫 응답을 기다리고 있는지 확인합니다. 불린 값을 반환합니다. - -### `.stop()` - -모든 탐색을 취소합니다. - -### `.reload()` - -페이지를 새로고침합니다. - -### `.reloadIgnoringCache()` - -캐시를 무시하고 페이지를 새로고침합니다. - -### `.canGoBack()` - -페이지 히스토리를 한 칸 뒤로 가기를 할 수 있는지 확인합니다. 불린 값을 반환합니다. - -### `.canGoForward()` - -페이지 히스토리를 한 칸 앞으로 가기를 할 수 있는지 확인합니다. 불린 값을 반환합니다. - -### `.canGoToOffset(offset)` - -* `offset` Integer - -페이지 히스토리를 `offset` 만큼 이동할 수 있는지 확인합니다. 불린값을 반환합니다. - -### `.clearHistory()` - -탐색 히스토리를 비웁니다. - -### `.goBack()` - -페이지 뒤로 가기를 실행합니다. - -### `.goForward()` - -페이지 앞으로 가기를 실행합니다. - -### `.goToIndex(index)` - -* `index` Integer - -페이지를 지정한 `index`로 이동합니다. - -### `.goToOffset(offset)` - -* `offset` Integer - -페이지로부터 `offset` 만큼 이동합니다. - -### `.isCrashed()` - -렌더러 프로세스가 크래시 됬는지 확인합니다. - -### `.setUserAgent(userAgent)` - -* `userAgent` String - -`User-Agent`를 지정합니다. - -### `.getUserAgent()` - -페이지의 `User-Agent 문자열`을 가져옵니다. - -### `.insertCSS(css)` - -* `css` String - -페이지에 CSS를 삽입합니다. - -### `.executeJavaScript(code[, userGesture, callback])` - -* `code` String -* `userGesture` Boolean -* `callback` Function (optional) - 스크립트의 실행이 완료되면 호출됩니다. - * `result` - -페이지에서 자바스크립트 코드를 실행합니다. - -만약 `userGesture`가 `true`로 설정되어 있으면 페이지에 유저 제스쳐 컨텍스트를 만듭니다. -이 옵션을 활성화 시키면 `requestFullScreen`와 같은 HTML API에서 유저의 승인을 -무시하고 개발자가 API를 바로 사용할 수 있도록 허용합니다. - -**역자주:** 기본적으로 브라우저에선 전체화면, 웹캠, 파일 열기등의 API를 사용하려면 유저의 -승인(이벤트)이 필요합니다. - -### `.openDevTools()` - -페이지에 대한 개발자 도구를 엽니다. - -### `.closeDevTools()` - -페이지에 대한 개발자 도구를 닫습니다. - -### `.isDevToolsOpened()` - -페이지에 대한 개발자 도구가 열려있는지 확인합니다. 불린 값을 반환합니다. - -### `.isDevToolsFocused()` - -페이지의 개발자 도구에 포커스 되어있는지 여부를 반화합니다. - -### `.inspectElement(x, y)` - -* `x` Integer -* `y` Integer - -(`x`, `y`) 위치에 있는 엘리먼트를 inspect합니다. - -### `.inspectServiceWorker()` - -Service worker에 대한 개발자 도구를 엽니다. - -### `.undo()` - -페이지에서 실행 취소 커맨드를 실행합니다. - -### `.redo()` - -페이지에서 다시 실행 커맨드를 실행합니다. - -### `.cut()` - -페이지에서 잘라내기 커맨드를 실행합니다. - -### `.copy()` - -페이지에서 복사 커맨드를 실행합니다. - -### `.paste()` - -페이지에서 붙여넣기 커맨드를 실행합니다. - -### `.pasteAndMatchStyle()` - -페이지에서 `pasteAndMatchStyle` 편집 커맨드를 실행합니다. - -### `.delete()` - -페이지에서 삭제 커맨드를 실행합니다. - -### `.selectAll()` - -페이지에서 전체 선택 커맨드를 실행합니다. - -### `.unselect()` - -페이지에서 `unselect` 커맨드를 실행합니다. - -### `.replace(text)` - -* `text` String - -페이지에서 `replace` 커맨드를 실행합니다. - -### `.replaceMisspelling(text)` - -* `text` String - -페이지에서 `replaceMisspelling` 커맨드를 실행합니다. - -### `.insertText(text)` - -* `text` String - -포커스된 요소에 `text`를 삽입합니다. - -### `webContents.findInPage(text[, options])` - -* `text` String - 찾을 콘텐츠, 반드시 공백이 아니여야 합니다. -* `options` Object (optional) - * `forward` Boolean - 앞에서부터 검색할지 뒤에서부터 검색할지 여부입니다. 기본값은 - `true`입니다. - * `findNext` Boolean - 작업을 계속 처리할지 첫 요청만 처리할지 여부입니다. 기본값은 - `false`입니다. - * `matchCase` Boolean - 검색이 대소문자를 구분할지 여부입니다. 기본값은 - `false`입니다. - * `wordStart` Boolean - 단어의 시작 부분만 볼 지 여부입니다. 기본값은 - `false`입니다. - * `medialCapitalAsWordStart` Boolean - `wordStart`와 합쳐질 때, 소문자 또는 - 비문자가 따라붙은 대문자로 일치가 시작하는 경우 단어 중간의 일치를 허용합니다. - 여러가지 다른 단어 내의 일치를 허용합니다. 기본값은 `false`입니다. - -웹 페이지에서 `text`에 일치하는 모든 대상을 찾는 요청을 시작하고 요청에 사용된 요청을 -표현하는 `정수(integer)`를 반환합니다. 요청의 결과는 -[`found-in-page`](web-view-tag.md#event-found-in-page) 이벤트를 통해 취득할 수 -있습니다. - -### `webContents.stopFindInPage(action)` - -* `action` String - [`.findInPage`](web-view-tag.md#webviewtagfindinpage) - 요청이 종료되었을 때 일어날 수 있는 작업을 지정합니다. - * `clearSelection` - 선택을 취소합니다. - * `keepSelection` - 선택을 일반 선택으로 변경합니다. - * `activateSelection` - 포커스한 후 선택된 노드를 클릭합니다. - -제공된 `action`에 대한 `webContents`의 모든 `findInPage` 요청을 중지합니다. - -### `.print([options])` - -`webview` 페이지를 인쇄합니다. `webContents.print([options])` 메서드와 같습니다. - -### `.printToPDF(options, callback)` - -`webview` 페이지를 PDF 형식으로 인쇄합니다. -`webContents.printToPDF(options, callback)` 메서드와 같습니다. - -### `.capturePage([rect, ]callback)` - -`webview`의 페이지의 스냅샷을 캡쳐합니다. -`webContents.printToPDF(options, callback)` 메서드와 같습니다. - -### `.send(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `args` (optional) - -`channel`을 통해 렌더러 프로세스로 비동기 메시지를 보냅니다. 또한 `args`를 지정하여 -임의의 인수를 보낼 수도 있습니다. 렌더러 프로세스는 `ipcRenderer` 모듈의 `channel` -이벤트로 이 메시지를 받아 처리할 수 있습니다. - -예시는 [webContents.send](web-contents.md#webcontentssendchannel-args)를 참고하세요. - -### `.sendInputEvent(event)` - -* `event` Object - -페이지에 입력 `event`를 보냅니다. - -`event` 객체에 대해 자세히 알아보려면 [webContents.sendInputEvent](web-contents.md#webcontentssendinputeventevent)를 -참고하세요. - -### `.showDefinitionForSelection()` _macOS_ - -페이지에서 선택된 단어에 대한 사전 검색 결과 팝업을 표시합니다. - -### `.getWebContents()` - -이 `webview`에 해당하는 [WebContents](web-contents.md)를 반환합니다. - -## DOM 이벤트 - -`webview` 태그는 다음과 같은 DOM 이벤트를 가지고 있습니다: - -### Event: 'load-commit' - -Returns: - -* `url` String -* `isMainFrame` Boolean - -로드가 시작됬을 때 발생하는 이벤트입니다. -이 이벤트는 현재 문서내의 탐색뿐만 아니라 서브 프레임 문서 레벨의 로드도 포함됩니다. -하지만 비동기 리소스 로드는 포함되지 않습니다. - -### Event: 'did-finish-load' - -탐색이 끝나면 발생하는 이벤트입니다. 브라우저 탭의 스피너가 멈추고 `onload` 이벤트가 -발생할 때를 생각하면 됩니다. - -### Event: 'did-fail-load' - -Returns: - -* `errorCode` Integer -* `errorDescription` String -* `validatedURL` String -* `isMainFrame` Boolean - -`did-finish-load`와 비슷합니다. 하지만 이 이벤트는 `window.stop()`과 같이 취소 -함수가 호출되었거나 로드에 실패했을 때 발생하는 이벤트입니다. - -### Event: 'did-frame-finish-load' - -Returns: - -* `isMainFrame` Boolean - -프레임의 탐색이 끝나면 발생하는 이벤트입니다. - -### Event: 'did-start-loading' - -브라우저 탭의 스피너가 돌기 시작할 때 처럼 페이지의 로드가 시작될 때 발생하는 -이벤트입니다. - -### Event: 'did-stop-loading' - -브라우저 탭의 스피너가 멈출 때 처럼 페이지의 로드가 끝나면 발생하는 이벤트입니다. - -### Event: 'did-get-response-details' - -Returns: - -* `status` Boolean -* `newURL` String -* `originalURL` String -* `httpResponseCode` Integer -* `requestMethod` String -* `referrer` String -* `headers` Object -* `resourceType` String - -요청한 리소스에 관해 자세한 내용을 알 수 있을 때 발생하는 이벤트입니다. -`status`는 리소스를 다운로드할 소켓 커낵션을 나타냅니다. - -### Event: 'did-get-redirect-request' - -Returns: - -* `oldURL` String -* `newURL` String -* `isMainFrame` Boolean - -리소스를 요청하고 받는 도중에 리다이렉트가 생기면 발생하는 이벤트입니다. - -### Event: 'dom-ready' - -프레임 문서의 로드가 끝나면 발생하는 이벤트입니다. - -### Event: 'page-title-updated' - -Returns: - -* `title` String -* `explicitSet` Boolean - -탐색하는 동안에 페이지의 제목이 설정되면 발생하는 이벤트입니다. `explicitSet`는 파일 -URL에서 합성(synthesised)된 제목인 경우 false로 표시됩니다. - -### Event: 'page-favicon-updated' - -Returns: - -* `favicons` Array - URL 배열 - -페이지가 favicon URL을 받았을 때 발생하는 이벤트입니다. - -### Event: 'enter-html-full-screen' - -페이지가 HTML API에 의해 전체 화면 모드에 돌입했을 때 발생하는 이벤트입니다. - -### Event: 'leave-html-full-screen' - -페이지의 전체 화면 모드가 해제됬을 때 발생하는 이벤트입니다. - -### Event: 'console-message' - -Returns: - -* `level` Integer -* `message` String -* `line` Integer -* `sourceId` String - -`console.log` API에 의해 로깅될 때 발생하는 이벤트입니다. - -다음 예시는 모든 로그 메시지를 로그 레벨이나 다른 속성에 관련 없이 호스트 페이지의 -콘솔에 다시 로깅하는 예시입니다. - -```javascript -webview.addEventListener('console-message', (e) => { - console.log('Guest page logged a message:', e.message); -}); -``` - -### Event: 'found-in-page' - -Returns: - -* `result` Object - * `requestId` Integer - * `finalUpdate` Boolean - 더 많은 응답이 따르는 경우를 표시합니다. - * `activeMatchOrdinal` Integer (optional) - 활성화 일치의 위치. - * `matches` Integer (optional) - 일치하는 개수. - * `selectionArea` Object (optional) - 첫 일치 부위의 좌표. - -[`webContents.findInPage`](web-contents.md#webcontentsfindinpage) 요청의 결과를 -사용할 수 있을 때 발생하는 이벤트입니다. - -```javascript -webview.addEventListener('found-in-page', (e) => { - if (e.result.finalUpdate) - webview.stopFindInPage('keepSelection'); -}); - -const requestId = webview.findInPage('test'); -``` - -### Event: 'new-window' - -Returns: - -* `url` String -* `frameName` String -* `disposition` String - `default`, `foreground-tab`, `background-tab`, - `new-window`, `other`를 사용할 수 있습니다. -* `options` Object - 새로운 `BrowserWindow`를 만들 때 사용되어야 하는 옵션. - -페이지가 새로운 브라우저 창을 생성할 때 발생하는 이벤트입니다. - -다음 예시 코드는 새 URL을 시스템의 기본 브라우저로 여는 코드입니다. - -```javascript -const {shell} = require('electron'); - -webview.addEventListener('new-window', (e) => { - const protocol = require('url').parse(e.url).protocol; - if (protocol === 'http:' || protocol === 'https:') { - shell.openExternal(e.url); - } -}); -``` - -### Event: 'will-navigate' - -Returns: - -* `url` String - -사용자 또는 페이지가 새로운 페이지로 이동할 때 발생하는 이벤트입니다. -`window.location` 객체가 변경되거나 사용자가 페이지의 링크를 클릭했을 때 발생합니다. - -이 이벤트는 `.loadURL`과 `.back` 같은 API를 이용한 -프로그램적으로 시작된 탐색에 대해서는 발생하지 않습니다. - -이 이벤트는 앵커 링크를 클릭하거나 `window.location.hash`의 값을 변경하는 등의 페이지 -내 탐색시엔 발생하지 않습니다. 대신 `did-navigate-in-page` 이벤트를 사용해야 합니다. - -`event.preventDefault()`를 호출하는 것은 __아무__ 효과도 내지 않습니다. - -### Event: 'did-navigate' - -Returns: - -* `url` String - -탐색이 완료되면 발생하는 이벤트입니다. - -이 이벤트는 앵커 링크를 클릭하거나 `window.location.hash`의 값을 변경하는 등의 페이지 -내 탐색시엔 발생하지 않습니다. 대신 `did-navigate-in-page` 이벤트를 사용해야 합니다. - -### Event: 'did-navigate-in-page' - -Returns: - -* `url` String - -페이지 내의 탐색이 완료되면 발생하는 이벤트입니다. - -페이지 내의 탐색이 발생하면 페이지 URL이 변경되지만 페이지 밖으로의 탐색은 일어나지 -않습니다. 예를 들어 앵커 링크를 클릭했을 때, 또는 DOM `hashchange` 이벤트가 발생했을 -때로 볼 수 있습니다. - -### Event: 'close' - -페이지가 자체적으로 닫힐 때 발생하는 이벤트입니다. - -다음 예시 코드는 페이지가 자체적으로 닫힐 때 `webview`를 `about:blank` 페이지로 -이동시키는 예시입니다. - -```javascript -webview.addEventListener('close', () => { - webview.src = 'about:blank'; -}); -``` - -### Event: 'ipc-message' - -Returns: - -* `channel` String -* `args` Array - -호스트 페이지에서 비동기 IPC 메시지를 보낼 때 발생하는 이벤트입니다. - -`sendToHost` 메소드와 `ipc-message` 이벤트로 호스트 페이지와 쉽게 통신을 할 수 -있습니다: - -```javascript -// In embedder page. -webview.addEventListener('ipc-message', (event) => { - console.log(event.channel); - // Prints "pong" -}); -webview.send('ping'); -``` - -```javascript -// In guest page. -const {ipcRenderer} = require('electron'); -ipcRenderer.on('ping', () => { - ipcRenderer.sendToHost('pong'); -}); -``` - -### Event: 'crashed' - -렌더러 프로세스가 크래시 되었을 때 발생하는 이벤트입니다. - -### Event: 'gpu-crashed' - -GPU 프로세스가 크래시 되었을 때 발생하는 이벤트입니다. - -### Event: 'plugin-crashed' - -Returns: - -* `name` String -* `version` String - -플러그인 프로세스가 크래시 되었을 때 발생하는 이벤트입니다. - -### Event: 'destroyed' - -WebContents가 파괴될 때 발생하는 이벤트입니다. - -### Event: 'media-started-playing' - -미디어가 재생되기 시작할 때 발생하는 이벤트입니다. - -### Event: 'media-paused' - -미디어가 중지되거나 재생이 완료되었을 때 발생하는 이벤트입니다. - -### Event: 'did-change-theme-color' - -Returns: - -* `themeColor` String - -페이지의 테마 색이 변경될 때 발생하는 이벤트입니다. 이 이벤트는 보통 meta 태그에 -의해서 발생합니다: - -```html - -``` - -### Event: 'update-target-url' - -Returns: - -* `url` String - -마우스나 키보드를 사용해 링크에 포커스할 때 발생하는 이벤트입니다. - -### Event: 'devtools-opened' - -개발자 도구가 열렸을 때 발생하는 이벤트입니다. - -### Event: 'devtools-closed' - -개발자 도구가 닫혔을 때 발생하는 이벤트입니다. - -### Event: 'devtools-focused' - -개발자 도구가 포커스되거나 열렸을 때 발생하는 이벤트입니다. - -[blink-feature-string]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in diff --git a/docs-translations/ko-KR/api/window-open.md b/docs-translations/ko-KR/api/window-open.md deleted file mode 100644 index 0c4fb7153376f..0000000000000 --- a/docs-translations/ko-KR/api/window-open.md +++ /dev/null @@ -1,75 +0,0 @@ -# `window.open` 함수 - -> 새 윈도우를 열고 URL을 로드합니다. - -`window.open` 함수가 호출되면 새 창을 생성하고 `url` 페이지를 불러옵니다. 이 창은 -지정한 `url`을 로드하여 만들어진 `BrowserWindow`의 새 인스턴스이며 본래 창 객체 대신 -페이지의 컨트롤이 제한된 프록시 객체를 반환합니다. - -프록시 객체는 브라우저의 웹 페이지 창과 호환될 수 있도록 일부 제한된 표준 기능만 가지고 -있습니다. 창의 모든 컨트롤 권한을 가지려면 `BrowserWindow`를 직접 생성해서 사용해야 -합니다. - -새롭게 생성된 `BrowserWindow`는 기본적으로 부모 창의 옵션을 상속합니다. 이 옵션을 -변경하려면 새 창을 열 때 `features` 인수를 지정해야 합니다. - -### `window.open(url[, frameName][, features])` - -* `url` String -* `frameName` String (optional) -* `features` String (optional) - -`BrowserWindowProxy` 클래스의 객체를 반환하는 새로운 윈도우를 생성합니다. - -`features` 문자열은 표준 브라우저의 포맷을 따르고 있지만, 각 기능은 `BrowserWindow`의 -옵션이어야 합니다. - -**참고:** Node 통합 기능은 열린 `window`에서 부모 윈도우가 해당 옵션이 -비활성화되어있는 경우 항상 비활성화됩니다. - -### `window.opener.postMessage(message, targetOrigin)` - -* `message` String -* `targetOrigin` String - -부모 윈도우에 메시지를 보냅니다. origin을 특정할 수 있으며 `*`를 지정하면 따로 origin -설정을 사용하지 않습니다. - -## Class: BrowserWindowProxy - -### `BrowserWindowProxy.blur()` - -자식 윈도우의 포커스를 해제합니다. - -### `BrowserWindowProxy.close()` - -자식 윈도우를 강제로 닫습니다. unload 이벤트가 발생하지 않습니다. - -### `BrowserWindowProxy.closed` - -자식 윈도우가 닫히면 true로 설정됩니다. - -### `BrowserWindowProxy.eval(code)` - -* `code` String - -자식 윈도우에서 특정 스크립트를 실행합니다. - -### `BrowserWindowProxy.focus()` - -자식 윈도우에 포커스를 맞춥니다. (창을 맨 앞으로 가져옵니다) - -### `BrowserWindowProxy.print()` - -자식 윈도우에 프린트 대화 상자를 호출합니다. - -### `BrowserWindowProxy.postMessage(message, targetOrigin)` - -* `message` String -* `targetOrigin` String - -자식 윈도우에 메시지를 보냅니다. origin을 특정할 수 있으며 `*`를 지정하면 따로 origin -설정을 사용하지 않습니다. - -참고로 자식 윈도우의 `window.opener` 객체에는 다른 속성 없이 이 메서드 한 개만 -구현되어 있습니다. diff --git a/docs-translations/ko-KR/development/atom-shell-vs-node-webkit.md b/docs-translations/ko-KR/development/atom-shell-vs-node-webkit.md deleted file mode 100644 index 5f436f89f0318..0000000000000 --- a/docs-translations/ko-KR/development/atom-shell-vs-node-webkit.md +++ /dev/null @@ -1,49 +0,0 @@ -# Electron이 NW.js(node-webkit)와 기술적으로 다른점 - -__참고: Electron은 Atom Shell의 새로운 이름입니다.__ - -NW.js 처럼 Electron은 JavaScript와 HTML 그리고 Node 통합 환경을 제공함으로써 웹 -페이지에서 저 수준 시스템에 접근할 수 있도록 하여 웹 기반 데스크탑 애플리케이션을 -작성할 수 있도록 하는 프레임워크 입니다. - -하지만 Electron과 NW.js는 근본적인 개발흐름의 차이도 있습니다: - -__1. 애플리케이션의 엔트리 포인트__ - -NW.js에선 애플리케이션의 엔트리 포인트로 웹 페이지를 사용합니다. `package.json`내의 -main 필드에 메인 웹 페이지(index.html) URL을 지정하면 애플리케이션의 메인 윈도우로 -열리게 됩니다. - -Electron에선 JavaScript를 엔트리 포인트로 사용합니다. URL을 직접 제공하는 대신 API를 -사용하여 직접 브라우저 창과 HTML 파일을 로드할 수 있습니다. 또한 윈도우의 종료시기를 -결정하는 이벤트를 리스닝해야 합니다. - -Electron은 Node.js 런타임과 비슷하게 작동합니다. Electron의 API는 저수준이기에 -브라우저 테스팅을 위해 [PhantomJS](http://phantomjs.org/)를 사용할 수도 있습니다. - -__2. 빌드 시스템__ - -Electron은 Chromium의 모든것을 빌드하는 복잡성을 피하기 위해 -[libchromiumcontent](https://github.com/brightray/libchromiumcontent)를 사용하여 -Chromium의 Content API에 접근합니다. libchromiumcontent은 단일 공유 라이브러리이고 -Chromium Content 모듈과 종속성 라이브러리들을 포함합니다. 유저는 Electron을 빌드 하기 -위해 높은 사양의 빌드용 컴퓨터를 구비할 필요가 없습니다. - -__3. Node 통합__ - -NW.js는 웹 페이지에서 require를 사용할 수 있도록 Chromium을 패치했습니다. 한편 -Electron은 Chromium의 해킹을 방지하기 위해 libuv loop와 각 플랫폼의 메시지 루프에 -통합하는 다른 방법을 채택하였습니다. [`node_bindings`][node-bindings]의 코드를 보면 -이 부분이 어떻게 구현됬는지 알 수 있습니다. - -__4. 다중 컨텍스트__ - -만약 NW.js를 사용해본 적이 있다면 Node context와 Web context의 개념을 잘 알고 있을 -겁니다. 이러한 개념은 NW.js가 구현되기 위해 만들어졌습니다. - -Node의 [다중 컨텍스트](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/)를 -사용하기 때문에 Electron은 웹 페이지의 새로운 JavaScript 컨텍스트를 생성하지 않습니다. - -참고: NW.js는 0.13 버전부터 선택적으로 다중 컨텍스트를 지원합니다. - -[node-bindings]: https://github.com/electron/electron/tree/master/atom/common diff --git a/docs-translations/ko-KR/development/build-instructions-linux.md b/docs-translations/ko-KR/development/build-instructions-linux.md deleted file mode 100644 index 3fe755313ebb3..0000000000000 --- a/docs-translations/ko-KR/development/build-instructions-linux.md +++ /dev/null @@ -1,204 +0,0 @@ -# 빌드 설명서 (Linux) - -이 가이드는 Linux 운영체제에서 Electron을 빌드하는 방법을 설명합니다. - -## 빌드전 요구사양 - -* 최소한 25GB 이상의 디스크 공간과 8GB 램이 필요합니다. -* Python 2.7.x. 몇몇 CentOS와 같은 배포판들은 아직도 Python 2.6.x 버전을 사용합니다. - 그래서 먼저 `python -V`를 통해 버전을 확인할 필요가 있습니다. -* Node.js v0.12.x. Node를 설치하는 방법은 여러 가지가 있습니다. 먼저, - [Node.js](http://nodejs.org) 사이트에서 소스 코드를 받아 빌드하는 방법입니다. - 이렇게 하면 Node를 일반 유저로 홈 디렉터리에 설치할 수 있습니다. 다른 방법으로는 - [NodeSource](https://nodesource.com/blog/nodejs-v012-iojs-and-the-nodesource-linux-repositories)에서 - 소스 파일을 받아와 설치할 수 있습니다. 자세한 내용은 [Node.js 설치 방법](https://github.com/joyent/node/wiki/Installation)을 - 참고하세요. -* Clang 3.4 또는 최신 버전 -* GTK+ 와 libnotify의 개발용 헤더 - -Ubuntu를 사용하고 있다면 다음과 같이 라이브러리를 설치해야 합니다: - -```bash -$ sudo apt-get install build-essential clang libdbus-1-dev libgtk2.0-dev \ - libnotify-dev libgnome-keyring-dev libgconf2-dev \ - libasound2-dev libcap-dev libcups2-dev libxtst-dev \ - libxss1 libnss3-dev gcc-multilib g++-multilib curl -``` - -Fedora를 사용하고 있다면 다음과 같이 라이브러리를 설치해야 합니다: - -```bash -$ sudo yum install clang dbus-devel gtk2-devel libnotify-devel libgnome-keyring-devel \ - xorg-x11-server-utils libcap-devel cups-devel libXtst-devel \ - alsa-lib-devel libXrandr-devel GConf2-devel nss-devel -``` - -다른 배포판의 경우 pacman 같은 패키지 매니저를 통해 패키지를 설치 할 수 있습니다. -패키지의 이름은 대부분 위 예시와 비슷할 것입니다. 또는 소스 코드를 내려받아 -직접 빌드하는 방법도 있습니다. - -## 코드 가져오기 - -```bash -$ git clone https://github.com/electron/electron.git -``` - -## 부트 스트랩 - -부트스트랩 스크립트는 필수적인 빌드 종속성 라이브러리들을 모두 다운로드하고 프로젝트 -파일을 생성합니다. 스크립트가 정상적으로 작동하기 위해선 Python 2.7.x 버전이 -필요합니다. 아마 다운로드 작업이 상당히 많은 시간을 소요할 것입니다. 참고로 Electron은 -`ninja`를 빌드 툴체인으로 사용하므로 `Makefile`은 생성되지 않습니다. - -```bash -$ cd electron -$ ./script/bootstrap.py -v -``` - -### 크로스 컴파일 - -`arm` 아키텍쳐로 빌드 하려면 다음 종속성 라이브러리를 설치해야 합니다: - -```bash -$ sudo apt-get install libc6-dev-armhf-cross linux-libc-dev-armhf-cross \ - g++-arm-linux-gnueabihf -``` - -그리고 `bootstrap.py` 스크립트의 `--target_arch` 파라미터에 `arm` 또는 `ia32` -아키텍쳐를 지정하여 크로스 컴파일 할 수 있습니다: - -```bash -$ ./script/bootstrap.py -v --target_arch=arm -``` - -## 빌드하기 - -`Release` 와 `Debug` 두 타겟 모두 빌드 합니다: - -```bash -$ ./script/build.py -``` - -이 스크립트는 `out/R` 디렉터리에 크기가 매우 큰 Electron 실행 파일을 배치합니다. 파일 -크기는 1.3GB를 초과합니다. 이러한 문제가 발생하는 이유는 Release 타겟 바이너리가 -디버그 심볼을 포함하기 때문입니다. 파일 크기를 줄이려면 `create-dist.py` 스크립트를 -실행하세요: - -```bash -$ ./script/create-dist.py -``` - -이 스크립트는 매우 작은 배포판을 `dist` 디렉터리에 생성합니다. create-dist.py -스크립트를 실행한 이후부턴 1.3GB에 육박하는 공간을 차지하는 `out/R` 폴더의 바이너리는 -삭제해도 됩니다. - -또는 `Debug` 타겟만 빌드 할 수 있습니다: - -```bash -$ ./script/build.py -c D -``` - -빌드가 모두 끝나면 `out/D` 디렉터리에서 `electron` 디버그 바이너리를 찾을 수 있습니다. - -## 정리하기 - -빌드 파일들을 정리합니다: - -```bash -$ ./script/clean.py -``` - -## 문제 해결 - -## libtinfo.so.5 동적 링크 라이브러리를 로드하는 도중 에러가 발생할 경우 - -미리 빌드된 `clang`은 `libtinfo.so.5`로 링크를 시도합니다. 따라서 플랫폼에 따라 -적당한 `libncurses` symlink를 추가하세요: - -```bash -$ sudo ln -s /usr/lib/libncurses.so.5 /usr/lib/libtinfo.so.5 -``` - -## 테스트 - -프로젝트 코딩 스타일을 확인하려면: - -```bash -$ npm run lint -``` - -테스트를 실행하려면: - -```bash -$ ./script/test.py -``` - -## 고급 주제 - -기본적인 빌드 구성은 가장 주력인 Linux 배포판에 초점이 맞춰져있으며, 특정 배포판이나 -기기에 빌드할 계획이라면 다음 정보들이 도움이 될 것입니다. - -### 로컬에서 `libchromiumcontent` 빌드하기 - -미리 빌드된 `libchromiumcontent`를 사용하는 것을 피하기 위해, `bootstrap.py` -스크립트에 `--build_libchromiumcontent` 스위치를 추가할 수 있습니다: - -```bash -$ ./script/bootstrap.py -v --build_libchromiumcontent -``` - -참고로 `shared_library` 구성은 기본적으로 빌드되어있지 않으며, 다음 모드를 사용하면 -`Release` 버전의 Electron만 빌드할 수 있습니다: - -```bash -$ ./script/build.py -c R -``` - -### 다운로드된 `clang` 바이너리 대신 시스템의 `clang` 사용하기 - -기본적으로 Electron은 Chromium 프로젝트에서 제공하는 미리 빌드된 `clang` 바이너리를 -통해 빌드됩니다. 만약 어떤 이유로 시스템에 설치된 `clang`을 사용하여 빌드하고 싶다면, -`bootstrap.py`를 `--clang_dir=` 스위치와 함께 실행함으로써 해결할 수 있습니다. -빌드 스크립트를 이 스위치와 함께 실행할 때 스크립트는 `/bin/`와 같은 경로로 -`clang` 바이너리를 찾습니다. - -예를 들어 `clang`을 `/user/local/bin/clang`에 설치했다면 다음과 같습니다: - -```bash -$ ./script/bootstrap.py -v --build_libchromiumcontent --clang_dir /usr/local -$ ./script/build.py -c R -``` - -### `clang` 대신 다른 컴파일러 사용하기 - -Electron을 `g++`과 같은 다른 컴파일러로 빌드하려면, 먼저 `--disable_clang` 스위치를 -통해 `clang`을 비활성화 시켜야 하고, 필요하다면 `CC`와 `CXX` 환경 변수도 설정합니다. - -예를 들어 GCC 툴체인을 사용하여 빌드한다면 다음과 같습니다: - -```bash -$ env CC=gcc CXX=g++ ./script/bootstrap.py -v --build_libchromiumcontent --disable_clang -$ ./script/build.py -c R -``` - -### 환경 변수 - -또한 `CC`와 `CXX`와는 별개로, 빌드 구성을 변경하기 위해 다음 환경 변수들을 사용할 수 -있습니다: - -* `CPPFLAGS` -* `CPPFLAGS_host` -* `CFLAGS` -* `CFLAGS_host` -* `CXXFLAGS` -* `CXXFLAGS_host` -* `AR` -* `AR_host` -* `CC` -* `CC_host` -* `CXX` -* `CXX_host` -* `LDFLAGS` - -이 환경 변수는 `bootstrap.py` 스크립트를 실행할 때 설정되어야 하며, `build.py` -스크립트에선 작동하지 않습니다. diff --git a/docs-translations/ko-KR/development/build-instructions-osx.md b/docs-translations/ko-KR/development/build-instructions-osx.md deleted file mode 100644 index 9527a712fe169..0000000000000 --- a/docs-translations/ko-KR/development/build-instructions-osx.md +++ /dev/null @@ -1,65 +0,0 @@ -# 빌드 설명서 (macOS) - -이 가이드는 macOS 운영체제에서 Electron을 빌드하는 방법을 설명합니다. - -## 빌드전 요구 사항 - -* macOS >= 10.8 -* [Xcode](https://developer.apple.com/technologies/tools/) >= 5.1 -* [node.js](http://nodejs.org) (external) - -만약 Homebrew를 이용해 파이선을 설치했다면 다음 Python 모듈도 같이 설치해야 합니다: - -* pyobjc - -## 코드 가져오기 - -```bash -$ git clone https://github.com/electron/electron.git -``` - -## 부트 스트랩 - -부트스트랩 스크립트는 필수적인 빌드 종속성 라이브러리들을 모두 다운로드하고 프로젝트 -파일을 생성합니다. 참고로 Electron은 [ninja](https://ninja-build.org/)를 빌드 -툴체인으로 사용하므로 Xcode 프로젝트는 생성되지 않습니다. - -```bash -$ cd electron -$ ./script/bootstrap.py -v -``` - -## 빌드하기 - -`Release` 와 `Debug` 두 타겟 모두 빌드 합니다: - -```bash -$ ./script/build.py -``` - -또는 `Debug` 타겟만 빌드 할 수 있습니다: - -```bash -$ ./script/build.py -c D -``` - -빌드가 모두 끝나면 `out/D` 디렉터리에서 `Electron.app` 실행 파일을 찾을 수 있습니다. - -## 32비트 지원 - -Electron은 현재 macOS 64비트만 지원하고 있습니다. 그리고 앞으로도 macOS 32비트는 지원할 -계획이 없습니다. - -## 테스트 - -프로젝트 코딩 스타일을 확인하려면: - -```bash -$ ./script/cpplint.py -``` - -테스트를 실행하려면: - -```bash -$ ./script/test.py -``` diff --git a/docs-translations/ko-KR/development/build-instructions-windows.md b/docs-translations/ko-KR/development/build-instructions-windows.md deleted file mode 100644 index fef72d2af0fcf..0000000000000 --- a/docs-translations/ko-KR/development/build-instructions-windows.md +++ /dev/null @@ -1,150 +0,0 @@ -# 빌드 설명서 (Windows) - -이 가이드는 Windows 운영체제에서 Electron을 빌드하는 방법을 설명합니다. - -## 빌드전 요구 사항 - -* Windows 7 / Server 2008 R2 또는 최신 버전 -* Visual Studio 2015 - [VS 2015 커뮤니티 에디션 무료 다운로드](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) -* [Python 2.7](http://www.python.org/download/releases/2.7/) -* [Node.js](http://nodejs.org/download/) -* [Git](http://git-scm.com) - -현재 사용하고 있는 PC에 Windows를 설치하지 않았다면 -[dev.microsoftedge.com](https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/)에서 -사용 기한이 정해져있는 무료 가상머신 버전의 Windows를 받아 Electron을 빌드하는 방법도 -있습니다. - -Electron은 모든 빌드를 command-line 스크립트를 통해 빌드합니다. 따라서 빌드에 Visual -Studio를 사용할 수 없습니다. 하지만 여전히 Electron을 개발할 땐 어떤 에디터든 사용이 -가능합니다. 그리고 빠른 시일내에 Visual Studio를 이용한 빌드도 지원할 계획입니다. - -**참고:** Visual Studio가 직접 빌드에 사용되지 않더라도 IDE와 같이 제공된 빌드 -툴체인이 빌드에 **반드시** 사용되므로 여전히 필요합니다. - -**참고:** Visual Studio 2013은 사용할 수 없습니다 MSVS **2015** 을 사용하고 있는지 -확인해주세요. - -## 코드 가져오기 - -```powershell -$ git clone https://github.com/electron/electron.git -``` - -## 부트 스트랩 - -부트스트랩 스크립트는 필수적인 빌드 종속성 라이브러리들을 모두 다운로드하고 프로젝트 -파일을 생성합니다. 참고로 Electron은 `ninja`를 빌드 툴체인으로 사용하므로 Visual -Studio 프로젝트는 생성되지 않습니다. - -```powershell -$ cd electron -$ python script\bootstrap.py -v -``` - -## 빌드하기 - -`Release` 와 `Debug` 두 타겟 모두 빌드 합니다: - -```powershell -$ python script\build.py -``` - -또는 `Debug` 타겟만 빌드 할 수 있습니다: - -```powershell -$ python script\build.py -c D -``` - -빌드가 모두 끝나면 `out/D` (디버그 타겟) 또는 `out/R` (릴리즈 타겟) 디렉터리에서 -`electron.exe` 실행 파일을 찾을 수 있습니다. - -## 64비트 빌드 - -64비트를 타겟으로 빌드 하려면 부트스트랩 스크립트를 실행할 때 `--target_arch=x64` -인수를 같이 넘겨주면 됩니다: - -```powershell -$ python script\bootstrap.py -v --target_arch=x64 -``` - -다른 빌드 단계도 정확하게 같습니다. - -## 테스트 - -프로젝트 코딩 스타일을 확인하려면: - -```powershell -$ python script\cpplint.py -``` - -테스트를 실행하려면: - -```powershell -$ python script\test.py -``` - -테스트 실행시 `runas`와 같은 네이티브 모듈을 포함하는데 이 모듈은 디버그 빌드에서 같이 -사용할 수 없습니다. 하지만 여전히 릴리즈 빌드에선 사용할 수 있습니다. - -릴리즈 빌드로 테스트를 실행하려면 다음 커맨드를 사용하면 됩니다: - -```powershell -$ python script\test.py -R -``` - -## 문제 해결 - -### Command xxxx not found - -만약 `Command xxxx not found`와 같은 형식의 에러가 발생했다면 -`VS2015 Command Prompt` 콘솔로 빌드 스크립트를 실행해 보는게 좋습니다. - -### Fatal internal compiler error: C1001 - -Visual Studio가 업데이트까지 완벽하게 설치된 최신버전인지 확인하세요. - -### Assertion failed: ((handle))->activecnt >= 0 - -Cygwin에서 빌드 할 경우 `bootstrap.py` 스크립트가 다음의 에러와 함께 빌드에 실패할 수 -있습니다: - -``` -Assertion failed: ((handle))->activecnt >= 0, file src\win\pipe.c, line 1430 - -Traceback (most recent call last): - File "script/bootstrap.py", line 87, in - sys.exit(main()) - File "script/bootstrap.py", line 22, in main - update_node_modules('.') - File "script/bootstrap.py", line 56, in update_node_modules - execute([NPM, 'install']) - File "/home/zcbenz/codes/raven/script/lib/util.py", line 118, in execute - raise e -subprocess.CalledProcessError: Command '['npm.cmd', 'install']' returned non-zero exit status 3 -``` - -이 버그는 Cygwin Python과 Win32 Node를 같이 사용할 때 발생합니다. 부트스트랩 -스크립트에서 Win32 Python을 사용함으로써 이 문제를 해결할 수 있습니다. `C:\Python27` -디렉터리에 Python이 설치되었다는 가정하에 다음 명령을 실행하면 됩니다: - -```bash -$ /cygdrive/c/Python27/python.exe script/bootstrap.py -``` - -### LNK1181: cannot open input file 'kernel32.lib' - -32비트 Node.js를 다시 설치하세요. - -### Error: ENOENT, stat 'C:\Users\USERNAME\AppData\Roaming\npm' - -간단하게 해당 디렉터리를 생성하면 [문제가 해결될 겁니다](http://stackoverflow.com/a/25095327/102704): - -```powershell -$ mkdir ~\AppData\Roaming\npm -``` - -### node-gyp is not recognized as an internal or external command - -Git Bash로 빌드 했을 때 이러한 에러가 발생할 수 있습니다. 반드시 PowerShell이나 -VS2015 Command Prompt에서 빌드를 진행해야 합니다. diff --git a/docs-translations/ko-KR/development/build-system-overview.md b/docs-translations/ko-KR/development/build-system-overview.md deleted file mode 100644 index b10b813dced85..0000000000000 --- a/docs-translations/ko-KR/development/build-system-overview.md +++ /dev/null @@ -1,70 +0,0 @@ -# 빌드 시스템 개요 - -Electron은 프로젝트 생성을 위해 [gyp](https://gyp.gsrc.io/)를 사용하며 -[ninja](https://ninja-build.org/)를 이용하여 빌드합니다. 프로젝트 설정은 `.gyp` 와 -`.gypi` 파일에서 볼 수 있습니다. - -## gyp 파일 - -Electron을 빌드 할 때 `gyp` 파일들은 다음과 같은 규칙을 따릅니다: - -* `electron.gyp`는 Electron의 빌드 과정 자체를 정의합니다. -* `common.gypi`는 Node가 Chromium과 함께 빌드될 수 있도록 조정한 빌드 설정입니다. -* `vendor/brightray/brightray.gyp`는 `brightray`의 빌드 과정을 정의하고 Chromium - 링킹에 대한 기본적인 설정을 포함합니다. -* `vendor/brightray/brightray.gypi`는 빌드에 대한 일반적인 설정이 포함되어 있습니다. - -## 구성요소 빌드 - -Chromium은 꽤나 큰 프로젝트입니다. 이러한 이유로 인해 최종 링킹 작업은 상당한 시간이 -소요될 수 있습니다. 보통 이런 문제는 개발을 어렵게 만듭니다. 우리는 이 문제를 해결하기 -위해 Chromium의 "component build" 방식을 도입했습니다. 이는 각각의 컴포넌트를 각각 -따로 분리하여 공유 라이브러리로 빌드 합니다. 하지만 이 빌드 방식을 사용하면 링킹 작업은 -매우 빨라지지만 실행 파일 크기가 커지고 성능이 저하됩니다. - -Electron도 이러한 방식에 상당히 비슷한 접근을 했습니다: -`Debug` 빌드 시 바이너리는 공유 라이브러리 버전의 Chromium 컴포넌트를 사용함으로써 -링크 속도를 높이고, `Release` 빌드 시 정적 라이브러리 버전의 컴포넌트를 사용합니다. -이렇게 각 빌드의 단점을 상호 보완하여 디버그 시 빌드 속도는 향상되고 배포판 빌드의 -공유 라이브러리의 단점은 개선했습니다. - -## 부트스트랩 최소화 - -Prebuilt된 모든 Chromium 바이너리들은 부트스트랩 스크립트가 실행될 때 다운로드됩니다. -기본적으로 공유 라이브러리와 정적 라이브러리 모두 다운로드되며 최종 전체 파일 크기는 -플랫폼에 따라 800MB에서 2GB까지 차지합니다. - -기본적으로 (`libchromiumcontent`)는 Amazon Web Service를 통해 다운로드 됩니다. 만약 -`LIBCHROMIUMCONTENT_MIRROR` 환경 변수가 설정되어 있으면 부트스트랩은 해당 링크를 -사용하여 바이너리를 다운로드 합니다. [libchromiumcontent-qiniu-mirror](https://github.com/hokein/libchromiumcontent-qiniu-mirror)는 -libchromiumcontent의 미러입니다. 만약 AWS에 접근할 수 없다면 -`export LIBCHROMIUMCONTENT_MIRROR=http://7xk3d2.dl1.z0.glb.clouddn.com/` 미러를 -통해 다운로드 할 수 있습니다. - -만약 빠르게 Electron의 개발 또는 테스트만 하고 싶다면 `--dev` 플래그를 추가하여 공유 -라이브러리만 다운로드할 수 있습니다: - -```bash -$ ./script/bootstrap.py --dev -$ ./script/build.py -c D -``` - -## 두 절차에 따른 프로젝트 생성 - -Electron은 `Release`와 `Debug` 빌드가 서로 다른 라이브러리 링크 방식을 사용합니다. -하지만 `gyp`는 따로 빌드 설정을 분리하여 라이브러리 링크 방식을 정의하는 방법을 -지원하지 않습니다. - -이 문제를 해결하기 위해 Electron은 링크 설정을 제어하는 `gyp` 변수 -`libchromiumcontent_component`를 사용하고 `gyp`를 실행할 때 단 하나의 타겟만을 -생성합니다. - -## 타겟 이름 - -많은 프로젝트에서 타겟 이름을 `Release` 와 `Debug`를 사용하는데 반해 Electron은 -`R`과 `D`를 대신 사용합니다. 이유는 가끔 알 수 없는 이유(randomly)로 `Release` 와 -`Debug` 중 하나만 빌드 설정에 정의되어 있을때 `gyp`가 크래시를 일으키는데 이유는 앞서 -말한 바와 같이 Electron은 한번에 한개의 타겟만을 생성할 수 있기 때문입니다. - -이 문제는 개발자에게만 영향을 미칩니다. 만약 단순히 Electron을 rebranding 하기 위해 -빌드 하는 것이라면 이 문제에 신경 쓸 필요가 없습니다. diff --git a/docs-translations/ko-KR/development/coding-style.md b/docs-translations/ko-KR/development/coding-style.md deleted file mode 100644 index ff162575d72cd..0000000000000 --- a/docs-translations/ko-KR/development/coding-style.md +++ /dev/null @@ -1,57 +0,0 @@ -# 코딩 스타일 - -이 가이드는 Electron의 코딩 스타일에 관해 설명합니다. - -`npm run lint`를 실행하여 `cpplint`와 `eslint`를 통해 어떤 코딩 스타일 이슈를 확인할 -수 있습니다. - -## C++과 Python - -C++과 Python 스크립트는 Chromium의 -[코딩 스타일](http://www.chromium.org/developers/coding-style)을 따릅니다. 파이선 -스크립트 `script/cpplint.py`를 사용하여 모든 파일이 해당 코딩스타일에 맞게 코딩 했는지 -확인할 수 있습니다. - -Python 버전은 2.7을 사용합니다. - -C++ 코드는 많은 Chromium의 추상화와 타입을 사용합니다. 따라서 Chromium 코드에 대해 잘 -알고 있어야 합니다. 이와 관련하여 시작하기 좋은 장소로 Chromium의 -[Important Abstractions and Data Structures](https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures) -문서가 있습니다. 이 문서에선 몇가지 특별한 타입과 스코프 타입(스코프 밖으로 나가면 -자동으로 메모리에서 할당을 해제합니다. 스마트 포인터와 같습니다) 그리고 로깅 메커니즘 -등을 언급하고 있습니다. - -## JavaScript - -* [표준](http://npm.im/standard) JavaScript 코딩 스타일을 사용합니다. -* Google의 코딩 스타일에도 맞추기 위해 파일의 끝에는 **절대** 개행을 삽입해선 안됩니다. -* 파일 이름의 공백은 `_`대신에 `-`을 사용하여야 합니다. 예를 들어 -`file_name.js`를 `file-name.js`로 고쳐야 합니다. 왜냐하면 -[github/atom](https://github.com/github/atom)에서 사용되는 모듈의 이름은 보통 -`module-name` 형식이기 때문입니다. 이 규칙은 '.js' 파일에만 적용됩니다. -* 적절한 곳에 새로운 ES6/ES2015 문법을 사용해도 됩니다. - * [`const`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/const) - 는 requires와 다른 상수에 사용합니다 - * [`let`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/let) - 은 변수를 정의할 때 사용합니다 - * [Arrow functions](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/Arrow_functions) - 는 `function () { }` 표현 대신에 사용합니다 - * [Template literals](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals) - 는 `+`로 문자열을 합치는 대신 사용합니다. - -## 이름 짓기 - -Electron API는 Node.js와 비슷한 명명법을 사용합니다: - -- `BrowserWindow`와 같은 모듈 자체를 뜻하는 이름은, `CamelCase`를 사용합니다. -- `globalShortcut`과 같은 API의 세트일 땐, `mixedCase`를 사용합니다. -- API가 객체의 속성일 경우, 그리고 `win.webContents`와 같이 충분히 복잡하고 분리된 - 부분일 경우, `mixedCase`를 사용합니다. -- 다른 모듈이 아닌 API를 구현할 땐, ` Tag` 또는 `Process Object`와 같이 - 단순하고 자연스러운 제목을 사용합니다. - -새로운 API를 만들 땐 jQuery의 one-function 스타일 대신 getter, setter스타일을 -사용해야 합니다. 예를 들어 `.text([text])` 대신 `.getText()`와 `.setText(text)` -형식으로 함수를 설계하면 됩니다. 포럼에서 이 문제에 대한 -[논의](https://github.com/electron/electron/issues/46)가 -진행되고 있습니다. diff --git a/docs-translations/ko-KR/development/debug-instructions-windows.md b/docs-translations/ko-KR/development/debug-instructions-windows.md deleted file mode 100644 index 31e814f3d9e7e..0000000000000 --- a/docs-translations/ko-KR/development/debug-instructions-windows.md +++ /dev/null @@ -1,87 +0,0 @@ -# Windows에서 Electron 디버깅하기 - -만약 작성한 Javascript 애플리케이션이 아닌 Electron 자체의 크래시나 문제를 경험하고 -있다면, 네이티브/C++ 디버깅에 익숙하지 않은 개발자는 디버깅이 약간 까다로울 수 -있습니다. 그렇다 해도, Visual Studio, GitHub의 Electron이 호스팅하는 심볼 서버, -Electron 소스 코드가 중단점을 통해 순차적으로 쉽게 디버깅할 수 있는 환경을 제공합니다. - -## 요구 사항 - -* **Electron의 디버그 빌드**: 가장 쉬운 방법은 보통 - [Windows용 빌드 설명서](build-instructions-windows.md)에 명시된 요구 사항과 툴을 - 사용하여 스스로 빌드하는 것입니다. 물론 직접 다운로드 받은 Electron 바이너리에도 - 디버거 연결 및 디버깅을 사용할 수 있지만, 실질적으로 디버깅이 까다롭게 고도의 - 최적화가 되어있음을 발견하게 될 것입니다: 인라인화, 꼬리 호출, 이외 여러 가지 - 생소한 최적화가 적용되어 디버거가 모든 변수와 실행 경로를 정상적으로 표시할 수 - 없습니다. - -* **Visual Studio와 C++ 툴**: Visual Studio 2013과 Visual Studio 2015 두 가지 - 커뮤니티 에디션 모두 잘 작동합니다. 설치가 완료되면, - [Visual Studio가 GitHub의 Electron 심볼 서버를 사용하도록](setting-up-symbol-server.md) - 설정해야 합니다. 이 작업은 Visual Studio가 Electron에서 무슨일이 일어나는지 더 잘 - 이해할 수 있도록 하며 변수를 사람이 읽기 좋은 포맷으로 쉽게 표현할 수 있도록 합니다. - -* **ProcMon**: 이 무료 [SysInternals][sys-internals] 툴은 프로세스 인수, 파일 - 핸들러 그리고 레지스트리 작업을 탐색할 수 있게 도와줍니다. - -## Electron에 디버거 연결하고 디버깅하기 - -디버깅 작업을 시작하려면, PowerShell/CMD 중 한 가지를 열고 디버그 빌드 상태의 -Electron에 인수로 애플리케이션을 전달하여 실행합니다: - -```powershell -$ ./out/D/electron.exe ~/my-electron-app/ -``` - -### 중단점 설정 - -그리고, Visual Studio를 엽니다. Electron은 Visual Studio로 만들어지지 않았으며 -이러한 이유로 인해 프로젝트 파일을 가지고 있지 않습니다. 하지만 "파일로 열기"를 통해 -소스 코드 파일들을 열 수 있습니다. Visual Studio가 각각의 파일을 따로 연다는 것입니다. -여전히 중단점을 설정할 수 있습니다. Visual Studio는 현재 소스 코드와 일치하는 작동 -중인 프로세스와 중단점을 자동으로 찾아냅니다. - -관련된 코드 파일들은 `./atom/`에서 찾을 수 있으며 또한 Brightray 안 -`./vendor/brightray/browser`와 `./vendor/brightray/common`에서도 찾을 수 있습니다. -만약 하드코어를 좋아한다면, Chromium을 직접 디버깅할 수도 있습니다. 확실히 -`chromium_src` 안에서 찾을 수 있습니다. - -### 디버거 연결 - -로컬에서 작동 중인 프로세스 또는 원격 컴퓨터에 Visual Studio 디버거를 적용시킬 수 -있습니다. 프로세스의 실행이 끝난 후, 디버그 / 프로세스에 연결을 (또는 `Ctrl+Alt+P` -입력) 클릭하면 "프로세스에 연결" 대화 상자가 열립니다. 이 도구를 통해 로컬 또는 -원격에서 작동 중인 애플리케이션을 디버깅할 수 있으며 여러 프로세스를 동시에 디버깅할 -수도 있습니다. - -만약 Electron이 서로 다른 유저 계정에서 실행 중이라면, `모든 사용자의 프로세스 -보이기`를 선택하면 됩니다. 참고로 이는 `BrowserWindow`가 열린 개수에 따라 달라질 수 -있으며 아마 다수의 프로세스를 발견할 수 있을 것입니다. 전형적인 one-window -애플리케이션은 Visual Studio에서 두 개의 `Electron.exe` 항목으로 표시됩니다. 하나는 -메인 프로세스이며 다른 하나는 렌더러 프로세스입니다. 리스트는 단지 이름 하나만 제공하기 -때문에 현재까지는 다른 적절한 프로세스 판별법이 없습니다. - -### 어떤 프로세스에 디버거를 적용해야 하나요? - -코드는 메인 프로세스 내에서 실행되며 (이는 코드를 안에서 찾을 수 있거나, 결국 메인 -Javascript 파일에 의해 실행) remote (`require('electron').remote`)를 사용하여 -코드를 실행하는 것 또한 메인 프로세스 내에서 실행됩니다. 다른 코드는 각각의 렌더러 -프로세스 내에서 실행됩니다. - -디버깅할 때 여러 프로그램에 디버거를 적용할 수 있지만, 언제나 한 개의 프로그램만 -디버거에서 활성화되어야 합니다. `디버그 경로` 툴바 또는 `프로세스 창`에서 활성화 -프로그램을 설정할 수 있습니다. - -## 프로세스를 관찰하기 위해 ProcMon 사용 - -Visual Studio는 특정 코드 경로를 탐색하는것에 대해 환상적인 기능을 제공하고 ProcMon은 -애플리케이션이 운영체제와 하는 일의 모든 것을 관찰하는데 강력한 기능을 가지고 있습니다. -이 툴은 프로세스의 파일, 레지스트리, 네트워킹, 프로세스, 프로파일링 상세를 포착할 수 -있으며 강력하게 **모든** 이벤트의 발생을 로깅을 시도합니다. 만약 애플리케이션이 -운영체제에 대해 무슨 일을 하고 있는지 이해하고 싶다면 이는 좋은 자원이 될 것입니다. - -ProcMon의 기본적인 디버깅 기능을 알아보고 싶다면 Microsoft에서 제공하는 -[동영상 강좌][procmon-instructions]를 참고하세요. - -[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-translations/ko-KR/development/setting-up-symbol-server.md b/docs-translations/ko-KR/development/setting-up-symbol-server.md deleted file mode 100644 index 9835d447081e3..0000000000000 --- a/docs-translations/ko-KR/development/setting-up-symbol-server.md +++ /dev/null @@ -1,52 +0,0 @@ -# 디버거에서 디버그 심볼 서버 설정 - -디버그 심볼은 디버깅 세션을 더 좋게 개선해 줍니다. 디버그 심볼은 실행 파일과 동적 링크 -라이브러리에서 메서드에 대한 정보를 담고 있으며 명료한 함수 호출 스텍 정보를 제공합니다. -심볼 서버는 유저가 크기가 큰 디버깅용 파일을 필수적으로 다운로드 받지 않고도 디버거가 -알맞은 심볼, 바이너리 그리고 소스를 자동적으로 로드할 수 있도록 해줍니다. 서버 사용법은 -[Microsoft의 심볼 서버](http://support.microsoft.com/kb/311503)와 비슷합니다. -사용법을 알아보려면 이 문서를 참조하세요. - -참고로 릴리즈된 Electron 빌드는 자체적으로 많은 최적화가 되어 있는 관계로 경우에 따라 -디버깅이 쉽지 않을 수 있습니다. Inlining, tail call 등 컴파일러 최적화에 의해 디버거가 -모든 변수의 콘텐츠를 보여줄 수 없는 경우도 있고 실행 경로가 이상하게 보여지는 경우도 -있습니다. 유일한 해결 방법은 최적화되지 않은 로컬 빌드를 하는 것입니다. - -공식적인 Electron의 심볼 서버의 URL은 -http://54.249.141.255:8086/atom-shell/symbols 입니다. 일단 이 URL에 직접적으로 -접근할 수는 없습니다: 디버깅 툴에 심볼의 경로를 추가해야 합니다. 아래의 예시를 참고하면 -로컬 캐시 디렉터리는 서버로부터 중복되지 않게 PDB를 가져오는데 사용됩니다. -`c:\code\symbols` 캐시 디렉터리를 사용중인 OS에 맞춰 적당한 경로로 변경하세요. - -## Windbg에서 심볼 서버 사용하기 - -Windbg 심볼 경로는 구분자와 `*` 문자로 설정되어 있습니다. Electron 심볼 서버만 -사용하려면 심볼 경로의 엔트리를 추가해야 합니다. (**참고:** `c:\code\symbols` -디렉터리 경로를 PC가 원하는 경로로 수정할 수 있습니다): - -``` -SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols -``` - -Windbg 메뉴 또는 `.sympath` 커맨드를 이용하여 환경에 `_NT_SYMBOL_PATH` 문자열을 -설정합니다. 만약 Microsoft의 심볼서버로부터 심볼을 받아오려면 다음과 같이 리스팅을 -먼저해야 합니다: - -``` -SRV*c:\code\symbols\*http://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols -``` - -## Visual Studio에서 심볼 서버 사용하기 - - - - -## 문제 해결: Symbols will not load - -Windbg에서 다음의 커맨드를 입력하여 왜 심볼이 로드되지 않았는지에 대한 오류 내역을 -출력합니다: - -``` -> !sym noisy -> .reload /f electron.exe -``` diff --git a/docs-translations/ko-KR/development/source-code-directory-structure.md b/docs-translations/ko-KR/development/source-code-directory-structure.md deleted file mode 100644 index aa6d2612df57e..0000000000000 --- a/docs-translations/ko-KR/development/source-code-directory-structure.md +++ /dev/null @@ -1,88 +0,0 @@ -# 소스 코드 디렉터리 구조 - -Electron의 소스 코드는 몇 개의 파트로 분리되어 있습니다. 그리고 Chromium의 분리 -규칙(separation conventions)을 주로 따르고 있습니다. - -이미 [Chromium의 멀티 프로세스 아키텍쳐](http://dev.chromium.org/developers/design-documents/multi-process-architecture)에 -익숙해져 있다면 소스 코드를 이해하기 쉬울 것입니다. - -## 소스 코드 구조 - -``` -Electron -├── atom/ - C++ 소스 코드. -| ├── app/ - 시스템 엔트리 코드. -| ├── browser/ - 주 윈도우를 포함한 프론트엔드, UI, 그리고 메인 프로세스에 관련된 -| | 코드와 렌더러 및 웹 페이지 관리 관련 코드. -| | ├── ui/ - 서로 다른 플랫폼에 대한 UI 관련 구현 코드. -| | | ├── cocoa/ - Cocoa 특정 소스 코드. -| | | ├── win/ - Windows GUI 특정 소스 코드. -| | | └── x/ - X11 특정 소스 코드. -| | ├── api/ - 메인 프로세스 API의 구현. -| | ├── net/ - 네트워킹 관련 코드. -| | ├── mac/ - Mac 특정 Objective-C 소스 코드. -| | └── resources/ - 아이콘들, 플랫폼 종속성 파일들, 기타 등등.. -| ├── renderer/ - 렌더러 프로세스에서 작동하는 코드. -| | └── api/ - 렌더러 프로세스 API의 구현. -| └── common/ - 메인과 렌더러 프로세스에서 모두 사용하는 코드, 몇가지 유틸리티 -| 함수들이 포함되어 있고 node의 메시지 루프와 Chromium의 메시지 루프를 통합. -| └── api/ - 공통 API 구현들, 기초 Electron 빌트-인 모듈들. -├── chromium_src/ - Chromium에서 복사하여 가져온 소스 코드. -├── default_app/ - Electron에 앱이 제공되지 않았을 때 보여지는 기본 페이지. -├── docs/ - 참조 문서. -├── lib/ - JavaScript 소스 코드. -| ├── browser/ - Javascript 메인 프로세스 초기화 코드. -| | └── api/ - Javascript API 구현 코드. -| ├── common/ - 메인과 렌더러 프로세스에서 모두 사용하는 JavaScript -| | └── api/ - Javascript API 구현 코드. -| └── renderer/ - Javascript 렌더러 프로세스 초기화 코드. -| └── api/ - Javascript API 구현 코드. -├── spec/ - 자동화 테스트. -├── electron.gyp - Electron의 빌드 규칙. -└── common.gypi - 컴파일러 설정 및 `node` 와 `breakpad` 등의 구성요소를 위한 빌드 - 규칙. -``` - -## 그외 디렉터리 구조 - -* **script** - 개발목적으로 사용되는 빌드, 패키징, 테스트, 기타등을 실행하는 스크립트. -* **tools** - gyp 파일에서 사용되는 헬퍼 스크립트 `script`와는 다르게 유저로부터 직접 - 실행되지 않는 스크립트들을 이곳에 넣습니다. -* **vendor** - 소스 코드의 서드파티 종속성 코드 소스 코드 디렉터리가 겹쳐 혼란을 일으킬 - 수 있기 때문에 `third_party`와 같은 Chromium 소스 코드 디렉터리에서 사용된 폴더 - 이름은 사용하지 않았습니다. -* **node_modules** - 빌드에 사용되는 node 서드파티 모듈. -* **out** - `ninja`의 임시 출력 디렉터리. -* **dist** - 배포용 바이너리를 빌드할 때 사용하는 `script/create-dist.py` - 스크립트로부터 만들어지는 임시 디렉터리. -* **external_binaries** - `gyp` 빌드를 지원하지 않아 따로 다운로드된 서드파티 - 프레임워크 바이너리들. - -## Git 서브 모듈 최신 버전으로 유지 - -Electron 저장소는 몇 가지 외부 벤더 종속성을 가지고 있으며 [/vendor][vendor] -디렉터리에서 확인할 수 있습니다. 때때로 `git status`를 실행했을 때 아마 다음과 같은 -메시지를 흔히 목격할 것입니다: - -```sh -$ git status - - modified: vendor/brightray (new commits) - modified: vendor/node (new commits) -``` - -이 외부 종속성 모듈들을 업데이트 하려면, 다음 커맨드를 실행합니다: - -```sh -git submodule update --init --recursive -``` - -만약 자기 자신이 너무 이 커맨드를 자주 사용하는 것 같다면, `~/.gitconfig` 파일을 -생성하여 편하게 업데이트할 수 있습니다: - -``` -[alias] - su = submodule update --init --recursive -``` - -[vendor]: https://github.com/electron/electron/tree/master/vendor diff --git a/docs-translations/ko-KR/faq.md b/docs-translations/ko-KR/faq.md deleted file mode 100644 index 34a8733556e33..0000000000000 --- a/docs-translations/ko-KR/faq.md +++ /dev/null @@ -1,156 +0,0 @@ -# Electron FAQ - -## 언제 Electron이 최신 버전의 Chrome으로 업그레이드 되나요? - -Electron의 Chrome 버전은 보통 새로운 Chrome 안정 버전이 릴리즈 된 이후 1주 내지 2주 -내로 업데이트됩니다. 하지만 이러한 업데이트 주기는 보장되지 않으며 업그레이드에 필요한 -작업의 양에 따라 달라집니다. - -Electron은 크롬이 사용하는 안정된 채널만을 이용합니다, 만약 중요한 수정이 베타 또는 -개발 채널에 패치된 경우, 이전 버전의 채널로 롤백합니다. - -자세한 내용은 [보안 설명](../tutorial/security.md)을 참고하세요. - -## Electron은 언제 최신 버전의 Node.js로 업그레이드 하나요? - -새로운 버전의 Node.js가 릴리즈 되면, 보통 Electron을 업그레이드 하기 전에 한 달 정도 -대기합니다. 이렇게 하면 새로운 Node.js 버전을 업데이트 함으로써 발생하는 버그들을 -피할 수 있기 때문입니다. 이러한 상황은 자주 발생합니다. - -Node.js의 새로운 기능은 보통 V8 업그레이드에서 가져옵니다. Electron은 Chrome -브라우저에 탑재된 V8을 사용하고 있습니다. 눈부신 새로운 Node.js 버전의 자바스크립트 -기능은 보통 이미 Electron에 있습니다. - -## 어떻게 웹 페이지 간에 데이터를 공유할 수 있나요? - -두 웹페이지 간에 (렌더러 프로세스) 데이터를 공유하려면 간단히 이미 모든 브라우저에서 -사용할 수 있는 HTML5 API들을 사용하면 됩니다. 가장 좋은 후보는 -[Storage API][storage], [`localStorage`][local-storage], -[`sessionStorage`][session-storage], 그리고 [IndexedDB][indexed-db]가 있습니다. - -또는 Electron에서만 사용할 수 있는 IPC 시스템을 사용하여 메인 프로세스의 global -변수에 데이터를 저장한 후 다음과 같이 렌더러 프로세스에서 `electron` 모듈의 `remote` -속성을 통하여 접근할 수 있습니다: - -```javascript -// 메인 프로세스에서 -global.sharedObject = { - someProperty: 'default value' -}; -``` - -```javascript -// 첫 번째 페이지에서 -require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'; -``` - -```javascript -// 두 번째 페이지에서 -console.log(require('electron').remote.getGlobal('sharedObject').someProperty); -``` - -## 제작한 애플리케이션의 윈도우/트레이가 몇 분 후에나 나타납니다. - -이러한 문제가 발생하는 이유는 보통 윈도우/트레이를 담은 변수에 가비지 컬렉션이 작동해서 -그럴 가능성이 높습니다. - -이러한 문제를 맞닥뜨린 경우 다음 문서를 읽어보는 것이 좋습니다: - -* [메모리 관리][memory-management] -* [변수 스코프][variable-scope] - -만약 빠르게 고치고 싶다면, 다음과 같이 변수를 전역 변수로 만드는 방법이 있습니다: - -```javascript -app.on('ready', () => { - const tray = new Tray('/path/to/icon.png'); -}); -``` - -를 이렇게: - -```javascript -let tray = null; -app.on('ready', () => { - tray = new Tray('/path/to/icon.png'); -}); -``` - -## Electron에서 jQuery/RequireJS/Meteor/AngularJS를 사용할 수 없습니다. - -Node.js가 Electron에 합쳐졌기 때문에, DOM에 `module`, `exports`, `require` 같은 -몇 가지 심볼들이 추가됬습니다. 따라서 같은 이름의 심볼을 사용하는 몇몇 라이브러리들과 -충돌이 발생할 수 있습니다. - -이러한 문제를 해결하려면, Electron에서 node 포함을 비활성화시켜야 합니다: - -```javascript -// 메인 프로세스에서. -let win = new BrowserWindow({ - webPreferences: { - nodeIntegration: false - } -}); -``` - -하지만 Node.js의 기능과 Electron API를 유지하고 싶다면 페이지에 다른 라이브러리를 -추가하기 전에 심볼들의 이름을 변경해야 합니다: - -```html - - - - -``` - -## `require('electron').xxx`가 undefined를 반환합니다. - -Electron의 빌트인 모듈을 사용할 때, 다음과 같은 오류가 발생할 수 있습니다: - -``` -> require('electron').webFrame.setZoomFactor(1.0); -Uncaught TypeError: Cannot read property 'setZoomLevel' of undefined -``` - -이러한 문제가 발생하는 이유는 [npm의 `electron` 모듈][electron-module]이 로컬 또는 -전역 중 한 곳에 설치되어, Electron의 빌트인 모듈을 덮어씌우는 바람에 빌트인 모듈을 -사용할 수 없기 때문입니다. - -올바른 빌트인 모듈을 사용하고 있는지 확인하고 싶다면, `electron` 모듈의 경로를 -출력하는 방법이 있습니다: - -```javascript -console.log(require.resolve('electron')); -``` - -그리고 다음과 같은 경로를 가지는지 점검하면 됩니다: - -``` -"/path/to/Electron.app/Contents/Resources/atom.asar/renderer/api/lib/exports/electron.js" -``` - -하지만 `node_modules/electron/index.js`와 같은 경로로 되어있을 경우, `electron` -모듈을 지우거나 이름을 바꿔야만 합니다. - -```bash -npm uninstall electron -npm uninstall -g electron -``` - -그런데 여전히 빌트인 모듈이 계속해서 문제를 발생시키는 경우, 아마 모듈을 잘못 사용하고 -있을 가능성이 큽니다. 예를 들면 `electron.app`은 메인 프로세스에서만 사용할 수 있는 -모듈이며, 반면 `electron.webFrame` 모듈은 렌더러 프로세스에서만 사용할 수 있는 -모듈입니다. - -[memory-management]: https://developer.mozilla.org/ko/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 -[storage]: https://developer.mozilla.org/ko/docs/Web/API/Storage -[local-storage]: https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage -[session-storage]: https://developer.mozilla.org/ko/docs/Web/API/Window/sessionStorage -[indexed-db]: https://developer.mozilla.org/ko/docs/Web/API/IndexedDB_API diff --git a/docs-translations/ko-KR/styleguide.md b/docs-translations/ko-KR/styleguide.md deleted file mode 100644 index 584d3245bdb5a..0000000000000 --- a/docs-translations/ko-KR/styleguide.md +++ /dev/null @@ -1,102 +0,0 @@ -# Electron 문서 스타일 가이드 - -[Electron 문서 읽기](#electron-문서-읽기) 와 -[Electron 문서 작성하기](#electron-문서-작성하기) 중 이해가 필요한 부분을 찾아 -참고하세요: - -## Electron 문서 작성하기 - -Electron 문서를 작성하는 규칙은 다음과 같습니다. - -- `h1` 제목은 페이지당 한 개만 사용할 수 있습니다. -- 코드 블럭에서 터미널 언어 선택시 `cmd` 대신 `bash`를 사용합니다. - (syntax highlighter를 사용하기 위해서) -- 문서의 `h1` 제목은 반드시 현재 객체 이름과 같게 해야 합니다. (`browser-window` → - `BrowserWindow`) - - 하이픈(-)으로 구분되었건 다르게 구분되었건 예시와 같이 작성합니다. -- 헤더 밑에 헤더를 바로 사용하지 않습니다. 한 줄이라도 좋으니 헤더와 헤더 사이에 설명을 - 추가합니다. -- 메서드 헤더는 `code backtick` 으로 표시합니다. -- 이벤트 헤더는 한 '따옴표'로 표시합니다. -- 리스트를 2 단계 이상 중첩하지 않습니다. (안타깝게도 markdown 렌더러가 이를 지원하지 - 않습니다) -- 섹션에 대한 제목을 추가합니다. Events, Class 메서드 그리고 인스턴스 메서드 등 -- 어떤 '것'의 사용 결과를 설명할 때 '될 것입니다' 형식을 사용하여 설명합니다. -- 이벤트와 메서드를 표기할 땐 `h3` 헤더를 사용합니다. -- 선택적 인수는 `function (required[, optional])` 형식으로 작성합니다. -- 선택적 인수는 목록에서 호출되면 표시합니다. -- 문장의 길이는 한 줄당 80 칸을 유지합니다. -- 플랫폼 특정 메서드 헤더는 이탈릭체로 표시합니다. - - ```### `method(foo, bar)` _macOS_``` -- 'on' 표현 대신 'in the ___ process' 형식의 표현을 지향합니다. - -### 번역된 참조 문서 - -번역된 Electron의 참조 문서는 `docs-translations` 디렉터리에 있습니다. - -아직 번역되지 않은 언어를 추가하려면 (일부분 포함): - -- 언어의 약어(예: en-US, ja-JP, ko-KR)로 서브 디렉터리를 만듭니다. -- 서브 디렉터리에 `docs` 디렉터리를 복사합니다. 파일 이름과 디렉터리 구조는 모두 - 유지합니다. -- 문서를 번역합니다. -- 언어 디렉터리 내의 `README.md`에 번역한 문서의 링크를 추가합니다. -- 메인(upstream) Electron의 [README](https://github.com/electron/electron#documentation-translations)에 - 번역된 언어 디렉터리의 링크를 추가합니다. - -## Electron 문서 읽기 - -Electron 문서 구조를 이해하는 데 참고할 수 있는 유용한 도움말입니다. - -### Methods - -[Method](https://developer.mozilla.org/ko/docs/Glossary/Method) 문서의 -예시입니다: - -``` -`methodName(required[, optional]))` - -* `required` String (**required**) -* `optional` Integer -``` - -메서드 이름은 인수가 무엇을 받는지에 따라 결정됩니다. 선택적 인수는 브라켓([, ])으로 -묶어 이 인수가 다른 인수뒤에서 선택적으로 사용될 수 있다는 것을 표시합니다. - -메서드 이름 하단에선 각 인수에 대해 자세한 설명을 합니다. 인수의 타입은: -[`String`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String), -[`Number`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Number), -[`Object`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object), -[`Array`](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array) -와 같은 일반적으로 쓰이는 타입 중 하나를 받거나 Electron의 [`webContent`](api/web-content.md) -같은 커스텀 타입을 받습니다. - -만약 인수가 특정 플랫폼에 대해서만 적용된다면, 해당하는 플랫폼들을 공백-구분된 이텔릭체 -리스트를 데이터 타입 뒤에 표기합니다. 값은 `OS X`, `Windows` 또는 `Linux`가 될 수 -있습니다. - -``` -* `animate` Boolean (optional) _OS X_ _Windows_ -``` - -### Events - -[Event](https://developer.mozilla.org/ko/docs/Web/API/Event) 문서의 예시입니다: - -``` -Event: 'wake-up' - -Returns: - -* `time` String -``` - -이벤트는 `.on` 리스너 메서드로 사용할 수 있습니다. 만약 이벤트에서 값을 반환한다면 -문서에서 표시된 대로 일정한 타입의 값을 반환합니다. 이벤트를 처리하거나 응답하려 한다면 -다음과 같이 사용할 수 있습니다: - -```javascript -Alarm.on('wake-up', (time) => { - console.log(time) -}) -``` diff --git a/docs-translations/ko-KR/tutorial/application-distribution.md b/docs-translations/ko-KR/tutorial/application-distribution.md deleted file mode 100644 index e6bb62449986c..0000000000000 --- a/docs-translations/ko-KR/tutorial/application-distribution.md +++ /dev/null @@ -1,176 +0,0 @@ -# 애플리케이션 배포 - -Electron 애플리케이션을 배포하는 방법은 간단합니다. - -먼저 폴더 이름을 `app`로 지정한 후 Electron 리소스 디렉터리에 폴더를 통째로 집어넣기만 -하면 됩니다. 리소스 디렉터리는 macOS의 경우: `Electron.app/Contents/Resources/` -Windows와 Linux의 경우: `resources/` 입니다. - -macOS의 경우: - -```text -electron/Electron.app/Contents/Resources/app/ -├── package.json -├── main.js -└── index.html -``` - -Windows와 Linux의 경우: - -```text -electron/resources/app -├── package.json -├── main.js -└── index.html -``` - -그리고 `Electron.app`을 실행하면(Linux에선 `electron` Windows에선 `electron.exe` -입니다) Electron 앱이 실행됩니다. 최종 사용자에겐 이 `electron` 폴더(Electron.app)를 -배포하면 됩니다. - -## asar로 앱 패키징 하기 - -소스파일 전체를 복사해서 배포하는 것과는 별개로 [asar](https://github.com/electron/asar) -아카이브를 통해 애플리케이션의 소스 코드가 사용자에게 노출되는 것을 방지할 수 있습니다. - -`asar` 아카이브를 사용할 땐 단순히 `app` 폴더 대신에 애플리케이션을 패키징한 -`app.asar` 파일로 대체하면됩니다. Electron은 자동으로 `app`폴더 대신 asar 아카이브를 -기반으로 애플리케이션을 실행합니다. - -macOS의 경우: - -```text -electron/Electron.app/Contents/Resources/ -└── app.asar -``` - -Windows 와 Linux의 경우: - -```text -electron/resources/ -└── app.asar -``` - -자세한 내용은 [애플리케이션 패키징](application-packaging.md)에서 찾아볼 수 있습니다. - -## 다운로드한 바이너리의 리소스를 앱에 맞게 수정하기 - -애플리케이션을 Electron에 번들링한 후 해당 애플리케이션에 맞게 리브랜딩 할 수 있습니다. - -### Windows - -[rcedit](https://github.com/atom/rcedit)를 통해 `electron.exe`을 원하는 이름으로 -변경할 수 있고, 또한 아이콘과 기타 정보도 변경할 수 있습니다. - -### macOS - -`Electron.app`을 원하는 이름으로 변경할 수 있습니다. 그리고 다음 표시된 애플리케이션 -내부 파일에서 `CFBundleDisplayName`, `CFBundleIdentifier` 그리고 `CFBundleName` -필드를 원하는 이름으로 변경해야 합니다: - -* `Electron.app/Contents/Info.plist` -* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` - -또한 helper 앱이 프로세스 모니터에 `Electron Helper`로 나오지 않도록 이름을 -변경할 수 있습니다. 하지만 반드시 내부 및 모든 helper 앱의 이름을 변경해야 합니다. - -애플리케이션 아이콘은 `Electron.app/Contents/Resources/atom.icns`을 원하는 -아이콘으로 변경하면 됩니다. - -애플리케이션 이름을 원하는 이름으로 변경한 예시: - -``` -MyApp.app/Contents -├── Info.plist -├── MacOS/ -│   └── MyApp -└── Frameworks/ - ├── MyApp Helper EH.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper EH - ├── MyApp Helper NP.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper NP - └── MyApp Helper.app - ├── Info.plist - └── MacOS/ -    └── MyApp Helper -``` - -### Linux - -실행파일 `electron`의 이름을 원하는 대로 바꿀 수 있습니다. 리눅스 애플리케이션의 -아이콘은 [.desktop](https://developer.gnome.org/integration-guide/stable/desktop-files.html.en) -파일을 사용하여 지정할 수 있습니다. - -## 패키징 툴 - -애플리케이션을 일일이 수동으로 패키지로 만드는 대신, 서드 파티 패키징 툴을 사용하며 -이러한 작업을 자동화 시킬 수 있습니다: - -* [electron-builder](https://github.com/electron-userland/electron-builder) -* [electron-packager](https://github.com/electron-userland/electron-packager) - -## Electron 소스 코드를 다시 빌드하여 리소스 수정하기 - -또한 Electron 소스 코드를 다시 빌드할 때 애플리케이션 이름을 변경할 수 있습니다. - -`atom.gyp` 파일을 수정하여 다음과 같이 다시 빌드할 수 있습니다: - -### grunt-build-atom-shell - -Electron의 소스 코드를 수정하고 다시 빌드하는 작업은 상당히 복잡합니다. 일일이 -소스 코드를 수정하는 대신 [grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell)을 -사용하여 빌드를 자동화 시킬 수 있습니다. - -이 툴을 사용하면 자동으로 `.gyp`파일을 수정하고 다시 빌드합니다. 그리고 애플리케이션의 -네이티브 Node 모듈 또한 새로운 실행파일 이름으로 일치시킵니다. - -### Electron 커스텀 포크 만들기 - -Electron의 커스텀 포크를 만드는 것은 거의 확실히 앱을 만드는데 있어서 필요한 작업이 -아닐 수 있으며, 심지어 "제품 등급"의 애플리케이션이라도 필요하지 않습니다. -`electron-packager` 또는 `electron-builder`와 같은 도구를 사용하면 다른 특별한 -과정 없이 Electron을 "Rebrand" 할 수 있습니다. - -업스트림 단에서 추가될 수 없는 기능이나 이미 공식 버전에서 거부된 기능을 Electron에 -직접적으로 패치하기 위해 커스텀 C++를 추가해야 한다면 Electron을 포크해야 합니다. -Electron의 개발자로써, Electron을 매우 많은 시나리오에서도 작동하도록 만들려고 -합니다. 따라서 가능한한 변경 사항을 공식 버전의 Electron에 추가할 수 있도록 시도해 -주길 바라며, 당신에겐 아주 아주 쉬운 작업일 것이고 이러한 당신의 도움에 대해 감사하게 -생각합니다. - -#### surf-build와 함께 커스텀 릴리즈 만들기 - -1. npm을 통해 [Surf](https://github.com/surf-build/surf)를 설치합니다: - `npm install -g surf-build@latest` - -2. 새로운 S3 bucket을 만들고 다음과 같은 빈 디렉토리 구조를 만듭니다: - -``` -- atom-shell/ - - symbols/ - - dist/ -``` - -3. 다음의 환경 변수들을 설정합니다: - - * `ELECTRON_GITHUB_TOKEN` - GitHub에 릴리즈를 만들 수 있는 토큰. - * `ELECTRON_S3_ACCESS_KEY`, `ELECTRON_S3_BUCKET`, `ELECTRON_S3_SECRET_KEY` - - node.js 헤더 뿐만 아니라 심볼을 업로드할 장소. - * `ELECTRON_RELEASE` - `true`로 지정하고 업로드 부분이 실행되면, 설정되지 않은 - 부분을 남기고 `surf-build`가 CI-type 확인을 실행합니다. 모든 pull request를 - 실행할 때 적합합니다. - * `CI` - `true` 또는 다른 것을 지정하면 실패합니다. - * `GITHUB_TOKEN` - `ELECTRON_GITHUB_TOKEN`와 같게 설정 - * `SURF_TEMP` - Windows에선 `C:\Temp`로 설정하면 긴 경로 문제를 해결할 수 있습니다. - * `TARGET_ARCH` - `ia32` 또는 `x64`를 지정. - -4. Electron에 기여를 하는 기여자라면, _반드시_ `script/upload.py`에서 포크를 위해 - `ELECTRON_REPO`를 설정해야 합니다. (`MYORG/electron`) - -5. `surf-build -r https://github.com/MYORG/electron -s YOUR_COMMIT -n 'surf-PLATFORM-ARCH'` - -6. 빌드가 완료될 때까지 아주 아주 긴 시간을 기다립니다. diff --git a/docs-translations/ko-KR/tutorial/application-packaging.md b/docs-translations/ko-KR/tutorial/application-packaging.md deleted file mode 100644 index dd86ab0fc7a17..0000000000000 --- a/docs-translations/ko-KR/tutorial/application-packaging.md +++ /dev/null @@ -1,182 +0,0 @@ -# 애플리케이션 패키징 - -Windows에서 일어나는 긴 경로 이름에 대한 [issues](https://github.com/joyent/node/issues/6960)를 -완화하고 `require` 속도를 약간 빠르게 하며 애플리케이션의 리소스와 소스 코드를 좋지 않은 -사용자로부터 보호하기 위해 애플리케이션을 [asar][asar] 아카이브로 패키징 할 수 있습니다. - -## `asar` 아카이브 생성 - -[asar][asar] 아카이브는 tar과 비슷한 포맷으로 모든 리소스를 하나의 파일로 만듭니다. -그리고 Electron은 압축해제 없이 임의로 모든 파일을 읽어들일 수 있습니다. - -간단한 작업을 통해 애플리케이션을 `asar` 아카이브로 압축할 수 있습니다: - -### 1. asar 유틸리티 설치 - -```bash -$ npm install -g asar -``` - -### 2. `asar pack` 커맨드로 앱 패키징 - -```bash -$ asar pack your-app app.asar -``` - -## `asar` 아카이브 사용하기 - -Electron은 Node.js로부터 제공된 Node API와 Chromium으로부터 제공된 Web API 두 가지 -API를 가지고 있습니다. 따라서 `asar` 아카이브는 두 API 모두 사용할 수 있도록 -지원합니다. - -### Node API - -Electron에선 `fs.readFile`과 `require` 같은 Node API들을 지원하기 위해 `asar` -아카이브가 가상의 디렉터리 구조를 가지도록 패치했습니다. 그래서 아카이브 내부 -리소스들을 정상적인 파일 시스템처럼 접근할 수 있습니다. - -예를 들어 `/path/to`라는 경로에 `example.asar`라는 아카이브가 있다고 가정하면: - -```bash -$ asar list /path/to/example.asar -/app.js -/file.txt -/dir/module.js -/static/index.html -/static/main.css -/static/jquery.min.js -``` - -`asar` 아카이브에선 다음과 같이 파일을 읽을 수 있습니다: - -```javascript -const fs = require('fs'); -fs.readFileSync('/path/to/example.asar/file.txt'); -``` - -아카이브 내의 루트 디렉터리를 리스팅합니다: - -```javascript -const fs = require('fs'); -fs.readdirSync('/path/to/example.asar'); -``` - -아카이브 안의 모듈 사용하기: - -```javascript -require('/path/to/example.asar/dir/module.js'); -``` - -`BrowserWindow` 클래스를 이용해 원하는 웹 페이지도 표시할 수 있습니다: - -```javascript -const {BrowserWindow} = require('electron'); -let win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('file:///path/to/example.asar/static/index.html'); -``` - -### Web API - -웹 페이지 내에선 아카이브 내의 파일을 `file:` 프로토콜을 사용하여 요청할 수 있습니다. -이 또한 Node API와 같이 가상 디렉터리 구조를 가집니다. - -예를 들어 jQuery의 `$.get`을 사용하여 파일을 가져올 수 있습니다: - -```html - -``` - -### `asar` 아카이브를 일반 파일로 취급하기 - -`asar` 아카이브의 체크섬(checksum)을 검사하는 작업등을 하기 위해선 `asar` 아카이브를 -파일 그대로 읽어야 합니다. 이러한 작업을 하기 위해 `original-fs` 빌트인 모듈을 `fs` -모듈 대신에 사용할 수 있습니다. 이 모듈은 `asar` 지원이 빠져있습니다. 즉 파일 그대로를 -읽어들입니다: - -```javascript -const originalFs = require('original-fs'); -originalFs.readFileSync('/path/to/example.asar'); -``` - -또한 `process.noAsar`를 `true`로 지정하면 `fs` 모듈의 `asar` 지원을 비활성화 시킬 수 -있습니다. - -```javascript -process.noAsar = true; -fs.readFileSync('/path/to/example.asar'); -``` - -## Node API의 한계 - -`asar` 아카이브를 Node API가 최대한 디렉터리 구조로 작동하도록 노력해왔지만 여전히 -저수준(low-level nature) Node API 때문에 한계가 있습니다. - -### 아카이브는 읽기 전용입니다 - -아카이브는 수정할 수 없으며 기본적으로는 Node API로 파일을 수정할 수 있지만 `asar` -아카이브에선 작동하지 않습니다. - -### 아카이브 안의 디렉터리를 작업 경로로 설정하면 안됩니다 - -`asar` 아카이브는 디렉터리처럼 사용할 수 있도록 구현되었지만 그것은 실제 파일시스템의 -디렉터리가 아닌 가상의 디렉터리입니다. 그런 이유로 몇몇 API에서 지원하는 `cwd` 옵션을 -`asar` 아카이브 안의 디렉터리 경로로 지정하면 나중에 문제가 발생할 수 있습니다. - -### 특정 API로 인한 예외적인 아카이브 압축 해제 - -많은 `fs` API가 `asar` 아카이브의 압축을 해제하지 않고 바로 아카이브를 읽거나 정보를 -가져올 수 있으나 몇몇 API는 시스템의 실제 파일의 경로를 기반으로 작동하므로 Electron은 -API가 원할하게 작동할 수 있도록 임시 경로에 해당되는 파일의 압축을 해제합니다. 이 작업은 -약간의 오버헤드를 불러 일으킬 수 있습니다. - -위 예외에 해당하는 API 메서드는 다음과 같습니다: - -* `child_process.execFile` -* `child_process.execFileSync` -* `fs.open` -* `fs.openSync` -* `process.dlopen` - Used by `require` on native modules - -### `fs.stat`의 모조된(예측) 스테이터스 정보 - -`fs.stat` 로부터 반환되는 `Stats` 객체와 비슷한 API들은 `asar` 아카이브를 타겟으로 -할 경우 예측된 디렉터리 파일 정보를 가집니다. 왜냐하면 아카이브의 디렉터리 경로는 실제 -파일 시스템에 존재하지 않기 때문입니다. 그러한 이유로 파일 크기와 파일 타입 등을 확인할 -때 `Stats` 객체를 신뢰해선 안됩니다. - -### `asar` 아카이브 내부의 바이너리 실행 - -Node API에는 `child_process.exec`, `child_process.spawn` 그리고 -`child_process.execFile`와 같은 바이너리를 실행시킬 수 있는 API가 있습니다. 하지만 -`asar` 아카이브 내에선 `execFile` API만 사용할 수 있습니다. - -이 한계가 존재하는 이유는 `exec`와 `spawn`은 `file` 대신 `command`를 인수로 허용하고 -있고 `command`는 shell에서 작동하기 때문입니다. Electron은 어떤 커맨드가 `asar` -아카이브 내의 파일을 사용하는지 결정하는데 적절한 방법을 가지고 있지 않으며, 심지어 -그게 가능하다고 해도 부작용 없이 명령 경로를 대체할 수 있는지에 대해 확실히 알 수 있는 -방법이 없습니다. - -## `asar` 아카이브에 미리 압축 해제된 파일 추가하기 - -전술한 바와 같이 몇몇 Node API는 호출 시 해당 파일을 임시폴더에 압축을 해제합니다. -이 방법은 성능문제가 발생할 수 있습니다. 그리고 설계상 백신 소프트웨어에서 잘못 진단하여 -바이러스로 진단 할 수도 있습니다. - -이 문제를 해결하려면 `--unpack` 옵션을 통해 파일을 압축이 풀려진 상태로 유지해야 합니다. -다음의 예시는 node 네이티브 모듈의 공유 라이브러리를 압축이 풀려진 상태로 유지합니다: - -```bash -$ asar pack app app.asar --unpack *.node -``` - -커맨드를 실행한 후 같은 디렉터리에 `app.asar` 파일 외에 `app.asar.unpacked` 폴더가 -같이 생성됩니다. 이 폴더안에 unpack 옵션에서 설정한 파일들이 압축이 풀려진 상태로 -포함되어 있습니다. 사용자에게 애플리케이션을 배포할 때 반드시 해당 폴더도 같이 배포해야 -합니다. - -[asar]: https://github.com/electron/asar diff --git a/docs-translations/ko-KR/tutorial/debugging-main-process.md b/docs-translations/ko-KR/tutorial/debugging-main-process.md deleted file mode 100644 index fc6fee619b6db..0000000000000 --- a/docs-translations/ko-KR/tutorial/debugging-main-process.md +++ /dev/null @@ -1,80 +0,0 @@ -# 메인 프로세스 디버깅하기 - -브라우저 창의 개발자 도구는 웹 페이지 같은 렌더러 프로세스의 스크립트만 디버깅이 -가능합니다. 대신 Electron은 메인 프로세스의 디버깅을 위해 `--debug` 과 `--debug-brk` -스위치들을 제공합니다. - -## 커맨드 라인 스위치(command line switches) - -다음 스위치들을 사용하여 Electron의 메인 프로세스를 디버깅 할 수 있습니다: - -### `--debug=[port]` - -이 스위치를 사용하면 Electron은 지정한 `port`에 V8 디버거 프로토콜을 리스닝합니다. -기본 `port`는 `5858` 입니다. - -### `--debug-brk=[port]` - -`--debug`와 비슷하지만 스크립트의 첫번째 라인에서 일시정지합니다. - -## node-inspector로 디버깅 하기 - -**참고:** Electron은 현재 node-inspector 유틸리티와 호환성 문제가 있습니다. 이러한 -이유로 node-inspector 콘솔 내에서 메인 프로세스의 `process` 객체를 탐색할 경우 크래시가 -발생할 수 있습니다. - -### 1. [node-gyp 필수 도구][node-gyp-required-tools] 설치 - -### 2. [node-inspector][node-inspector] 설치 - -```bash -$ npm install node-inspector -``` - -### 3. [node-pre-gyp][node-pre-gyp] 설치 - -```bash -$ npm install node-pre-gyp -``` - -### 4. Electron용 `node-inspector` `v8` 모듈을 재 컴파일 - -**참고:** target 인수를 사용하는 Electron의 버전에 맞춰 변경하세요. - -```bash -$ node_modules/.bin/node-pre-gyp --target=1.2.5 --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall -$ node_modules/.bin/node-pre-gyp --target=1.2.5 --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall -``` - -또한 [네이티브 모듈을 사용하는 방법][how-to-install-native-modules] 문서도 참고해보세요. - -### 5. Electron 디버그 모드 활성화 - -다음과 같이 debung 플래그로 Electron을 실행할 수 있습니다: - -```bash -$ electron --debug=5858 your/app -``` - -또는 스크립트 첫번째 라인에서 일시 정지할 수 있습니다: - -```bash -$ electron --debug-brk=5858 your/app -``` - -### 6. Electron을 사용하는 [node-inspector][node-inspector] 시작하기 - -```bash -$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js -``` - -### 7. 디버거 UI 로드 - -Chrome 브라우저에서 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 주소에 -접속합니다. (기본 포트 또는 지정한 포트로 접속) 엔트리의 라인이 `debug-brk`로 시작하는 -경우 일시정지 버튼을 클릭해야 할 수도 있습니다. - -[node-inspector]: https://github.com/node-inspector/node-inspector -[node-pre-gyp]: https://github.com/mapbox/node-pre-gyp -[node-gyp-required-tools]: https://github.com/nodejs/node-gyp#installation -[how-to-install-native-modules]: using-native-node-modules.md#네이티브-모듈을-설치하는-방법 diff --git a/docs-translations/ko-KR/tutorial/desktop-environment-integration.md b/docs-translations/ko-KR/tutorial/desktop-environment-integration.md deleted file mode 100644 index 2f9ac97a493e4..0000000000000 --- a/docs-translations/ko-KR/tutorial/desktop-environment-integration.md +++ /dev/null @@ -1,355 +0,0 @@ -# 데스크톱 환경 통합 - -애플리케이션 배포의 대상이 되는 서로 다른 운영체제 시스템의 환경에 맞춰 애플리케이션의 -기능을 통합할 수 있습니다. 예를 들어 Windows에선 태스크바의 JumpList에 바로가기를 -추가할 수 있고 Mac(macOS)에선 dock 메뉴에 커스텀 메뉴를 추가할 수 있습니다. - -이 문서는 Electron API를 이용하여 각 운영체제 시스템의 기능을 활용하는 방법을 -설명합니다. - -## 데스크톱 알림 (Windows, Linux, macOS) - -Windows, Linux, macOS 운영체제 모두 기본적으로 애플리케이션에서 유저에게 알림을 보내는 -방법을 제공합니다. Electron은 [HTML5 Notification API](https://notifications.spec.whatwg.org/)를 -통해 개발자가 편리하게 데스크톱 알림을 사용할 수 있는 기능을 제공합니다. 데스크톱 알림은 -운영체제의 네이티브 알림 API를 사용하여 표시합니다. - -**참고:** 이 API는 HTML5 API이기 때문에 렌더러 프로세스에서만 사용할 수 있습니다. - -```javascript -let myNotification = new Notification('Title', { - body: 'Lorem Ipsum Dolor Sit Amet' -}); - -myNotification.onclick = () => { - console.log('Notification clicked'); -}; -``` - -위 코드를 통해 생성한 데스크톱 알림은 각 운영체제 모두 비슷한 사용자 경험을 제공하지만, -하지만 몇 가지 다른 점들이 있습니다. - -### Windows - -* Windows 10에선 "아무 문제 없이 잘" 작동합니다. -* Windows 8.1과 8에선 [Application User Model ID][app-user-model-id]로 바로가기를 - 만들어 놔야 합니다. 이 바로가기는 반드시 시작 화면에 설치되어 있어야 합니다. 참고로 - 반드시 시작 화면에 고정 할 필요는 없습니다. -* Windows 7과 그 이하 버전은 데스크톱 알림을 지원하지 않습니다. - 혹시 "풍선 팝업 알림" 기능을 찾는다면 [Tray API][tray-balloon]를 사용하세요. - -또한 알림 본문의 최대 길이는 250자 입니다. Windows 개발팀에선 알림 문자열을 200자 -이하로 유지하는 것을 권장합니다. - -### Linux - -데스크톱 알림의 구현으로 `libnotify`를 사용합니다. 따라서 [Desktop Notifications Specification][notification-spec]을 -따르는 모든 데스크탑 환경에서 데스크톱 알림 기능을 사용할 수 있습니다. Cinnamon, -Enlightenment, Unity, GNOME, KDE등을 지원합니다. - -### macOS - -macOS에서의 데스크톱 알림은 아주 직관적입니다. 하지만 데스크톱 알림을 사용할 땐 -[Apple's Human Interface guidelines regarding notifications](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html) -가이드를 고려해야 합니다. - -참고로 데스크롭 알림의 최대 길이는 256 바이트 입니다. 길이가 초과할 경우 초과한 글자가 -잘립니다. - -## 최근 사용한 문서 (Windows & macOS) - -Windows와 macOS는 JumpList 또는 dock 메뉴를 통해 최근 문서 리스트에 쉽게 접근할 수 -있습니다. - -__JumpList:__ - -![JumpList 최근 문서](http://i.msdn.microsoft.com/dynimg/IC420538.png) - -__애플리케이션 dock menu:__ - - - -파일을 최근 문서에 추가하려면 [app.addRecentDocument][addrecentdocument] API를 -사용할 수 있습니다: - -```javascript -app.addRecentDocument('/Users/USERNAME/Desktop/work.type'); -``` - -그리고 [app.clearRecentDocuments][clearrecentdocuments] API로 최근 문서 리스트를 -비울 수 있습니다: - -```javascript -app.clearRecentDocuments(); -``` - -### Windows에서 주의할 점 - -이 기능을 Windows에서 사용할 땐 운영체제 시스템에 애플리케이션에서 사용하는 파일 -확장자가 등록되어 있어야 합니다. 그렇지 않은 경우 파일을 JumpList에 추가해도 추가되지 -않습니다. 애플리케이션 등록에 관련된 API의 모든 내용은 [Application Registration][app-registration]에서 -찾아볼 수 있습니다. - -유저가 JumpList에서 파일을 클릭할 경우 클릭된 파일의 경로가 커맨드 라인 인수로 추가되어 -새로운 인스턴스의 애플리케이션이 실행됩니다. - -### macOS에서 주의할 점 - -파일이 최근 문서 메뉴에서 요청될 경우 `app` 모듈의 `open-file` 이벤트가 호출됩니다. - -## 커스텀 독 메뉴 (macOS) - -macOS는 개발자가 dock에 커스텀 메뉴를 만들 수 있도록 허용하고 있습니다. -보통 애플리케이션의 특정 기능 바로가기를 만들 때 사용합니다: - -__Terminal.app의 dock menu:__ - - - -커스텀 dock menu를 설정하려면 `app.dock.setMenu` API를 사용하면 됩니다. -macOS에서만 사용 가능합니다: - -```javascript -const {app, Menu} = require('electron'); - -const dockMenu = Menu.buildFromTemplate([ - {label: 'New Window', click() { console.log('New Window'); }}, - {label: 'New Window with Settings', submenu: [ - {label: 'Basic'}, - {label: 'Pro'} - ]}, - {label: 'New Command...'} -]); - -app.dock.setMenu(dockMenu); -``` - -## 사용자 작업 (Windows) - -Windows에선 JumpList의 `Tasks` 카테고리에 원하는 작업을 설정할 수 있습니다. -MSDN에선 해당 기능을 다음과 같이 설명하고 있습니다: - -> 애플리케이션 작업은 프로그램의 기능 그리고 주요사양 두가지를 기반으로 유저의 행동을 -> 예측하여 정의합니다. 실행할 필요가 없는 애플리케이션 작업은 작동하지 않을 때 반드시 -> context-free를 유지해야 합니다. 작업은 일반 사용자가 프로그램을 실행하거나 이메일 -> 프로그램으로 이메일을 작성하거나 달력을 불러오고, 워드 프로세서로 새 문서를 작성, -> 특정 모드, 부속 명령으로 프로그램을 실행하는 등의 통계적, 일반적으로 가장 많이 -> 사용되는 작업인지를 고려해야 합니다. 애플리케이션 작업은 일반 유저가 필요로 하지 -> 않는 고급 기능을 조잡하게 채우거나 등록과 같은 일회성의 작업을 포함해선 안됩니다. -> 또한 작업에 특별 이벤트 또는 업그레이드 등의 홍보성 작업을 추가하면 안됩니다. -> -> 작업 리스트는 가능한 한 정적으로 유지되는 것을 적극 권장합니다. -> 이것은 동일한 상태 또는 응용 프로그램의 상태에 관계없이 유지되어야 합니다. -> 작업 목록은 동적으로 변경할 수 있지만 몇몇 유저는 예상하지 못한 작업 목록 변경에 -> 혼란을 일으킬 수 있다는 점을 고려해야 합니다. - -__Internet Explorer의 작업:__ - -![IE](http://i.msdn.microsoft.com/dynimg/IC420539.png) - -macOS의 dock menu(진짜 메뉴)와는 달리 Windows의 사용자 작업은 애플리케이션 바로 -가기처럼 작동합니다. 유저가 작업을 클릭할 때 설정한 인수와 함께 새로운 애플리케이션이 -실행됩니다. - -사용자 작업을 설정하려면 [app.setUserTasks][setusertaskstasks] 메서드를 통해 구현할 -수 있습니다: - -```javascript -app.setUserTasks([ - { - program: process.execPath, - arguments: '--new-window', - iconPath: process.execPath, - iconIndex: 0, - title: 'New Window', - description: 'Create a new window' - } -]); -``` - -작업 리스트를 비우려면 간단히 `app.setUserTasks` 메서드의 첫번째 인수에 빈 배열을 넣어 -호출하면 됩니다: - -```javascript -app.setUserTasks([]); -``` - - -사용자 작업 리스트는 애플리케이션이 삭제되지 않는 한 종료되어도 태스크바에 보존됩니다. -이러한 이유로 반드시 프로그램 경로와 아이콘 경로를 지정해야 합니다. - -## 미리보기 툴바 - -Windows에선 작업 표시줄의 애플리케이션 선택시 나오는 미리보기에 특정한 미리보기 툴바를 -추가할 수 있습니다. 이 기능은 유저가 윈도우를 활성화 하지 않고 특정한 커맨드를 실행시킬 -수 있도록 할 수 있습니다. - -MSDN의 설명에 의하면: - -> 이 툴바는 표준 툴바의 공통 컨트롤과 비슷한 역할을 합니다. 버튼은 최대 7개 까지 -> 만들 수 있습니다. 각 버튼의 구조엔 ID, 이미지, 툴팁, 상태 등이 정의되어있습니다. -> 작업표시줄에 구조가 전달되면 애플리케이션이 상태에 따라 버튼을 숨기거나, 활성화하거나, -> 비활성화 할 수 있습니다. -> -> 예를 들어, 윈도우 미디어 플레이어는(WMP) 미디어 플레이어가 공통적으로 사용하는 -> 재생, 일시정지, 음소거, 정지등의 컨트롤을 포함하고 있습니다. - -__Windows Media Player의 미리보기 툴바:__ - -![player](https://i-msdn.sec.s-msft.com/dynimg/IC420540.png) - -[BrowserWindow.setThumbarButtons][setthumbarbuttons] API를 통해 애플리케이션에 -미리보기 툴바를 설정할 수 있습니다: - -```javascript -const {BrowserWindow} = require('electron'); -const path = require('path'); - -let win = new BrowserWindow({ - width: 800, - height: 600 -}); - -win.setThumbarButtons([ - { - tooltip: 'button1', - icon: path.join(__dirname, 'button1.png'), - click() { console.log('button1 clicked'); } - }, - { - tooltip: 'button2', - icon: path.join(__dirname, 'button2.png'), - flags:['enabled', 'dismissonclick'], - click() { console.log('button2 clicked.'); } - } -]); -``` - -미리보기 툴바를 비우려면 간단히 `BrowserWindow.setThumbarButtons` API에 빈 배열을 -전달하면 됩니다: - -```javascript -win.setThumbarButtons([]); -``` - -## Unity 런처 숏컷 기능 (Linux) - -Unity 환경에선 `.desktop` 파일을 수정함으로써 런처에 새로운 커스텀 엔트리를 추가할 수 -있습니다. [Adding Shortcuts to a Launcher][unity-launcher] 가이드를 참고하세요. - -__Audacious의 런처 숏컷:__ - -![audacious](https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles?action=AttachFile&do=get&target=shortcuts.png) - -## 작업 표시줄 안의 프로그래스 바 (Windows, macOS, Unity) - -Windows에선 작업 표시줄의 애플리케이션 버튼에 프로그래스 바를 추가할 수 있습니다. -이 기능은 사용자가 애플리케이션의 창을 열지 않고도 애플리케이션의 작업의 상태 정보를 -시각적으로 보여줄 수 있도록 해줍니다. - -macOS에선 프로그래스바가 dock 아이콘의 일부에 표시됩니다. - -또한 Unity DE도 런처에 프로그래스 바를 부착할 수 있습니다. - -__작업 표시줄 버튼의 프로그래스 바:__ - -![Taskbar Progress Bar](https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png) - -이 기능은 [BrowserWindow.setProgressBar][setprogressbar] API를 사용하여 구현할 수 -있습니다: - -```javascript -let win = new BrowserWindow({...}); -win.setProgressBar(0.5); -``` - -## 작업 표시줄의 아이콘 오버레이 (Windows) - -Windows에선 작업 표시줄 버튼에 애플리케이션의 상태를 표시하는 작은 오버레이를 사용할 -수 있습니다. MSDN에서 인용하자면 (영문): - -> Icon overlays serve as a contextual notification of status, and are intended -> to negate the need for a separate notification area status icon to communicate -> that information to the user. For instance, the new mail status in Microsoft -> Outlook, currently shown in the notification area, can now be indicated -> through an overlay on the taskbar button. Again, you must decide during your -> development cycle which method is best for your application. Overlay icons are -> intended to supply important, long-standing status or notifications such as -> network status, messenger status, or new mail. The user should not be -> presented with constantly changing overlays or animations. - -__작업 표시줄 버튼 위의 오버레이:__ - -![작업 표시줄 버튼 위의 오버레이](https://i-msdn.sec.s-msft.com/dynimg/IC420441.png) - -윈도우에 오버레이 아이콘을 설정하려면 [BrowserWindow.setOverlayIcon][setoverlayicon] -API를 사용할 수 있습니다: - -```javascript -let win = new BrowserWindow({...}); -win.setOverlayIcon('path/to/overlay.png', 'Description for overlay'); -``` - -## 대표 파일 제시 (macOS) - -macOS는 창에서 대표 파일을 설정할 수 있습니다. 타이틀바에서 파일 아이콘이 있고, 사용자가 -Command-Click 또는 Control-Click 키를 누를 경우 파일 경로 팝업이 보여집니다. 또한 -창의 상태도 지정할 수 있습니다. 다시 말해 로드된 문서의 수정 여부를 제목의 파일 -아이콘에 표시할 수 있습니다. - -__대표 파일 팝업 메뉴:__ - - - -대표 파일 관련 API는 [BrowserWindow.setRepresentedFilename][setrepresentedfilename] 과 -[BrowserWindow.setDocumentEdited][setdocumentedited]를 사용할 수 있습니다: - -```javascript -let win = new BrowserWindow({...}); -win.setRepresentedFilename('/etc/passwd'); -win.setDocumentEdited(true); -``` - -## 파일을 윈도우 밖으로 드래그할 수 있도록 만들기 - -파일을 조작하는 특정 종류의 애플리케이션들에서 파일을 Electron에서 다른 애플리케이션으로 -드래그할 수 있는 기능은 중요합니다. 이 기능을 구현하려면 애플리케이션에서 -`ondragstart` 이벤트가 발생했을 때 `webContents.startDrag(item)` API를 호출해야 -합니다: - -웹 페이지에서: - -```html -item - -``` - -메인 프로세스에서: - -```javascript -ipcMain.on('ondragstart', (event, filePath) => { - event.sender.startDrag({ - file: filePath, - icon: '/path/to/icon.png' - }) -}) -``` - -[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows -[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments-os-x-windows -[setusertaskstasks]: ../api/app.md#appsetusertaskstasks-windows -[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress -[setoverlayicon]: ../api/browser-window.md#winsetoverlayiconoverlay-description-windows-7 -[setrepresentedfilename]: ../api/browser-window.md#winsetrepresentedfilenamefilename-os-x -[setdocumentedited]: ../api/browser-window.md#winsetdocumenteditededited-os-x -[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx -[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher -[setthumbarbuttons]: ../api/browser-window.md#winsetthumbarbuttonsbuttons-windows-7 -[tray-balloon]: ../api/tray.md#traydisplayballoonoptions-windows -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx -[notification-spec]: https://developer.gnome.org/notification-spec/ diff --git a/docs-translations/ko-KR/tutorial/devtools-extension.md b/docs-translations/ko-KR/tutorial/devtools-extension.md deleted file mode 100644 index 2640b02a6cb2a..0000000000000 --- a/docs-translations/ko-KR/tutorial/devtools-extension.md +++ /dev/null @@ -1,59 +0,0 @@ -# 개발자 도구 확장 기능 - -애플리케이션의 디버깅을 쉽게 하기 위해 Electron은 기본적으로 -[Chrome DevTools Extension][devtools-extension]을 지원합니다. - -Electron은 유명한 웹 프레임워크를 디버깅하기 위해 사용할 수 있는 개발자 도구 확장 -기능을 사용할 수 있도록 [Chrome 개발자 도구 확장 기능][devtools-extension]을 -지원합니다. - -## 개발자 도구는 어떻게 로드하나요 - -Electron에 확장 기능을 로드하려면, Chrome 브라우저에서 다운로드 해야 하며, 파일 시스템 경로를 지정해야 합니다. 그리고 `BrowserWindow.addDevToolsExtension(extension)`를 호출함으로써 기능을 로드할 수 있습니다. - -예시로 [React Developer Tools][react-devtools]를 사용한다면: - -1. Chrome 브라우저를 설치합니다. -2. `chrome://extensions`로 이동한 후 해시된 `fmkadmapgofadopljbjfkapdkoienihi` - 같이 생긴 확장 기능의 ID를 찾습니다. -3. Chrome에서 사용하는 확장 기능을 저장해둔 파일 시스템 경로를 찾습니다: - * Windows에선 `%LOCALAPPDATA%\Google\Chrome\User Data\Default\Extensions`; - * Linux에선: - * `~/.config/google-chrome/Default/Extensions/` - * `~/.config/google-chrome-beta/Default/Extensions/` - * `~/.config/google-chrome-canary/Default/Extensions/` - * `~/.config/chromium/Default/Extensions/` - * macOS에선 `~/Library/Application Support/Google/Chrome/Default/Extensions`. -4. 확장 기능의 경로를 `BrowserWindow.addDevToolsExtension` API로 전달합니다. - React Developer Tools의 경우 다음과 비슷해야 합니다: - `~/Library/Application Support/Google/Chrome/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/0.14.10_0` - -확장 기능의 이름은 `BrowserWindow.addDevToolsExtension`에서 반환되며, 이 이름을 -`BrowserWindow.removeDevToolsExtension` API로 전달함으로써 해당하는 확장 기능을 -언로드할 수 있습니다. - -## 지원하는 개발자 도구 확장 기능 - -Electron은 아주 제한적인 `chrome.*` API만을 지원하므로 확장 기능이 지원하지 않는 -`chrome.*` API를 사용한다면 해당 기능은 작동하지 않을 것입니다. 다음 개발자 도구들은 -Electron에서 정상적으로 작동하는 것을 확인했으며 작동 여부를 보장할 수 있는 확장 -기능입니다: - -* [Ember Inspector](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi) -* [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi) -* [Backbone Debugger](https://chrome.google.com/webstore/detail/backbone-debugger/bhljhndlimiafopmmhjlgfpnnchjjbhd) -* [jQuery Debugger](https://chrome.google.com/webstore/detail/jquery-debugger/dbhhnnnpaeobfddmlalhnehgclcmjimi) -* [AngularJS Batarang](https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk) -* [Vue.js devtools](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd) - -### 개발자 도구가 작동하지 않을 때 어떻게 해야 하나요? - -먼저 해당 확장 기능이 확실히 계속 유지되고 있는지를 확인하세요. 몇몇 확장 기능들은 -최신 버전의 Chrome 브라우저에서도 작동하지 않습니다. 그리고 이러한 확장 기능에 대해선 -Electron 개발팀에 해줄 수 있는 것이 아무것도 없습니다. - -위와 같은 상황이 아니라면 Electron의 이슈 리스트에 버그 보고를 추가한 후 예상한 것과 -달리 확장 기능의 어떤 부분의 정상적으로 작동하지 않았는지 설명하세요. - -[devtools-extension]: https://developer.chrome.com/extensions/devtools -[react-devtools]: https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi diff --git a/docs-translations/ko-KR/tutorial/electron-versioning.md b/docs-translations/ko-KR/tutorial/electron-versioning.md deleted file mode 100644 index 0bf5b103ec8d4..0000000000000 --- a/docs-translations/ko-KR/tutorial/electron-versioning.md +++ /dev/null @@ -1,20 +0,0 @@ -# Electron 버전 관리 - -노련한 Node 개발자라면, `semver` (유의적 버전)에 대해 확실히 알고 있을 것입니다 - -그리고 제공된 의존성 관리 시스템은 고정된 버전 숫자 대신 견고한 가이드라인을 따릅니다. -Electron은 Node와 Chromium에 큰 의존성을 지니고 있는 만큼, 유의적 버전을 그대로 -따르지 않습니다. 따라서 항상 Electron의 특정 버전을 참조해야 합니다. - -버전 숫자는 다음과 같은 규칙으로 올라갑니다: - -* Major: Electron API의 주요 변경 사항을 반영합니다 - 만약 `0.37.0`에서 `1.0.0`로 - 업그레이드하는 경우, 애플리케이션을 업데이트해야 합니다. -* Minor: 주요 Chrome과 Node 버전의 업그레이드를 반영하거나; Electron의 중요한 변경 - 사항을 반영합니다 - 만약 `1.0.0`에서 `1.1.0`로 업그레이드하는 경우, 애플리케이션은 - 여전히 작동하겠지만, 약간의 업데이트가 필요할 수 있습니다. -* Patch: 새로운 기능과 버그 수정을 반영합니다 - 만약 `1.0.0`에서 `1.0.1`로 - 업그레이드하는 경우, 애플리케이션은 잘 작동할 것입니다. - -`electron-prebuilt`를 사용하고 있다면, Electron의 변경 사항을 확실하게 인지하고 -개발자 스스로 업그레이드를 적용하기 위해 고정된 버전 숫자를 사용하는 것을 권장합니다. -(`^1.1.0` 대신 `1.1.0` 사용) diff --git a/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md b/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md deleted file mode 100644 index 370f31d774905..0000000000000 --- a/docs-translations/ko-KR/tutorial/mac-app-store-submission-guide.md +++ /dev/null @@ -1,240 +0,0 @@ -# Mac 앱 스토어 애플리케이션 제출 가이드 - -Electron은 v0.34.0 버전부터 앱 패키지를 Mac App Store(MAS)에 제출할 수 있게 -되었습니다. 이 가이드는 애플리케이션을 앱 스토어에 등록하는 방법과 빌드의 한계에 대한 -설명을 제공합니다. - -**참고:** Mac App Store에 애플리케이션을 등록하려면 -[Apple Developer Program][developer-program]에 등록되어 있어야 하며 비용이 발생할 -수 있습니다. - -## 앱 스토어에 애플리케이션을 등록하는 방법 - -다음 몇 가지 간단한 절차에 따라 앱 스토어에 애플리케이션을 등록하는 방법을 알아봅니다. -한가지, 이 절차는 제출한 앱이 Apple로부터 승인되는 것을 보장하지 않습니다. 따라서 -여전히 Apple의 [Submitting Your App][submitting-your-app] 가이드를 숙지하고 있어야 -하며 앱 스토어 제출 요구 사항을 확실히 인지하고 있어야 합니다. - -### 인증서 취득 - -앱 스토어에 애플리케이션을 제출하려면, 먼저 Apple로부터 인증서를 취득해야 합니다. 취득 -방법은 웹에서 찾아볼 수 있는 [가이드][nwjs-guide]를 참고하면 됩니다. - -### Team ID 얻기 - -애플리케이션에 서명하기 전에, 먼저 개발 계정의 Team ID를 알아야 합니다. Team ID를 -알아보려면 [Apple Developer Center](https://developer.apple.com/account/)에 -로그인한 후, 사이드바의 Membership을 클릭합니다. Team ID는 Membership Information -섹션의 팀 이름 밑에 위치합니다. - -### 앱에 서명하기 - -준비 작업이 끝난 후, [애플리케이션 배포](application-distribution.md) 문서에 따라 -애플리케이션을 패키징한 후 애플리케이션에 서명합니다. - -먼저, Team ID를 키로 가지고 있는 애플리케이션의 `Info.plist`에 `ElectronTeamID` 키를 -추가해야 합니다: - -```xml - - - ... - ElectronTeamID - TEAM_ID - - -``` - -그리고, 다음 두 자격 파일을 준비해야 합니다. - -`child.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.inherit - - - -``` - -`parent.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.application-groups - TEAM_ID.your.bundle.id - - -``` - -`TEAM_ID` 부분은 Team ID로 치환하고, `your.bundle.id` 부분은 애플리케이션의 Bundle -ID로 치환해야 합니다. - -그리고 다음 스크립트를 통해 애플리케이션에 서명합니다: - -```bash -#!/bin/bash - -# 애플리케이션의 이름. -APP="YourApp" -# 서명할 애플리케이션의 경로. -APP_PATH="/path/to/YourApp.app" -# 서명된 패키지의 출력 경로. -RESULT_PATH="~/Desktop/$APP.pkg" -# 요청한 인증서의 이름. -APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)" -INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)" -# plist 파일의 경로. -CHILD_PLIST="/path/to/child.plist" -PARENT_PLIST="/path/to/parent.plist" - -FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" - -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/MacOS/$APP" -codesign -s "$APP_KEY" -f --entitlements "$PARENT_PLIST" "$APP_PATH" - -productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" -``` - -만약 macOS의 샌드박스 개념에 대해 처음 접한다면 Apple의 [Enabling App Sandbox][enable-app-sandbox] -문서를 참고하여 기본적인 개념을 이해해야 합니다. 그리고 자격(plist) 파일에 -애플리케이션에서 요구하는 권한의 키를 추가합니다. - - -그 외에 별로도 [electron-osx-sign][electron-osx-sign] 모듈을 사용하여 직접 서명할 -수도 있습니다. - -#### 네이티브 모듈에 서명하기 - -앱 내부에서 사용한 네이티브 모듈도 서명이 필요합니다. `electron-osx-sign`을 -사용한다면, 인수 목록에 빌트인 바이너리 경로가 포함되어 있는지 확인해야 합니다: - -```bash -electron-osx-sign YourApp.app YourApp.app/Contents/Resources/app/node_modules/nativemodule/build/release/nativemodule -``` - -참고로 네이티브 모듈이 의도하지 않게 중간 파일을 포함하는 경우도 있으며 이 파일은 -포함되어선 안됩니다. (해당 파일에도 서명해야 할 수도 있습니다) -[electron-packager][electron-packager]를 사용한다면, 빌드 과정에 `--ignore=.+\.o$` -인수를 추가하여 중간 파일을 무시할 수 있습니다. - -### 애플리케이션 업로드 - -애플리케이션 서명을 완료한 후 iTunes Connect에 업로드하기 위해 Application Loader를 -사용할 수 있습니다. 참고로 업로드하기 전에 [레코드][create-record]를 만들었는지 -확인해야 합니다. - -### 애플리케이션을 심사에 제출 - -위 과정을 마치면 [애플리케이션을 심사를 위해 제출][submit-for-review]할 수 있습니다. - -## MAS 빌드의 한계 - -모든 애플리케이션 샌드박스에 대한 요구 사항을 충족시키기 위해, 다음 모듈들은 MAS -빌드에서 비활성화됩니다: - -* `crashReporter` -* `autoUpdater` - -그리고 다음 동작으로 대체됩니다: - -* 비디오 캡쳐 기능은 몇몇 장치에서 작동하지 않을 수 있습니다. -* 특정 접근성 기능이 작동하지 않을 수 있습니다. -* 애플리케이션이 DNS의 변경을 감지하지 못할 수 있습니다. - -또한 애플리케이션 샌드박스 개념으로 인해 애플리케이션에서 접근할 수 있는 리소스는 -엄격하게 제한되어 있습니다. 자세한 내용은 [앱 샌드박싱][app-sandboxing] 문서를 -참고하세요. - -### 추가적인 권한 - -Mac 앱 스토어 빌드를 위해 앱에서 사용하는 Electron API에 따라 `parent.plist` 파일에 -추가적인 기능에 대한 권한을 추가해야 할 수도 있습니다. - -#### dialog.showOpenDialog - -```xml -com.apple.security.files.user-selected.read-only - -``` - -자세한 내용은 [User-Selected 파일 접근 활성화 문서][user-selected]를 참고하세요. - -#### dialog.showSaveDialog - -```xml -com.apple.security.files.user-selected.read-write - -``` - -자세한 내용은 [User-Selected 파일 접근 활성화 문서][user-selected]를 참고하세요. - -## Electron에서 사용하는 암호화 알고리즘 - -국가와 살고 있는 지역에 따라, 맥 앱스토어는 제출한 애플리케이션에서 사용하는 암호화 -알고리즘의 문서를 요구할 수 있습니다. 심지어 U.S. Encryption Registration (ERN)의 -승인 사본을 제출하라고 할 수도 있습니다. - -Electron은 다음과 같은 암호화 알고리즘을 사용합니다: - -* AES - [NIST SP 800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf), [NIST SP 800-38D](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf), [RFC 3394](http://www.ietf.org/rfc/rfc3394.txt) -* HMAC - [FIPS 198-1](http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf) -* ECDSA - ANS X9.62–2005 -* ECDH - ANS X9.63–2001 -* HKDF - [NIST SP 800-56C](http://csrc.nist.gov/publications/nistpubs/800-56C/SP-800-56C.pdf) -* PBKDF2 - [RFC 2898](https://tools.ietf.org/html/rfc2898) -* RSA - [RFC 3447](http://www.ietf.org/rfc/rfc3447) -* SHA - [FIPS 180-4](http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf) -* Blowfish - https://www.schneier.com/cryptography/blowfish/ -* CAST - [RFC 2144](https://tools.ietf.org/html/rfc2144), [RFC 2612](https://tools.ietf.org/html/rfc2612) -* DES - [FIPS 46-3](http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf) -* DH - [RFC 2631](https://tools.ietf.org/html/rfc2631) -* DSA - [ANSI X9.30](http://webstore.ansi.org/RecordDetail.aspx?sku=ANSI+X9.30-1%3A1997) -* EC - [SEC 1](http://www.secg.org/sec1-v2.pdf) -* IDEA - "On the Design and Security of Block Ciphers" book by X. Lai -* MD2 - [RFC 1319](http://tools.ietf.org/html/rfc1319) -* MD4 - [RFC 6150](https://tools.ietf.org/html/rfc6150) -* MD5 - [RFC 1321](https://tools.ietf.org/html/rfc1321) -* MDC2 - [ISO/IEC 10118-2](https://www.openssl.org/docs/manmaster/crypto/mdc2.html) -* RC2 - [RFC 2268](https://tools.ietf.org/html/rfc2268) -* RC4 - [RFC 4345](https://tools.ietf.org/html/rfc4345) -* RC5 - http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf -* RIPEMD - [ISO/IEC 10118-3](http://webstore.ansi.org/RecordDetail.aspx?sku=ISO%2FIEC%2010118-3:2004) - -ERN의 승인을 얻는 방법은, 다음 글을 참고하는 것이 좋습니다: -[애플리케이션이 암호화를 사용할 때, 합법적으로 Apple의 앱 스토어에 제출하는 방법 (또는 ERN의 승인을 얻는 방법)][ern-tutorial]. - -**역자주:** [Mac 앱 배포 가이드 공식 한국어 문서](https://developer.apple.com/osx/distribution/kr/) - -[developer-program]: https://developer.apple.com/support/compare-memberships/ -[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html -[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps -[enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html -[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html -[electron-osx-sign]: https://github.com/electron-userland/electron-osx-sign -[electron-packager]: https://github.com/electron-userland/electron-packager -[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html -[app-sandboxing]: https://developer.apple.com/app-sandboxing/ -[ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/ -[temporary-exception]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AppSandboxTemporaryExceptionEntitlements.html -[user-selected]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW6] diff --git a/docs-translations/ko-KR/tutorial/online-offline-events.md b/docs-translations/ko-KR/tutorial/online-offline-events.md deleted file mode 100644 index de2e10f9efe93..0000000000000 --- a/docs-translations/ko-KR/tutorial/online-offline-events.md +++ /dev/null @@ -1,82 +0,0 @@ -# 온라인/오프라인 이벤트 감지 - -온라인/오프라인 이벤트는 다음 예시와 같이 렌더러 프로세스에서 표준 HTML5 API를 이용하여 -구현할 수 있습니다. - -_main.js_ - -```javascript -const {app, BrowserWindow} = require('electron'); - -let onlineStatusWindow; - -app.on('ready', () => { - onlineStatusWindow = new BrowserWindow({width: 0, height: 0, show: false}); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` - -메인 프로세스에서 이 이벤트를 처리할 필요가 있는 경우 이벤트를 메인 프로세스로 보낼 수 -있습니다. 메인 프로세스는 `navigator` 객체를 가지고 있지 않기 때문에 이 이벤트를 직접 -사용할 수는 없습니다. - -대신 다음 예시와 같이 Electron의 inter-process communication(ipc) 유틸리티를 -사용하면 이벤트를 메인 프로세스로 전달할 수 있습니다. - -_main.js_ - -```javascript -const {app, ipcMain, BrowserWindow} = require('electron'); - -let onlineStatusWindow; - -app.on('ready', () => { - onlineStatusWindow = new BrowserWindow({width: 0, height: 0, show: false}); - onlineStatusWindow.loadURL(`file://${__dirname}/online-status.html`); -}); - -ipcMain.on('online-status-changed', (event, status) => { - console.log(status); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` diff --git a/docs-translations/ko-KR/tutorial/quick-start.md b/docs-translations/ko-KR/tutorial/quick-start.md deleted file mode 100644 index 7096425a599f9..0000000000000 --- a/docs-translations/ko-KR/tutorial/quick-start.md +++ /dev/null @@ -1,233 +0,0 @@ -# 시작하기 - -## 소개 - -Electron은 자바스크립트와 함께 제공된 풍부한 네이티브 API를 사용하여 멋진 데스크탑 -애플리케이션을 만들 수 있도록 해주는 프레임워크입니다. 이 프레임워크의 Node.js는 웹 -서버 개발이 아닌 데스크탑 애플리케이션 개발에 초점을 맞췄습니다. - -이 말은 Electron이 GUI 라이브러리의 자바스크립트 바인딩이라는 뜻이 아닙니다. 대신, -Electron은 웹 페이지의 GUI를 사용합니다. 쉽게 말해 Electron은 자바스크립트를 사용하여 -조작하는 작은 Chromium 브라우저로 볼 수 있습니다. - -### 메인 프로세스 - -Electron은 실행될 때 __메인 프로세스__ 로 불리는 `package.json`의 `main` 스크립트를 -호출합니다. 이 스크립트는 메인 프로세스에서 작동합니다. GUI 컴포넌트를 조작하거나 웹 -페이지 창을 생성할 수 있습니다. - -### 렌더러 프로세스 - -Electron이 웹페이지를 보여줄 때 Chromium의 multi-processes 구조도 같이 사용됩니다. -Electron 프로세스 내에서 작동하는 웹 페이지를 __렌더러 프로세스__ 라고 불립니다. - -보통 일반 브라우저의 웹 페이지들은 샌드박스가 적용된 환경에서 작동하며 네이티브 -리소스에는 접근할 수 없도록 되어 있습니다. 하지만 Electron은 웹 페이지 내에서 Node.js -API를 사용하여 low-level 수준으로 운영체제와 상호작용할 수 있습니다. - -### 메인 프로세스와 렌더러 프로세스의 차이점 - -메인 프로세스는 `BrowserWindow` Class를 사용하여 새로운 창을 만들 수 있습니다. -`BrowserWindow` 인스턴스는 따로 분리된 프로세스에서 렌더링 되며 이 프로세스를 렌더러 -프로세스라고 합니다. `BrowserWindow` 인스턴스가 소멸할 때 그 창의 렌더러 프로세스도 -같이 소멸합니다. - -메인 프로세스는 모든 웹 페이지와 렌더러 프로세스를 관리하며 렌더러 프로세스는 각각의 -프로세스에 고립되며 웹 페이지의 작동에만 영향을 끼칩니다. - -웹 페이지 내에선 기본적으로 네이티브 GUI와 관련된 API를 호출할 수 없도록 설계 되어 -있습니다. 왜냐하면 웹 페이지 내에서 네이티브 GUI 리소스를 관리하는 것은 보안에 취약하고 -리소스를 누수시킬 수 있기 때문입니다. 꼭 웹 페이지 내에서 API를 사용해야 한다면 메인 -프로세스에서 그 작업을 처리할 수 있도록 메인 프로세스와 통신을 해야 합니다. - -Electron에는 메인 프로세스와 렌더러 프로세스 사이에 통신을 할 수 있도록 -[`ipcRenderer`](../api/ipc-renderer.md)와 [`ipcMain`](../api/ipc-main.md) 모듈을 -제공하고 있습니다. 또는 [remote](../api/remote.md) 모듈을 사용하여 RPC 스타일로 -통신할 수도 있습니다. 또한 FAQ에서 [다양한 객체를 공유하는 방법](share-data)도 -소개하고 있습니다. - -## 첫번째 Electron 앱 만들기 - -보통 Electron 앱은 다음과 같은 폴더 구조를 가집니다: - -```text -your-app/ -├── package.json -├── main.js -└── index.html -``` - -`package.json`은 node 모듈의 package.json과 같습니다. 그리고 `main` 필드에 스크립트 -파일을 지정하면 메인 프로세스의 엔트리 포인트로 사용합니다. 예를 들어 사용할 수 있는 -`package.json`은 다음과 같습니다: - -```json -{ - "name" : "your-app", - "version" : "0.1.0", - "main" : "main.js" -} -``` - -__알림__: 만약 `main` 필드가 `package.json`에 설정되어 있지 않으면 Electron은 -자동으로 같은 디렉터리의 `index.js`를 로드합니다. - -반드시 `main.js`에서 창을 만들고 시스템 이벤트를 처리해야 합니다. 대표적인 예시로 -다음과 같이 작성할 수 있습니다: - -```javascript -const electron = require('electron'); -// 애플리케이션 생명주기를 조작 하는 모듈. -const {app} = electron; -// 네이티브 브라우저 창을 만드는 모듈. -const {BrowserWindow} = electron; - -// 윈도우 객체를 전역에 유지합니다. 만약 이렇게 하지 않으면 -// 자바스크립트 GC가 일어날 때 창이 멋대로 닫혀버립니다. -let win; - -function createWindow () { - // 새로운 브라우저 창을 생성합니다. - win = new BrowserWindow({width: 800, height: 600}); - - // 그리고 현재 디렉터리의 index.html을 로드합니다. - win.loadURL(`file://${__dirname}/index.html`); - - // 개발자 도구를 엽니다. - win.webContents.openDevTools(); - - // 창이 닫히면 호출됩니다. - win.on('closed', () => { - // 윈도우 객체의 참조를 삭제합니다. 보통 멀티 윈도우 지원을 위해 - // 윈도우 객체를 배열에 저장하는 경우가 있는데 이 경우 - // 해당하는 모든 윈도우 객체의 참조를 삭제해 주어야 합니다. - win = null; - }); -} - -// 이 메서드는 Electron의 초기화가 끝나면 실행되며 브라우저 -// 윈도우를 생성할 수 있습니다. 몇몇 API는 이 이벤트 이후에만 -// 사용할 수 있습니다. -app.on('ready', createWindow); - -// 모든 창이 닫히면 애플리케이션 종료. -app.on('window-all-closed', () => { - // macOS의 대부분의 애플리케이션은 유저가 Cmd + Q 커맨드로 확실하게 - // 종료하기 전까지 메뉴바에 남아 계속 실행됩니다. - if (process.platform !== 'darwin') { - app.quit(); - } -}); - -app.on('activate', () => { - // macOS에선 보통 독 아이콘이 클릭되고 나서도 - // 열린 윈도우가 없으면, 새로운 윈도우를 다시 만듭니다. - if (win === null) { - createWindow(); - } -}); - -// 이 파일엔 제작할 애플리케이션에 특화된 메인 프로세스 코드를 -// 포함할 수 있습니다. 또한 파일을 분리하여 require하는 방법으로 -// 코드를 작성할 수도 있습니다. -``` - -마지막으로, 사용자에게 보여줄 `index.html` 웹 페이지의 예시입니다: - -```html - - - - - 헬로 월드! - - -

헬로 월드!

- 이 애플리케이션은 node , - Chrome , - Electron 을 사용합니다. - - -``` - -## 앱 실행하기 - -앱을 작성한 후 [애플리케이션 배포](application-distribution.md) 가이드를 따라 앱을 -패키징 하고 패키징한 앱을 실행할 수 있습니다. 또한 Electron 실행파일을 다운로드 받아 -바로 실행해 볼 수도 있습니다. - -### electron-prebuilt - -[`electron-prebuilt`](https://github.com/electron-userland/electron-prebuilt)는 -Electron의 미리 컴파일된 바이너리를 포함하는 `npm` 모듈입니다. - -만약 `npm`을 통해 전역에 이 모듈을 설치했다면, 애플리케이션 소스 디렉터리에서 다음 -명령을 실행하면 바로 실행할 수 있습니다: - -```bash -electron . -``` - -또는 앱 디렉터리 밖에서 앱을 실행할 수도 있습니다: - -```bash -electron app -``` - -npm 모듈을 로컬에 설치했다면 다음 명령으로 실행할 수 있습니다: - -```bash -./node_modules/.bin/electron . -``` - -### 다운로드 받은 Electron 바이너리 사용 - -따로 Electron 바이너리를 다운로드 받았다면 다음 예시와 같이 실행하면 됩니다. - -#### Windows - -```bash -$ .\electron\electron.exe your-app\ -``` - -#### Linux - -```bash -$ ./electron/electron your-app/ -``` - -#### macOS - -```bash -$ ./Electron.app/Contents/MacOS/Electron your-app/ -``` - -애플리케이션 실행파일은 `Electron`의 release 패키지에 포함되어 있습니다. -[여기](https://github.com/electron/electron/releases)에서 다운로드 받을 수 있습니다. - -### 배포용 실행 파일 만들기 - -애플리케이션 작성을 모두 끝냈다면 [애플리케이션 배포](application-distribution.md) -가이드를 통해 제작한 앱을 패키징하고 배포할 수 있습니다. - -### 미리 작성된 앱 실행하기 - -[`electron/electron-quick-start`](https://github.com/electron/electron-quick-start) -저장소를 클론하면 이 문서에서 작성한 예시 앱을 바로 실행해 볼 수 있습니다. - -**참고**: 이 예시를 실행시키려면 [Git](https://git-scm.com)과 -[Node.js](https://nodejs.org/en/download/)가 필요합니다. (CLI에서 실행 가능한 - [npm](https://npmjs.org)이 있어야 합니다) - -**역자주**: `npm`은 보통 Node.js를 설치하면 자동으로 같이 설치됩니다. - -```bash -# 저장소를 클론합니다 -$ git clone https://github.com/electron/electron-quick-start -# 저장소 안으로 들어갑니다 -$ cd electron-quick-start -# 애플리케이션의 종속성 모듈을 설치한 후 실행합니다 -$ npm install && npm start -``` - -[share-data]: ../faq.md#어떻게-웹-페이지-간에-데이터를-공유할-수-있나요 diff --git a/docs-translations/ko-KR/tutorial/security.md b/docs-translations/ko-KR/tutorial/security.md deleted file mode 100644 index 5a53d2b8bd4c5..0000000000000 --- a/docs-translations/ko-KR/tutorial/security.md +++ /dev/null @@ -1,75 +0,0 @@ -# 보안, 네이티브 호환성, 그리고 신뢰성 - -웹 개발자로써, 우리는 일반적으로 브라우저의 강력한 웹 보안을 잘 이용해왔습니다 - 작성한 -코드에 관련된 보안 문제는 아주 적었습니다. 우리는 웹 사이트의 샌드박스안에서 허용된 -상당히 제한된 권한과 기능에 의존해왔으며, 우리는 새로운 보안 위협에 대해 발 빠르게 -대응할 수 있는 엔지니어들로 이루어진 커다란 팀으로부터 만들어진 브라우저를 사용자들이 -마음 놓고 즐길 것이라고 믿어왔습니다. - -하지만 Electron을 사용하여 작업한다면, Electron은 웹 브라우저가 아니라는 것을 기억해 -두어야 합니다. Electron은 친근한 웹 기술을 사용하여 풍부한 기능의 데스크톱 -애플리케이션을 만들 수 있도록 해주지만 그만큼 코드가 더 큰 힘을 사용합니다. -JavaScript가 파일 시스템, 유저 쉘, 그외 여러가지 기능에 접근할 수 있습니다. 이러한 -능력은 높은 퀄리티를 가진 네이티브 애플리케이션을 개발할 수 있도록 해주지만 코드에 -부여된 추가적인 기능만큼 고유한 보안 문제가 발생할 가능성이 있습니다. - -이를 염두해두고, 신뢰할 수 없는 출처의 임의의 콘텐츠를 표시할 때 Electron에서 -자체적으로 처리하지 않는 심각한 보안 문제를 야기할 수 있다는 점을 주의해야 합니다. -실제로도, 가장 유명한 Electron 애플리케이션들은 (Atom, Slack, Visual Studio Code, -등) 주로 로컬 콘텐츠를 (또는 Node 통합이 제외된 신뢰된, 보안된 원격 콘텐츠) 사용합니다 -- 만약 애플리케이션이 온라인 출처에서 가져온 코드를 실행한다면, 그 코드가 악성 코드가 -아닌지 판별하는 것은 본인의 책임입니다. - -## Chromium 보안 문제와 업그레이드 - -Electron이 새로운 버전의 Chromium을 가능한 한 빠르게 지원하려고 노력하지만, -개발자는 이러한 업그레이딩 작업은 매우 힘든 작업이라는 것을 알아야 합니다 - 각 관련된 -수십에서 심지어 백자리 개수의 파일들을 손수 수정해야 합니다. 주어진 자원과 현재 -기여도를 생각한다면, Electron은 항상 최신 버전의 Chromium을 유지하지 못할 수 있으며, -며칠부터 몇 주까지 더 걸릴 수 있습니다. - -현재 Chromium 구성 요소를 업데이트하는 시스템은 우리가 사용할 수 있는 자원과 이 -프레임워크를 기반으로 구축된 대부분의 애플리케이션이 요구하는 것 사이에서 적절한 균형을 -유지하고 있다고 느끼고 있습니다. 우리는 확실히 Electron 위에 무언가를 만드는 사람들의 -사용 사례에 대한 자세한 내용을 듣는 것에 관심이 있습니다. 이러한 노력을 지원하는 Pull -request와 기여는 언제나 환영합니다. - -## 위 조언 무시하기 - -원격 위치에서 받아온 코드를 로컬에서 실행하는 경우 언제나 보안 문제가 존재합니다. -예를 들어, 원격 웹 사이트가 브라우저 윈도우에서 표시될 때를 생각해볼 때, 만약 공격자가 -어떠한 방법으로 웹 페이지의 콘텐츠를 변경하는 경우 (소스를 직접적으로 공격하거나 -애플리케이션과 실질적인 위치 사이에서 공격하는 등), 공갹자는 사용자의 기기에서 네이티브 -코드를 실행할 수 있습니다. - -> :warning: 어떠한 상황에서도 원격 코드를 로드하고 실행할 땐 Node 통합 기능을 -비활성화하고, 로컬 파일만 (애플리케이션 패키지 내부에 포함된) Node 코드를 실행시킬 수 -있도록 하는 것이 좋습니다. 원격 콘텐츠를 표시할 땐, 항상 `webview`를 사용하고 -`nodeIntegration`이 비활성화되어있는지 확인하세요. - -#### 체크 리스트 - -이 리스트는 완벽하지 않습니다, 하지만 최소한 다음 사항은 확인하는 것이 좋습니다: - -* 보안된 (https) 콘텐츠만 표시합니다. -* 원격 콘텐츠를 표시하는 모든 렌더러에서 Node 통합 기능을 비활성화합니다. - (`webPreferences` 사용) -* `webSecurity`를 비활성화하지 않습니다. 이 옵션을 비활성화하면 동일-출처 정책도 - 비활성화됩니다. -* [`Content-Security-Policy`](http://www.html5rocks.com/en/tutorials/security/content-security-policy/) - 를 정의하고, 한정적인 규칙을 사용하세요 (i.e. `script-src 'self'`) -* 문자열을 코드로 실행할 수 있는 - [`eval`을 덮어쓰고 비활성화](https://github.com/nylas/N1/blob/0abc5d5defcdb057120d726b271933425b75b415/static/index.js#L6-L8)하세요. -* `allowDisplayingInsecureContent`를 `true`로 설정하지 마세요. -* `allowRunningInsecureContent`를 `true`로 설정하지 마세요. -* 무엇을 하고 있는지 확실히 알고 있지않는 이상 `experimentalFeatures` 또는 - `experimentalCanvasFeatures`를 활성화하지 마세요. -* 무엇을 하고 있는지 확실히 알고 있지않는 이상 `blinkFeatures`를 활성화하지 마세요. -* WebViews: `nodeintegration`를 `false`로 설정하세요. -* WebViews: `disablewebsecurity`를 사용하지 마세요. -* WebViews: `allowpopups`를 사용하지 마세요. -* WebViews: 원격 CSS/JS와 `insertCSS` 또는 `executeJavaScript`를 함께 사용하지 - 마세요. - -다시 말하지만, 이 리스트는 그저 위험을 최소화할 뿐이며 완전히 제거하지 않습니다. 만약 -목적이 그저 웹 사이트를 보여주는 것이라면 일반 웹 브라우저가 더 안전한 방법입니다. diff --git a/docs-translations/ko-KR/tutorial/supported-platforms.md b/docs-translations/ko-KR/tutorial/supported-platforms.md deleted file mode 100644 index d2d71c1454e51..0000000000000 --- a/docs-translations/ko-KR/tutorial/supported-platforms.md +++ /dev/null @@ -1,30 +0,0 @@ -# 지원하는 플랫폼 - -Electron에선 다음과 같은 플랫폼을 지원합니다: - -### macOS - -macOS는 64비트 바이너리만 제공됩니다. 그리고 최소 macOS 지원 버전은 10.9입니다. - -### Windows - -Windows 7 이후 버전만 지원됩니다. Windows Vista에서도 작동할 수 있지만 아직 모든 작동 -테스트가 완료되지 않았습니다. - -윈도우용 바이너리는 `x86`과 `x64` 모두 제공됩니다. 그리고 `ARM` 버전 윈도우는 아직 -지원하지 않습니다. - -### Linux - -Ubuntu 12.04 버전에서 빌드된 `ia32`(`i686`), `x64`(`amd64`) 바이너리가 제공됩니다. -그리고 `arm` 버전 바이너리는 ARM v7 hard-float ABI와 Debian Wheezy용 NEON에 맞춰 -제공됩니다. - -미리 빌드된 바이너리가 배포판에서 작동할 수 있는지 여부는 Electron이 빌드된 플랫폼에서 -링크된 라이브러리에 따라 달라집니다. 그래서 현재 Linux 바이너리는 Ubuntu 12.04 버전만 -정상적인 작동이 보장됩니다. 하지만 다음 플랫폼들은 미리 빌드된 Electron 바이너리가 -정상적으로 작동하는 것을 확인했습니다: - -* Ubuntu 12.04 이후 버전 -* Fedora 21 -* Debian 8 diff --git a/docs-translations/ko-KR/tutorial/testing-on-headless-ci.md b/docs-translations/ko-KR/tutorial/testing-on-headless-ci.md deleted file mode 100644 index 42b2e027fd867..0000000000000 --- a/docs-translations/ko-KR/tutorial/testing-on-headless-ci.md +++ /dev/null @@ -1,58 +0,0 @@ -# Headless CI 시스템에서 테스팅하기 (Travis, Jenkins) - -Chromium을 기반으로 한 Electron은 작업을 위해 디스플레이 드라이버가 필요합니다. -만약 Chromium이 디스플레이 드라이버를 찾기 못한다면, Electron은 그대로 실행에 -실패할 것입니다. 따라서 실행하는 방법에 관계없이 모든 테스트를 실행하지 못하게 됩니다. -Electron 기반 애플리케이션을 Travis, Circle, Jenkins 또는 유사한 시스템에서 테스팅을 -진행하려면 약간의 설정이 필요합니다. 요점만 말하자면, 가상 디스플레이 드라이버가 -필요합니다. - -## 가상 디스플레이 드라이버 설정 - -먼저, [Xvfb](https://en.wikipedia.org/wiki/Xvfb)를 설치합니다. 이것은 X11 -디스플레이 서버 프로토콜의 구현이며 모든 그래픽 작업을 스크린 출력없이 인-메모리에서 -수행하는 가상 프레임버퍼입니다. 정확히 우리가 필요로 하는 것입니다. - -그리고, 가상 xvfb 스크린을 생성하고 DISPLAY라고 불리우는 환경 변수를 지정합니다. -Electron의 Chromium은 자동적으로 `$DISPLAY` 변수를 찾습니다. 따라서 앱의 추가적인 -다른 설정이 필요하지 않습니다. 이러한 작업은 Paul Betts의 -[xvfb-maybe](https://github.com/paulcbetts/xvfb-maybe)를 통해 자동화 할 수 -있습니다: `xvfb-maybe`를 테스트 커맨드 앞에 추가하고 현재 시스템에서 요구하면 -이 작은 툴이 자동적으로 xvfb를 설정합니다. Windows와 macOS에선 간단히 아무 작업도 -하지 않습니다. - -``` -## Windows와 macOS에선, 그저 electron-mocha를 호출합니다 -## Linux에선, 현재 headless 환경에 있는 경우 -## xvfb-run electron-mocha ./test/*.js와 같습니다 -xvfb-maybe electron-mocha ./test/*.js -``` - -### Travis CI - -Travis에선, `.travis.yml`이 대충 다음과 같이 되어야 합니다: - -```yml -addons: - apt: - packages: - - xvfb - -install: - - export DISPLAY=':99.0' - - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & -``` - -### Jenkins - -Jenkins는 [Xvfb 플러그인이 존재합니다](https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin). - -### Circle CI - -Circle CI는 멋지게도 이미 xvfb와 `$DISPLY` 변수가 준비되어 있습니다. 따라서 -[추가적인 설정이 필요하지](https://circleci.com/docs/environment#browsers) 않습니다. - -### AppVeyor - -AppVeyor는 Windows에서 작동하기 때문에 Selenium, Chromium, Electron과 그 비슷한 -툴들을 복잡한 과정 없이 모두 지원합니다. - 설정이 필요하지 않습니다. diff --git a/docs-translations/ko-KR/tutorial/using-native-node-modules.md b/docs-translations/ko-KR/tutorial/using-native-node-modules.md deleted file mode 100644 index fb503679c04be..0000000000000 --- a/docs-translations/ko-KR/tutorial/using-native-node-modules.md +++ /dev/null @@ -1,91 +0,0 @@ -# 네이티브 Node 모듈 사용하기 - -Electron에선 네이티브 Node 모듈을 지원합니다. 하지만 Electron이 시스템에 설치된 -Node의 버전과 전혀 다른 V8 버전을 사용하고 있을 가능성이 높은 관계로, 네이티브 모듈을 -빌드할 때 Electron의 헤더를 수동으로 지정해 주어야 합니다. - -## 네이티브 모듈을 설치하는 방법 - -네이티브 모듈을 설치하는 방법에는 세 가지 방법이 있습니다: - -### `npm` 사용하기 - -몇 가지 환경 변수를 설치하는 것으로, 직접적으로 `npm`을 모듈을 설치하는데 사용할 수 -있습니다. - -다음 예시는 Electron에 대한 모든 종속성을 설치하는 예시입니다: - -```bash -# Electron의 버전. -export npm_config_target=1.2.3 -# Electron의 아키텍쳐, ia32 또는 x64가 될 수 있습니다. -export npm_config_arch=x64 -# Electron에 대한 헤더 다운로드 링크. -export npm_config_disturl=https://atom.io/download/atom-shell -# node-pre-gyp에 Electron을 빌드한다는 것을 알려줍니다. -export npm_config_runtime=electron -# node-pre-gyp에 소스 코드로부터 모듈을 빌드한다는 것을 알려줍니다. -export npm_config_build_from_source=true -# 모든 종속성을 설치하고 캐시를 ~/.electron-gyp에 저장합니다. -HOME=~/.electron-gyp npm install -``` - -### 모듈을 설치하고 Electron을 위해 다시 빌드하기 - -다른 Node 프로젝트와 같이 모듈을 설치하는 것을 선택할 수도 있습니다. 그리고 -[`electron-rebuild`][electron-rebuild] 패키지와 함께 Electron에 대해 모듈을 다시 -빌드할 수 있습니다. 이 모듈은 Electron의 버전을 가져올 수 있고 헤더를 다운로드 하거나 -네이티브 모듈을 빌드하는 등의 작업을 자동으로 실행할 수 있습니다. - -다음 예시는 `electron-rebuild`을 설치하고 자동으로 모듈을 빌드하는 예시입니다: - -```bash -npm install --save-dev electron-rebuild - -# "npm install"을 실행할 때마다 다음 명령을 실행하세요: -./node_modules/.bin/electron-rebuild - -# Windows에서 문제가 발생하면 다음 명령을 대신 실행하세요: -.\node_modules\.bin\electron-rebuild.cmd -``` - -**역자주:** `npm script`의 `postinstall`을 사용하면 이 작업을 자동화 할 수 있습니다. - -### Electron을 위해 직접적으로 빌드하기 - -현재 본인이 네이티브 모듈을 개발하고 있는 개발자이고 Electron에 대해 실험하고 싶다면, -직접적으로 모듈을 Electron에 대해 다시 빌드하고 싶을 것입니다. `node-gyp`를 통해 -직접적으로 Electron에 대해 빌드할 수 있습니다. - -```bash -cd /path-to-module/ -HOME=~/.electron-gyp node-gyp rebuild --target=1.2.3 --arch=x64 --dist-url=https://atom.io/download/atom-shell -``` - -`HOME=~/.electron-gyp`은 변경할 헤더의 위치를 찾습니다. `--target=0.29.1`은 -Electron의 버전입니다. `--dist-url=...`은 헤더를 다운로드 하는 주소입니다. -`--arch=x64`는 64비트 시스템을 타겟으로 빌드 한다는 것을 `node-gyp`에게 알려줍니다. - -## 문제 해결 - -네이티브 모듈을 설치했는데 잘 작동하지 않았다면, 다음 몇 가지를 확인해봐야 합니다: - -* 모듈의 아키텍쳐가 Electron의 아키텍쳐와 일치합니다. (ia32 또는 x64) -* Electron을 업그레이드한 후, 보통은 모듈을 다시 빌드해야 합니다. -* 문제가 의심된다면, 먼저 `electron-rebuild`를 실행하세요. - -## 모듈이 `node-pre-gyp`에 의존합니다 - -[`node-pre-gyp` 툴][node-pre-gyp]은 미리 빌드된 바이너리와 함께 네이티브 Node 모듈을 -배치하는 방법을 제공하며 수 많은 유명한 모듈들이 이를 사용합니다. - -보통 이 모듈은 Electron과 함께 잘 작동하지만, Electron이 Node보다 새로운 V8 버전을 -사용할 때, 만약 ABI가 변경되었다면, 때때로 안 좋은 일이 일어납니다. 그래서 일반적으론 -언제나 네이티브 모듈의 소스 코드를 가져와서 빌드하는 것을 권장합니다. - -`npm`을 통한 방법을 따르고 있다면, 기본적으로 이 소스를 받아와서 빌드합니다. 만약 -그렇지 않다면, `npm`에 `--build-from-source`를 전달해 주어야 합니다. 아니면 -`npm_config_build_from_source`를 환경 변수에 설정하는 방법도 있습니다. - -[electron-rebuild]: https://github.com/paulcbetts/electron-rebuild -[node-pre-gyp]: https://github.com/mapbox/node-pre-gyp diff --git a/docs-translations/ko-KR/tutorial/using-pepper-flash-plugin.md b/docs-translations/ko-KR/tutorial/using-pepper-flash-plugin.md deleted file mode 100644 index bfe16a85cf427..0000000000000 --- a/docs-translations/ko-KR/tutorial/using-pepper-flash-plugin.md +++ /dev/null @@ -1,77 +0,0 @@ -# Pepper 플래시 플러그인 사용하기 - -Electron은 Pepper 플래시 플러그인을 지원합니다. Electron에서 Pepper 플래시 -플러그인을 사용하려면 Pepper 플래시 플러그인의 위치를 지정한 후 애플리케이션 내에서 -활성화 시켜야 합니다. - -## 플래시 플러그인 준비하기 - -크롬 브라우저의 `chrome://plugins` 페이지에 접속한 후 `세부정보`에서 플래시 -플러그인의 위치와 버전을 찾을 수 있습니다. Electron에서 플래시 플러그인을 지원하기 -위해선 이 두 가지를 복사해 와야 합니다. - -## Electron 스위치 추가 - -플러그인을 사용하려면 Electron 커맨드 라인에 `--ppapi-flash-path` 와 -`--ppapi-flash-version` 플래그를 `app`의 `ready` 이벤트가 발생하기 전에 추가해야 -합니다. 그리고 `browser-window`에 `plugins` 옵션을 활성화해야 합니다. - -예를 들면: - -```javascript -// 플래시 플러그인의 위치를 설정합니다. main.js와 위치가 같다고 가정할 때: -let pluginName -switch (process.platform) { - case 'win32': - pluginName = 'pepflashplayer.dll' - break - case 'darwin': - pluginName = 'PepperFlashPlayer.plugin' - break - case 'linux': - pluginName = 'libpepflashplayer.so' - break -} - -app.commandLine.appendSwitch('ppapi-flash-path', path.join(__dirname, pluginName)) - -// 선택적인으로 플래시 플레이어의 버전을 설정합니다. 예시로는, v17.0.0.169 -app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169') - -app.on('ready', () => { - win = new BrowserWindow({ - width: 800, - height: 600, - webPreferences: { - plugins: true - } - }) - win.loadURL(`file://${__dirname}/index.html`) - // 이외의 코드 -}); -``` - -직접 플러그인을 삽입하는 대신 시스템의 Pepper Flash 플러그인을 사용할 수도 있습니다. -시스템상의 플러그인의 경로는 `app.getPath('pepperFlashSystemPlugin')`로 불러올 수 -있습니다. - -## `` 태그를 이용하여 플러그인을 활성화 - -`plugins` 속성을 `` 태그에 추가합니다. - -```html - -``` - -## 문제 해결 - -개발자 도구의 콘솔에서 `navigator.plugins`를 탐색하면 Pepper 플래시 플러그인이 잘 -로드되었는지를 확인할 수 있습니다. (물론 플러그인의 경로를 잘 설정하지 않으면 확인할 -수 없습니다) - -Pepper 플래시 플러그인의 구조는 Electron과 일치해야 합니다. Windows에서 자주 -발생하는 문제는 32비트 버전의 플래시 플레이어를 64비트 버전의 Electron에서 사용하는 -것입니다. - -Windows에선 `--ppapi-flash-path`로 전달되는 경로의 분리자로 `\`를 사용해야 합니다. -POSIX-스타일 경로는 작동하지 않을 것입니다. diff --git a/docs-translations/ko-KR/tutorial/using-selenium-and-webdriver.md b/docs-translations/ko-KR/tutorial/using-selenium-and-webdriver.md deleted file mode 100644 index 96ed767d27705..0000000000000 --- a/docs-translations/ko-KR/tutorial/using-selenium-and-webdriver.md +++ /dev/null @@ -1,170 +0,0 @@ -# Selenium 과 WebDriver 사용하기 - -[ChromeDriver - WebDriver for Chrome][chrome-driver]로부터 인용: - -> WebDriver는 많은 브라우저에서 웹 앱을 자동적으로 테스트하는 툴입니다. -> 이 툴킷은 웹 페이지를 자동으로 탐색하고 유저 폼을 사용하거나 자바스크립트를 실행하는 -> 등의 작업을 수행할 수 있습니다. ChromeDriver는 Chromium의 WebDriver wire 프로토콜 -> 스텐드얼론 서버 구현입니다. Chromium 과 WebDriver 팀 멤버에 의해 개발되었습니다. - -## Spectron 설정하기 - -[Spectron][spectron]은 공식적으로 지원하는 Electron을 위한 ChromeDriver 테스팅 -프레임워크입니다. 이는 [WebdriverIO](http://webdriver.io/)를 기반으로 만들어졌고, -테스트에서 Electron API에 접근하기 위한 헬퍼를 가지고 있으며 ChromeDriver를 포함하고 -있습니다. - -```bash -$ npm install --save-dev spectron -``` - -```js -// 윈도우가 제목과 함께 보이는지 검증하는 간단한 테스트. -var Application = require('spectron').Application -var assert = require('assert') - -var app = new Application({ - path: '/Applications/MyApp.app/Contents/MacOS/MyApp' -}) - -app.start().then(function () { - // 윈도우가 보이는지 확인합니다. - return app.browserWindow.isVisible() -}).then(function (isVisible) { - // 윈도우가 보이는지 검증합니다. - assert.equal(isVisible, true) -}).then(function () { - // 윈도우의 제목을 가져옵니다. - return app.client.getTitle() -}).then(function (title) { - // 윈도우의 제목을 검증합니다. - assert.equal(title, 'My App') -}).catch(function (error) { - // 테스트의 실패가 있다면 로깅합니다. - console.error('Test failed', error.message) -}).then(function () { - // 애플리케이션을 중지합니다. - return app.stop() -}) -``` - -## WebDriverJs 설정하기 - -[WebDriverJs](https://code.google.com/p/selenium/wiki/WebDriverJs)는 WebDriver를 -사용하여 테스트 할 수 있도록 도와주는 node 패키지입니다. 다음 예시를 참고하세요. - -### 1. 크롬 드라이버 시작 - -먼저, `chromedriver` 바이너리를 다운로드 받고 실행합니다: - -```bash -$ npm install electron-chromedriver -$ ./node_modules/.bin/chromedriver -Starting ChromeDriver (v2.10.291558) on port 9515 -Only local connections are allowed. -``` - -포트 `9515`는 나중에 사용하므로 기억해 놓습니다. - -### 2. WebDriverJS 설치 - -```bash -$ npm install selenium-webdriver -``` - -### 3. 크롬 드라이버에 연결 - -`selenium-webdriver`를 Electron과 같이 사용하는 방법은 기본적으로 upstream과 -같습니다. 한가지 다른점이 있다면 수동으로 크롬 드라이버 연결에 대해 설정하고 Electron -실행파일의 위치를 전달합니다: - -```javascript -const webdriver = require('selenium-webdriver'); - -const driver = new webdriver.Builder() - // 작동하고 있는 크롬 드라이버의 포트 "9515"를 사용합니다. - .usingServer('http://localhost:9515') - .withCapabilities({ - chromeOptions: { - // 여기에 사용중인 Electron 바이너리의 경로를 지정하세요. - binary: '/Path-to-Your-App.app/Contents/MacOS/Electron', - } - }) - .forBrowser('electron') - .build(); - -driver.get('http://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(); -``` - -## WebdriverIO 설정하기 - -[WebdriverIO](http://webdriver.io/)는 웹 드라이버와 함께 테스트를 위해 제공되는 -node 패키지입니다. - -### 1. 크롬 드라이버 시작 - -먼저, `chromedriver` 바이너리를 다운로드 받고 실행합니다: - -```bash -$ npm install electron-chromedriver -$ ./node_modules/.bin/chromedriver --url-base=wd/hub --port=9515 -Starting ChromeDriver (v2.10.291558) on port 9515 -Only local connections are allowed. -``` - -포트 `9515`는 나중에 사용하므로 기억해 놓읍시다 - -### 2. WebDriverIO 설치 - -```bash -$ npm install webdriverio -``` - -### 3. 크롬 드라이버에 연결 -```javascript -const webdriverio = require('webdriverio'); -let options = { - host: 'localhost', // localhost에서 작동중인 크롬 드라이버 서버를 사용합니다. - port: 9515, // 연결할 크롬 드라이버 서버의 포트를 설정합니다. - desiredCapabilities: { - browserName: 'chrome', - chromeOptions: { - binary: '/Path-to-Your-App/electron', // Electron 바이너리 경로 - args: [/* cli arguments */] // 선택 사항, 'app=' + /path/to/your/app/ - } - } -}; - -let client = webdriverio.remote(options); - -client - .init() - .url('http://google.com') - .setValue('#q', 'webdriverio') - .click('#btnG') - .getTitle().then((title) => { - console.log('Title was: ' + title); - }) - .end(); -``` - -## 작업 환경 - -따로 Electron을 다시 빌드하지 않는 경우 간단히 애플리케이션을 Electron의 리소스 -디렉터리에 [배치](application-distribution.md)하여 바로 테스트 할 수 있습니다. - -또한, Electron 바이너리의 명령줄 인수에 애플리케이션 폴더를 지정하는 방법으로 실행할 -수도 있습니다. 이 방법을 사용하면 애플리케이션 폴더를 Electron의 `resource` -디렉터리로 복사하는 불필요한 과정을 생략할 수 있습니다. - -[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/ -[spectron]: http://electron.atom.io/spectron diff --git a/docs-translations/ko-KR/tutorial/using-widevine-cdm-plugin.md b/docs-translations/ko-KR/tutorial/using-widevine-cdm-plugin.md deleted file mode 100644 index 3be7f70a8c23c..0000000000000 --- a/docs-translations/ko-KR/tutorial/using-widevine-cdm-plugin.md +++ /dev/null @@ -1,82 +0,0 @@ -# Widevine CDM 플러그인 사용하기 - -Electron에선 Chrome 브라우저에서 취득해온 Widevine CDM 플러그인을 사용할 수 있습니다. - -## 플러그인 취득 - -Electron은 라이센스상의 문제로 Widevine CDM 플러그인을 직접 제공하지 않습니다. -따라서 플러그인을 얻으려면 먼저 사용할 Electron 빌드의 아키텍쳐와 버전에 맞춰 공식 -Chrome 브라우저를 설치해야 합니다. - -**참고:** Chrome 브라우저의 메이저 버전은 Electron에서 사용하는 Chrome 버전과 -같습니다, 만약 그렇지 않다면 `navigator.plugins`가 로드됐더라도 정상적으로 작동하지 -않습니다. - -### Windows & macOS - -Chrome 브라우저에서 `chrome://components/`를 열고 `WidevineCdm`을 찾은 후 확실히 -최신버전인지 확인합니다. 여기까지 하면 모든 플러그인 바이너리를 -`APP_DATA/Google/Chrome/WidevineCDM/VERSION/_platform_specific/PLATFORM_ARCH/` -디렉터리에서 찾을 수 있습니다. - -`APP_DATA`는 애플리케이션 데이터를 저장하고 있는 시스템 경로입니다. Windows에선 -`%LOCALAPPDATA%`로 접근할 수 있고 macOS에선 `~/Library/Application Support`로 -접근할 수 있습니다. `VERSION`은 `1.4.8.866` 같은 Widevine CDM 플러그인의 버전 -문자열입니다. `PLATFORM`은 플랫폼을 뜻하며 `mac` 또는 `win`이 될 수 있으며 `ARCH`는 -아키텍쳐를 뜻하고 `x86` 또는 `x64`가 될 수 있습니다. - -Windows에선 `widevinecdm.dll` 와 `widevinecdmadapter.dll` 같은 바이너리를 -요구하며 macOS에선 `libwidevinecdm.dylib`와 `widevinecdmadapter.plugin` 바이너리를 -요구합니다. 원하는 곳에 이들을 복사해 놓을 수 있습니다. 하지만 반드시 바이너리는 같은 -위치에 두어야 합니다. - -### Linux - -Linux에선 플러그인 바이너리들이 Chrome 브라우저와 함께 제공됩니다. -`/opt/google/chrome` 경로에서 찾을 수 있으며, 파일 이름은 `libwidevinecdm.so`와 -`libwidevinecdmadapter.so`입니다. - -## 플러그인 사용 - -플러그인 파일을 가져온 후, Electron의 `--widevine-cdm-path` 커맨드 라인 스위치에 -`widevinecdmadapter`의 위치를 전달하고 플러그인의 버전을 `--widevine-cdm-version` -스위치에 전달해야 합니다. - -**참고:** `widevinecdmadapter` 바이너리가 Electron으로 전달되어도, `widevinecdm` -바이너리는 옆에 같이 두어야 합니다. - -커맨드 라인 스위치들은 `app` 모듈의 `ready` 이벤트가 발생하기 전에 전달되어야 합니다. -그리고 이 플러그인을 사용하는 페이지는 플러그인(속성)이 활성화되어있어야 합니다. - -예시 코드: - -```javascript -// `widevinecdmadapter`의 파일 이름을 이곳에 전달해야 합니다. 파일 이름은 -// * macOS에선 `widevinecdmadapter.plugin`로 지정합니다, -// * Linux에선 `libwidevinecdmadapter.so`로 지정합니다, -// * Windows에선 `widevinecdmadapter.dll`로 지정합니다. -app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevinecdmadapter.plugin'); -// 플러그인의 버전은 크롬의 `chrome://plugins` 페이지에서 취득할 수 있습니다. -app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866'); - -let win = null; -app.on('ready', () => { - win = new BrowserWindow({ - webPreferences: { - // `plugins`은 활성화되어야 합니다. - plugins: true - } - }); -}); -``` - -## 플러그인 작동 확인 - -플러그인 정상적으로 작동하는지 확인하려면 다음과 같은 방법을 사용할 수 있습니다: - -* 개발자 도구를 연 후 `navigator.plugins`를 확인하여 Widevine CDM 플러그인이 - 포함되었는지 알 수 있습니다. -* https://shaka-player-demo.appspot.com/를 열어, `Widevine`을 사용하는 설정을 - 로드합니다. -* http://www.dash-player.com/demo/drm-test-area/를 열어, 페이지에서 - `bitdash uses Widevine in your browser`라고 적혀있는지 확인하고 비디오를 재생합니다. diff --git a/docs-translations/ko-KR/tutorial/windows-store-guide.md b/docs-translations/ko-KR/tutorial/windows-store-guide.md deleted file mode 100644 index d932f0e6b3123..0000000000000 --- a/docs-translations/ko-KR/tutorial/windows-store-guide.md +++ /dev/null @@ -1,149 +0,0 @@ -# Windows 스토어 가이드 - -Windows 8부터, 오래되고 좋은 win32 실행 파일이 새로운 형제를 얻었습니다: Universial -Windows Platform. 새로운 `.appx` 포맷은 Cortana와 푸시 알림과 같은 다수의 강력한 -API뿐만 아니라, Windows Store를 통해 설치와 업데이트를 단순화합니다. - -Microsoft는 개발자들이 새로운 애플리케이션 모델의 좋은 기능들을 사용할 수 있도록 -[Electron 애플리케이션을 `.appx` 패키지로 컴파일시키는 도구를 개발했습니다][electron-windows-store]. -이 가이드는 이 도구를 사용하는 방법과 Electron AppX 패키지의 호환성과 한정 사항을 -설명합니다. - -## 기본 상식과 요구 사항 - -Windows 10 "기념일 업데이트"는 win32 `.exe` 바이너리를 가상화된 파일 시스템과 -레지스트리를 함께 실행시킬 수 있도록 만들었습니다. 두 가지 모두 실행 중인 -애플리케이션과 Windows 컨테이너 안의 인스톨러에 의해 컴파일되는 동안 만들어지며, -설치가 되는 동안 Windows가 확실하게 어떤 변경 사항이 운영 체제에 적용되는지 식별할 수 -있도록 합니다. 가상 파일 시스템과 가상 레지스트리를 페어링 하는 실행 파일은 Windows가 -한 번의 클릭으로 설치와 삭제를 할 수 있도록 만듭니다. - -더 나아가서, exe는 appx 모델 안에서 실행됩니다 - 이 말은 즉 Universial Windows -Platform에서 제공되는 수많은 API를 사용할 수 있다는 이야기입니다. 더 많은 기능을 -사용하기 위해, Electron 애플리케이션은 백그라운드로 실행된 UWP 앱과 페어링 하여 -`exe`와 같이 실행할 수 있습니다 - 이렇게 헬퍼와 비슷하게 실행되고 작업을 실행하기 위해 -백그라운드에서 작동하며, 푸시 알림을 받거나, 다른 UWP 애플리케이션과 통신하는 역할을 -합니다. - -현재 존재하는 Electron 애플리케이션을 컴파일 하려면, 다음 요구 사항을 충족해야 합니다: - - -* Windows 10 기념일 업데이트 (이 업데이트가 정식 배포되기 전까지 개발자는 Windows - Insider Preview를 사용할 수 있습니다) -* Windows 10 SDK, [여기서 다운로드][windows-sdk] - -그리고 CLI에서 `electron-windows-store`를 설치합니다: - -``` -npm install -g electron-windows-store -``` - -## Step 1: Electron 어플리케이션 패키징 - -[electron-packager](https://github.com/electron-userland/electron-packager)를 -사용하여 애플리케이션을 패키징합니다. (또는 비슷한 도구를 사용합니다) 마지막으로 최종 -애플리케이션에선 `node_modules`가 필요 없으며 그저 애플리케이션의 크기를 늘릴 뿐이니 -확실하게 지웠는지 확인합니다. - -출력된 파일들은 대충 다음과 같아야 합니다: - -``` -├── Ghost.exe -├── LICENSE -├── content_resources_200_percent.pak -├── content_shell.pak -├── d3dcompiler_47.dll -├── ffmpeg.dll -├── icudtl.dat -├── libEGL.dll -├── libGLESv2.dll -├── locales -│ ├── am.pak -│ ├── ar.pak -│ ├── [...] -├── natives_blob.bin -├── node.dll -├── resources -│ ├── app -│ └── atom.asar -├── snapshot_blob.bin -├── squirrel.exe -├── ui_resources_200_percent.pak -└── xinput1_3.dll -``` - -## `electron-windows-store` 실행하기 - -관리자 권한의 PowerShell ("관리자 권한으로 실행")을 실행하고, 디렉토리 입력과 출력, -애플리케이션의 이름과 버전, 마지막으로 `node_modules`를 평탄화시키는 인수들과 함께 -`electron-windows-store`를 실행합니다. - -``` -electron-windows-store ` - --input-directory C:\myelectronapp ` - --output-directory C:\output\myelectronapp ` - --flatten true ` - --package-version 1.0.0.0 ` - --package-name myelectronapp -``` - -명령이 실행되면, 도구는 다음과 같이 작동합니다: Electron 애플리케이션을 입력으로 받고, -`node_modules`를 평탄화하고 애플리케이션을 `app.zip`으로 압축합니다. 그리고 -인스톨러와 Windows Container를 사용하여, "확장된" AppX 패키지를 만듭니다 - -Windows Application Manifest (`AppXManifest.xml`)와 동시에 가상 파일 시스템과 가상 -레지스트리를 포함하여 출력 폴더로 내보냅니다. - -확장된 AppX 파일이 만들어지면, 도구는 Windows App Packager (`MakeAppx.exe`)를 -사용하여 디스크의 파일로부터 단일-파일 AppX 패키지를 생성해냅니다. 최종적으로, 이 -도구는 새 AppX 패키지에 서명하기 위해 컴퓨터에서 신뢰된 인증서를 만드는 데 사용할 수 -있습니다. 서명된 AppX 패키지로, CLI는 자동으로 기기에 패키지를 설치할 수 있습니다. - -## Step 3: AppX 패키지 사용하기 - -Windows 기념일 업데이트 (코드네임 Windows 레드스톤)가 아직 모든 일반 사용자에게 -배포되지 않았기 때문에, 올해까지는 애플리케이션을 Windows Store에 올릴 수 없을 것 -입니다 - 하지만 개발자 또는 회사 환경에서 `Add-AppxPackage` -[PowerShell Cmdlet을 통해][add-appxpackage] 기기에 애플리케이션을 설치할 수 있습니다. - -또 다른 중요한 제약은 컴파일된 AppX 패키지는 여전히 win32 실행 파일이 담겨있다는 -것입니다 - 따라서 Xbox, HoloLens, Phone에서 실행할 수 없습니다. - -## Optional: 백그라운드 작업을 사용하여 UWP 기능 추가 - -필요하다면 Windows 10의 모든 기능을 사용하기 위해 보이지 않는 UWP 백그라운드 작업과 -Electron 앱을 연결할 수 있습니다 - 푸시 알림, 코타나 통합, 라이브 타일등. - -Electron 앱이 토스트 알림이나 라이브 타일을 사용할 수 있도록 하는 방법을 알아보려면 -[Microsoft가 제공하는 샘플을 참고하세요][background-task]. - -## Optional: 컨테이너 가상화를 사용하여 변환 - -AppX 패키지를 만드려면, `electron-windows-store` CLI를 통해 대부분의 Electron 앱을 -그대로 변환할 수 있습니다. 하지만, 커스텀 인스톨러를 사용하고 있거나, 패키지를 -생성하는데 어떠한 문제라도 겪고있다면, Windows Container를 사용하여 패키지를 생성하는 -시도를 해볼 수 있습니다 - 이 모드를 사용하면, CLI가 어플리케이션이 정확하게 운영체제에 -대해 수행하는 작업이 어떤 변경 사항을 만드는지를 결정하기 위해 어플리케이션을 빈 Windows -Container에서 설치하고 실행할 것입니다. - -처음 CLI를 실행하기 전에, "Windows Desktop App Converter"를 먼저 설정해야 합니다. -이 작업은 약 몇 분 정도 소요됩니다. 하지만 걱정하지 않아도 됩니다 - 이 작업은 딱 한 -번만 하면 됩니다. Desktop App Converter는 [여기][app-converter]에서 다운로드 받을 -수 있고, `DesktopAppConverter.zip`와 `BaseImage-14316.wim` 두 파일을 모두 받아야 -합니다. - -1. `DesktopAppConverter.zip`의 압축을 풉니다. 그다음 PowerShell을 관리자 권한으로 - 실행하고 압축을 푼 위치로 이동합니다. (실행하는 모든 명령에 "관리자 권한"을 - 적용하려면 `Set-ExecutionPolicy bypass`를 실행하면 됩니다) -2. 그리고, `.\DesktopAppConverter.ps1 -Setup -BaseImage .\BaseImage-14316.wim`를 - 실행하여 Windows 베이스 이미지 (`BaseImage-14316.wim`)를 Desktop App Converter로 - 전달하고 설치를 진행합니다. -3. 만약 위 명령이 재시작을 요구하면, 기기를 재시작하고 위 명령을 다시 실행시키세요. - -설치가 완료되면, 컴파일할 Electron 애플리케이션 경로로 이동합니다. - -[windows-sdk]: https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk -[app-converter]: https://www.microsoft.com/en-us/download/details.aspx?id=51691 -[add-appxpackage]: https://technet.microsoft.com/en-us/library/hh856048.aspx -[electron-packager]: https://github.com/electron-userland/electron-packager -[electron-windows-store]: https://github.com/catalystcode/electron-windows-store -[background-task]: https://github.com/felixrieseberg/electron-uwp-background diff --git a/docs-translations/pt-BR/README.md b/docs-translations/pt-BR/README.md deleted file mode 100644 index aa0537708aaf2..0000000000000 --- a/docs-translations/pt-BR/README.md +++ /dev/null @@ -1,89 +0,0 @@ -Por favor, certifique-se de que está utilizando a documentação que corresponde à sua versão do Electron. -O número da versão deve ser uma parte da URL da página. Se não for, você provavelmente está utilizando -a documentação de um branch de desenvolvimento que pode conter mudanças na API que não são compatíveis -com a sua versão do Electron. Se este for o caso, você pode mudar para uma versão diferente da -documentação na lista de [versões disponíveis](http://electron.atom.io/docs/) em atom.io, -ou se você estiver usando a interface do GitHub, abra o *dropdown* "Switch branches/tags" e -selecione a *tag* que corresponde à sua versão. - -## FAQ - -Existem muitas perguntas comuns que são feitas, verifique antes de criar uma issue. -* [Electron FAQ](../../docs/faq.md) - -## Guias - -* [Plataformas Suportadas](tutorial/supported-platforms.md) -* [Distribuição de Aplicações](tutorial/application-distribution.md) -* [Guia de Submissão da Mac App Store](../../docs/tutorial/mac-app-store-submission-guide.md) -* [Empacotamento da Aplicação](tutorial/application-packaging.md) -* [Usando Módulos Nativos do Node](tutorial/using-native-node-modules.md) -* [Depuração do Processo Principal](tutorial/debugging-main-process.md) -* [Usando Selenium e WebDriver](../../docs/tutorial/using-selenium-and-webdriver.md) -* [Extensão DevTools](tutorial/devtools-extension.md) -* [Usando o Plugin Pepper Flash](tutorial/using-pepper-flash-plugin.md) -* [Usando o Plugin Widevine CDM](../../docs/tutorial/using-widevine-cdm-plugin.md) - -## Tutoriais - -* [Introdução](tutorial/quick-start.md) -* [Integração com o Ambiente de Desenvolvimento](tutorial/desktop-environment-integration.md) -* [Evento de Detecção Online/Offline](tutorial/online-offline-events.md) - -## API - Referências - -* [Sinopse](../../docs/api/synopsis.md) -* [Processos](api/process.md) -* [Aceleradores (Teclas de Atalho)](api/accelerator.md) -* [Parâmetros CLI suportados (Chrome)](../../docs/api/chrome-command-line-switches.md) -* [Variáveis de Ambiente](../../docs/api/environment-variables.md) - -### Elementos DOM Personalizados: - -* [Objeto `File`](../../docs/api/file-object.md) -* [Tag ``](../../docs/api/web-view-tag.md) -* [Função `window.open`](../../docs/api/window-open.md) - -### Módulos para o Processo Principal: - -* [app](api/app.md) -* [autoUpdater](api/auto-updater.md) -* [BrowserWindow](../../docs/api/browser-window.md) -* [contentTracing](../../docs/api/content-tracing.md) -* [dialog](../../docs/api/dialog.md) -* [globalShortcut](../../docs/api/global-shortcut.md) -* [ipcMain](../../docs/api/ipc-main.md) -* [Menu](../../docs/api/menu.md) -* [MenuItem](../../docs/api/menu-item.md) -* [powerMonitor](api/power-monitor.md) -* [powerSaveBlocker](../../docs/api/power-save-blocker.md) -* [protocol](../../docs/api/protocol.md) -* [session](../../docs/api/session.md) -* [webContents](../../docs/api/web-contents.md) -* [Tray](../../docs/api/tray.md) - -### Módulos para o Processo Renderizador: - -* [DesktopCapturer](../../docs/api/desktop-capturer.md) -* [ipcRenderer](../../docs/api/ipc-renderer.md) -* [remote](../../docs/api/remote.md) -* [webFrame](../../docs/api/web-frame.md) - -### Módulos para ambos os processos: - -* [clipboard](../../docs/api/clipboard.md) -* [crashReporter](../../docs/api/crash-reporter.md) -* [nativeImage](../../docs/api/native-image.md) -* [screen](../../docs/api/screen.md) -* [shell](api/shell.md) - -## Desenvolvimento - -* [Estilo de Código](development/coding-style.md) -* [Estrutura de Diretórios de Código Fonte](../../docs/development/source-code-directory-structure.md) -* [Diferenças Técnicas do NW.js (antigo node-webkit)](../../docs/development/atom-shell-vs-node-webkit.md) -* [Visão Geral do Build](../../docs/development/build-system-overview.md) -* [Instrução de Build (Mac)](../../docs/development/build-instructions-osx.md) -* [Instrução de Build (Windows)](../../docs/development/build-instructions-windows.md) -* [Instrução de Build (Linux)](../../docs/development/build-instructions-linux.md) -* [Configurando um Symbol Server no Debugger](../../docs/development/setting-up-symbol-server.md) diff --git a/docs-translations/pt-BR/api/accelerator.md b/docs-translations/pt-BR/api/accelerator.md deleted file mode 100644 index 7d4df4c79da74..0000000000000 --- a/docs-translations/pt-BR/api/accelerator.md +++ /dev/null @@ -1,46 +0,0 @@ -# Acelerador (teclas de atalhos) - -Um acelerador é uma string que representa um atalho de tecla. Ele pode conter -múltiplos modificadores e códigos chaves, combinados pelo caractere `+`. - -Exemplos: - -* `Command+A` -* `Ctrl+Shift+Z` - -## Aviso sobre plataformas - -No Linux e no Windows a tecla `Command` não tem nenhum efeito, -então use `CommandOrControl` que representa a tecla `Command` existente no macOS e -`Control` no Linux e no Windows para definir aceleradores (atalhos). - -A chave `Super` está mapeada para a tecla `Windows` para Windows e Linux, -e para a tecla `Cmd` para macOS. - -## Modificadores disponíveis - -* `Command` (ou `Cmd` abreviado) -* `Control` (ou `Ctrl` abreviado) -* `CommandOrControl` (ou `CmdOrCtrl` abreviado) -* `Alt` -* `Shift` -* `Super` - -## Códigos chaves disponíveis - -* `0` até `9` -* `A` até `Z` -* `F1` até `F24` -* Pontuações como `~`, `!`, `@`, `#`, `$`, etc. -* `Plus` -* `Space` -* `Backspace` -* `Delete` -* `Insert` -* `Return` (ou `Enter` como pseudônimo) -* `Up`, `Down`, `Left` e `Right` -* `Home` e `End` -* `PageUp` e `PageDown` -* `Escape` (ou `Esc` abreviado) -* `VolumeUp`, `VolumeDown` e `VolumeMute` -* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` e `MediaPlayPause` diff --git a/docs-translations/pt-BR/api/app.md b/docs-translations/pt-BR/api/app.md deleted file mode 100644 index c18a803439a84..0000000000000 --- a/docs-translations/pt-BR/api/app.md +++ /dev/null @@ -1,452 +0,0 @@ -# app - -O módulo `app` é responsável por controlar o ciclo de vida do aplicativo. - -O exemplo a seguir mostra como fechar o aplicativo quando a última janela é fechada: - -```javascript -const app = require('electron').app; -app.on('window-all-closed', function() { - app.quit(); -}); -``` - -## Eventos - -O objeto `app` emite os seguintes eventos: - -### Evento: 'will-finish-launching' - -Emitido quando o aplicativo finaliza a inicialização básica. No Windows e no Linux, -o evento `will-finish-launching` é o mesmo que o evento `ready`; No macOS, -esse evento representa a notificação `applicationWillFinishLaunching` do `NSApplication`. -Normalmente aqui seriam criados *listeners* para os eventos `open-file` e `open-url`, e inicializar o *crash reporter* e atualizador automático. - -Na maioria dos casos, você deve fazer tudo no manipulador de eventos do `ready`. - -### Evento: 'ready' - -Emitido quando o Electron finaliza a inicialização. - -### Evento: 'window-all-closed' - -Emitido quando todas as janelas forem fechadas. - -Este evento só é emitido quando o aplicativo não for fechar. Se o -usuário pressionou`Cmd + Q`, ou o desenvolvedor chamou `app.quit()`, -o Electron tentará primeiro fechar todas as janelas e então emitir o -evento `will-quit`, e neste caso o evento `window-all-closed` não -seria emitido. - -### Evento: 'before-quit' - -Retorna: - -* `event` Event - -Emitido antes que o aplicativo comece a fechar suas janelas. -Chamar `event.preventDefault()` irá impedir o comportamento padrão, -que é terminar o aplicativo. - -### Evento: 'will-quit' - -Retorna: - -* `event` Event - -Emitido quando todas as janelas foram fechadas e o aplicativo irá finalizar. -Chamar `event.preventDefault()` irá impedir o comportamento padrão, -que é terminar o aplicativo. - -Veja a descrição do evento `window-all-closed` para as diferenças entre o -evento `will-quit` e `window-all-closed`. - -### Evento: 'quit' - -Emitido quando o aplicativo está finalizando. - -### Evento: 'open-file' _macOS_ - -Retorna: - -* `event` Event -* `path` String - -Emitido quando o usuário deseja abrir um arquivo com o aplicativo. O evento -`open-file` normalmente é emitido quando o aplicativo já está aberto e o S.O. -quer reutilizar o aplicativo para abrir o arquivo. `open-file` também é emitido -quando um arquivo é jogado no *dock* e o aplicativo ainda não está rodando. -Certifique-se de utilizar um *listener* para o evento `open-file` cedo na -inicialização do seu aplicativo para cuidar deste caso (antes mesmo do evento -`ready` ser emitido). - -Você deve chamar `event.preventDefault()` se quiser cuidar deste caso. - -No Windows, você deve fazer o *parse* do `process.argv` para pegar o -endereço do arquivo. - -### Evento: 'open-url' _macOS_ - -Retorna: - -* `event` Event -* `url` String - -Emitido quando o usuário deseja abrir uma URL com o aplicativo. O esquema deve -ser registrado para ser aberto pelo seu aplicativo. - -Você deve chamar `event.preventDefault()` se quiser cuidar deste caso. - -### Evento: 'activate' _macOS_ - -Retorna: - -* `event` Event -* `hasVisibleWindows` Boolean - -Emitido quando o aplicativo é ativado, que normalmente acontece quando o ícone -do aplicativo no *dock* é clicado. - -### Evento: 'browser-window-blur' - -Retorna: - -* `event` Event -* `window` BrowserWindow - -Emitido quando uma [browserWindow](../../../docs/api/browser-window.md) fica embaçada. - -### Evento: 'browser-window-focus' - -Retorna: - -* `event` Event -* `window` BrowserWindow - -Emitido quando uma [browserWindow](../../../docs/api/browser-window.md) é focada. - -### Evento: 'browser-window-created' - -Retorna: - -* `event` Event -* `window` BrowserWindow - -Emitido quando uma nova [browserWindow](../../../docs/api/browser-window.md) é criada. - -### Evento: 'certificate-error' - -Returns: - -* `event` Event -* `webContents` [WebContents](../../../docs/api/web-contents.md) -* `url` URL -* `error` String - O código de erro -* `certificate` Object - * `data` Buffer - dados codificados PEM - * `issuerName` String -* `callback` Function - -Emitido quando há uma falha na verificação do `certificate` para a `url`, -para confiar no certificado, você deve impedir o comportamento padrão com -`event.preventDefault()` e chamar `callback(true)`. - -```javascript -session.on('certificate-error', function(event, webContents, url, error, certificate, callback) { - if (url == "https://github.com") { - // Lógica de verificação. - event.preventDefault(); - callback(true); - } else { - callback(false); - } -}); -``` - -### Evento: 'select-client-certificate' - -Retorna: - -* `event` Event -* `webContents` [WebContents](../../../docs/api/web-contents.md) -* `url` URL -* `certificateList` [Objects] - * `data` Buffer - dados codificados PEM - * `issuerName` String - Nome Comum do Emissor -* `callback` Function - -Emitido quando um certificado de cliente é requisitado. - -A `url` corresponde à entrada de navegação requisitando o certificado do -cliente e `callback` precisa ser chamada com uma entrada filtrada da lista. -Usar `event.preventDefault()` impede o aplicativo de usar o primeiro certificado -da memória. - -```javascript -app.on('select-client-certificate', function(event, webContents, url, list, callback) { - event.preventDefault(); - callback(list[0]); -}) -``` - -### Evento: 'login' - -Retorna: - -* `event` Event -* `webContents` [WebContents](../../../docs/api/web-contents.md) -* `request` Object - * `method` String - * `url` URL - * `referrer` URL -* `authInfo` Object - * `isProxy` Boolean - * `scheme` String - * `host` String - * `port` Integer - * `realm` String -* `callback` Function - -Emitido quando `webContents` deseja fazer autenticação básica. - -O comportamento padrão é cancelar todas as autenticações, para sobrescrever -isto, você deve impedir esse comportamento com `event.preventDefault()` e -chamar `callback(username, password)` com as credenciais. - -```javascript -app.on('login', function(event, webContents, request, authInfo, callback) { - event.preventDefault(); - callback('username', 'secret'); -}) -``` - -### Evento: 'gpu-process-crashed' - -Emitido quando o processo da gpu falha. - -## Métodos - -O objeto `app` possui os seguintes métodos: - -**Nota:** Alguns métodos só estão disponíveis em sistemas operacionais específicos e estão rotulados como tal. - -### `app.quit()` - -Tente fechar todas as janelas. O evento `before-quit` será emitido primeiro. Se todas -as janelas fecharem com sucesso, o evento `will-quit` será emitido e por padrão o -aplicativo irá terminar. - -Este método garante que todos os manipuladores de evento `beforeunload` e `unload` -sejam corretamente executados. É possível que uma janela cancele o processo de -encerramento ao retornar `false` no manipulador de evento `beforeunload`. - -### `app.exit(exitCode)` - -* `exitCode` Integer - -Finaliza imediatamente com `exitCode`. - -Todas as janelas serão fechadas imediatamente sem perguntar ao usuário, e os eventos -`before-quit` e `will-quit` não serão emitidos. - -### `app.getAppPath()` - -Retorna o atual diretório do aplicativo. - -### `app.getPath(name)` - -* `name` String - -Retorna um endereço para um diretório especial ou arquivo associado com `nome`. -Numa falha um `Error` é lançado. - -Você pode requisitar os seguintes endereços pelo nome: - -* `home` Diretório *home* do usuário. -* `appData` Diretório de dados do aplicativo por usuário, que por padrão aponta para: - * `%APPDATA%` no Windows - * `$XDG_CONFIG_HOME` ou `~/.config` no Linux - * `~/Library/Application Support` no macOS -* `userData` O diretório para guardar os arquivos de configuração do seu aplicativo, que por padrão é o diretório `appData` concatenado com o nome do seu aplicativo. -* `temp` Diretório temporário. -* `exe` O arquivo executável atual. -* `module` A biblioteca `libchromiumcontent`. -* `desktop` O diretório *Desktop* do usuário atual. -* `documents` Diretório "Meus Documentos" do usuário. -* `downloads` Diretório dos downloads do usuário. -* `music` Diretório de músicas do usuário. -* `pictures` Diretório de imagens do usuário. -* `videos` Diretório de vídeos do usuário. - -### `app.setPath(name, path)` - -* `name` String -* `path` String - -Sobrescreve o `path` para um diretório especial ou arquivo associado com `name`. -Se o endereço especifica um diretório não existente, o diretório será criado por -este método. Numa falha um `Error` é lançado. - -Você pode sobrescrever apenas endereços com um `name` definido em `app.getPath`. - -Por padrão, *cookies* e *caches* de páginas web serão guardadas no diretório `userData`. Se você quiser mudar esta localização, você deve sobrescrever o -endereço `userData` antes que o evento `ready` do módulo `app` seja emitido. - -### `app.getVersion()` - -Retorna a versão do aplicativo carregado. Se nenhuma versão for encontrada no -arquivo `package.json` do aplicativo, a versão do pacote ou executável atual é -retornada. - -### `app.getName()` - -Retorna o nome do aplicativo atual, que é o nome no arquivo `package.json` do -aplicativo. - -Normalmente o campo `name` do `package.json` é um nome curto em letras minúsculas, -de acordo com as especificações de módulos npm. Normalmente você deve também -especificar um campo `productName`, que é o nome completo em letras maiúsculas do -seu aplicativo, e que será preferido ao `name` pelo Electron. - -### `app.getLocale()` - -Retorna a localidade atual do aplicativo. - -### `app.addRecentDocument(path)` _macOS_ _Windows_ - -* `path` String - -Adiciona `path` à lista de documentos recentes. - -Esta lista é gerenciada pelo S.O.. No Windows você pode visitar a lista pela -barra de tarefas, e no macOS você pode visita-la pelo *dock*. - -### `app.clearRecentDocuments()` _macOS_ _Windows_ - -Limpa a lista de documentos recentes. - -### `app.setUserTasks(tasks)` _Windows_ - -* `tasks` Array - Vetor de objetos `Task` - -Adiciona `tasks` à categoria [Tasks][tasks] do JumpList no Windows. - -`tasks` é um vetor de objetos `Task` no seguinte formato: - -`Task` Object -* `program` String - Endereço do programa a ser executado, normalmente você deve especificar `process.execPath` que abre o programa atual. -* `arguments` String - Os argumentos de linha de comando quando `program` é executado. -* `title` String - A string a ser exibida em uma JumpList. -* `description` String - Descrição desta *task*. -* `iconPath` String - O endereço absoluto para um ícone a ser exibido em uma JumpList, que pode ser um arquivo arbitrário que contém um ícone. Normalmente você pode especificar `process.execPath` para mostrar o ícone do programa. -* `iconIndex` Integer - O índice do ícone do arquivo do icone. Se um arquivo de ícone consiste de dois ou mais ícones, defina este valor para identificar o ícone. Se o arquivo de ícone consiste de um ícone apenas, este valor é 0. - -### `app.allowNTLMCredentialsForAllDomains(allow)` - -* `allow` Boolean - -Define dinamicamente se sempre envia credenciais para HTTP NTLM ou autenticação *Negotiate* - normalmente, o Electron irá mandar apenas credenciais NTLM/Kerberos para URLs que se enquadram em sites "Intranet Local" (estão no mesmo domínio que você). -Entretanto, esta detecção frequentemente falha quando redes corporativas são mal configuradas, então isso permite optar por esse comportamento e habilitá-lo para todas as URLs. - -### `app.makeSingleInstance(callback)` - -* `callback` Function - -Este método faz da sua aplicação uma Aplicação de Instância Única - invés de permitir múltiplas instâncias do seu aplicativo rodarem, isto irá assegurar que apenas uma única instância do seu aplicativo rodará, e outras instâncias sinalizam esta instância e finalizam. - -`callback` será chamado com `callback(argv, workingDirectory)` quando uma segunda instância tenha sido executada. `argv` é um vetor de argumentos de linha de comando da segunda instância, e `workingDirectory` é o atual endereço de seu diretório. -Normalmente aplicativos respondem à isso não minimizando sua janela primária e dando foco à ela. - -É garantida a execução do `callback` após o evento `ready` do `app` ser emitido. - -Este método retorna `false` caso seu processo seja a instância primária do aplicativo e seu aplicativo deve continuar carregando. E retorna `true` caso seu processo tenha enviado seus parâmetros para outra instância, e você deve imediatamente finalizar. - -No macOS o sistema enforça instância única automaticamente quando usuários tentam abrir uma segunda instância do seu aplicativo no *Finder*, e os eventos `open-file` e `open-url` serão emitidos para isso. Entretanto, quando usuários inicializam seu aplicativo na linha de comando, o mecanismo de instância única do sistema será ignorado e você terá de utilizar esse método para assegurar-se de ter uma instância única. - -Um exemplo de ativação da janela de primeira instância quando uma segunda instância inicializa: - -```js -var myWindow = null; - -var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { - // Alguém tentou rodar uma segunda instância, devemos focar nossa janela - if (myWindow) { - if (myWindow.isMinimized()) myWindow.restore(); - myWindow.focus(); - } - return true; -}); - -if (shouldQuit) { - app.quit(); - return; -} - -// Cria myWindow, carrega o resto do aplicativo, etc... -app.on('ready', function() { -}); -``` - -### `app.setAppUserModelId(id)` _Windows_ - -* `id` String - -Muda o [Application User Model ID][app-user-model-id] para `id`. - -### `app.commandLine.appendSwitch(switch[, value])` - -Adiciona uma opção (com `value` opcional) à linha de comando do Chromium. - -**Nota:** Isto não irá afetar `process.argv`, e é utilizado principalmente por desenvolvedores para controlar alguns comportamentos de baixo nível do Chromium. - -### `app.commandLine.appendArgument(value)` - -Adiciona um argumento à linha de comando do Chromium. O argumento será passado com aspas corretamente. - -**Nota:** Isto não irá afetar `process.argv`. - -### `app.dock.bounce([type])` _macOS_ - -* `type` String (opcional) - Pode ser `critical` ou `informational`. O padrão é - `informational` - -Quando `critical` é passado, o ícone do *dock* irá pular até que o aplicativo se torne ativo ou a requisição seja cancelada. - -Quando `informational` é passado, o ícone do *dock* irá pular por um segundo. -Entretanto, a requisição se mantém ativa até que o aplicativo se torne ativo ou a requisição seja cancelada. - -Retorna um ID representando a requisição. - -### `app.dock.cancelBounce(id)` _macOS_ - -* `id` Integer - -Cancela o salto do `id`. - -### `app.dock.setBadge(text)` _macOS_ - -* `text` String - -Define a string a ser exibida na área de *badging* do *dock*. - -### `app.dock.getBadge()` _macOS_ - -Retorna a string da *badge* do *dock*. - -### `app.dock.hide()` _macOS_ - -Esconde o ícone do *dock*. - -### `app.dock.show()` _macOS_ - -Exibe o ícone do *dock*. - -### `app.dock.setMenu(menu)` _macOS_ - -* `menu` Menu - -Define o [menu do dock][dock-menu] do aplicativo. - -[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 -[tasks]:http://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 diff --git a/docs-translations/pt-BR/api/auto-updater.md b/docs-translations/pt-BR/api/auto-updater.md deleted file mode 100644 index ff4db562a0c94..0000000000000 --- a/docs-translations/pt-BR/api/auto-updater.md +++ /dev/null @@ -1,85 +0,0 @@ -# autoUpdater - -Este módulo oferece uma interface para o framework de atualização automática `Squirrel`. - -## Avisos sobre Plataformas - -Embora o `autoUpdater` ofereça uma API uniforme para diferentes plataformas, existem diferenças sutis em cada plataforma. - -### macOS - -No macOS, o módulo `autoUpdater` é construído sobre o [Squirrel.Mac][squirrel-mac], o que significa que você não precisa de nenhuma configuração especial para fazê-lo funcionar. Para requerimentos de servidor, você pode ler [Server Support][server-support]. - -### Windows - -No Windows, você deve instalar seu aplicativo na máquina de um usuário antes que possa usar o auto-updater, então é recomendado utilizar o módulo [grunt-electron-installer][installer] para gerar um instalador do Windows. - -O instalador gerado com Squirrel irá criar um ícone de atalho com um [Application User Model ID][app-user-model-id] no formato `com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`, por exemplo: `com.squirrel.slack.Slack` e `com.squirrel.code.Code`. Você precisa usar o mesmo ID para seu aplicativo a API `app.setAppUserModelId`, senão o Windows não conseguirá fixar seu aplicativo corretamente na barra de tarefas. - -A configuração do servidor também é diferente do macOS. Você pode ler a documentação do [Squirrel.Windows][squirrel-windows] para mais detalhes. - -### Linux - -Não há suporte nativo do auto-updater para Linux, então é recomendado utilizar o gerenciador de pacotes da distribuição para atualizar seu aplicativo. - -## Eventos - -O objeto `autoUpdater` emite os seguintes eventos: - -### Evento: 'error' - -Retorna: - -* `error` Error - -Emitido quando há um erro durante a atualização. - -### Evento: 'checking-for-update' - -Emitido quando está verificando se uma atualização foi inicializada. - -### Evento: 'update-available' - -Emitido quando há uma atualização disponível. A atualização é baixada automaticamente. - -### Evento: 'update-not-available' - -Emitido quando não há uma atualização disponível. - -### Evento: 'update-downloaded' - -Retorna: - -* `event` Event -* `releaseNotes` String -* `releaseName` String -* `releaseDate` Date -* `updateURL` String - -Emitido quando uma atualização foi baixada. - -No Windows apenas `releaseName` está disponível. - -## Métodos - -O objeto `autoUpdater` possui os seguintes métodos: - -### `autoUpdater.setFeedURL(url)` - -* `url` String - -Define a `url` e inicializa o auto-updater. A `url` não pode ser alterada uma vez que foi definida. - -### `autoUpdater.checkForUpdates()` - -Pergunta ao servidor se há uma atualização. Você deve chamar `setFeedURL` antes de usar esta API. - -### `autoUpdater.quitAndInstall()` - -Reinicia o aplicativo e instala a atualização após esta ter sido baixada. Só deve ser chamado após o `update-downloaded` ter sido emitido. - -[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/atom/grunt-electron-installer -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx diff --git a/docs-translations/pt-BR/api/browser-window.md b/docs-translations/pt-BR/api/browser-window.md deleted file mode 100644 index 4360296ffe63f..0000000000000 --- a/docs-translations/pt-BR/api/browser-window.md +++ /dev/null @@ -1,622 +0,0 @@ -# BrowserWindow - -A classe `BrowserWindow` lhe dá a habilidade de criar uma janela do browser. Por exemplo: - -```javascript -const BrowserWindow = require('electron').BrowserWindow; - -var win = new BrowserWindow({ width: 800, height: 600, show: false }); -win.on('closed', function() { - win = null; -}); - -win.loadURL('https://github.com'); -win.show(); -``` - -Você também pode criar uma janela sem o chrome utilizando a API [Frameless Window](../../../docs/api/frameless-window.md). - -## Classe: BrowserWindow - -`BrowserWindow` é um [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter). - -Ela cria uma nova `BrowserWindow` com propriedades nativas definidas pelo `options`. - -### `new BrowserWindow([options])` - -`options` Objeto (opcional), propriedades: - -* `width` Integer - Largura da janela em pixels. O padrão é `800`. -* `height` Integer - Altura da janela em pixels. O padrão é `600`. -* `x` Integer - Deslocamento da janela da esquerda da tela. O padrão é centralizar a janela. -* `y` Integer - Deslocamento da janela do topo da tela. O padrão é centralizar a janela. -* `useContentSize` Boolean - `width` e `height` seriam utilizados como o tamanho da página web, o que significa que o tamanho real da janela irá incluir o tamanho da moldura da janela e será um pouco maior. O padrão é `false`. -* `center` Boolean - Mostra a janela no centro da tela. -* `minWidth` Integer - Largura mínima da janela. O padrão é `0`. -* `minHeight` Integer - Altura mínima da janela. O padrão é `0`. -* `maxWidth` Integer - Largura máxima da janela. O padrão é sem limites. -* `maxHeight` Integer - Altura máxima da janela. O padrão é sem limites. -* `resizable` Boolean - Se é possível modificar o tamanho da janela. O padrão é `true`. -* `alwaysOnTop` Boolean - Se a janela deve sempre ficar à frente de outras janelas. O padrão é `false`. -* `fullscreen` Boolean - Se a janela deve estar em tela cheia. Quando definido como `false`, o botão de tela cheia estará escondido ou desabilitado no macOS. O padrão é `false`. -* `skipTaskbar` Boolean - Se deve mostrar a janela na barra de tarefas. O padrão é `false`. -* `kiosk` Boolean - Modo *kiosk*. O padrão é `false`. -* `title` String - Título padrão da janela. O padrão é `"Electron"`. -* `icon` [NativeImage](../../../docs/api/native-image.md) - O ícone da janela, quando omitido no Windows, o ícone do executável é utilizado como o ícone da janela. -* `show` Boolean - Se a janela deve ser exibida quando criada. O padrão é `true`. -* `frame` Boolean - Defina como `false` para criar uma [Frameless Window](../../../docs/api/frameless-window.md). O padrão é `true`. -* `acceptFirstMouse` Boolean - Se o *web view* aceita um evento *mouse-down* que ativa a janela simultaneamente. O padrão é `false`. -* `disableAutoHideCursor` Boolean - Se deve esconder o cursor quando estiver digitando. O padrão é `false`. -* `autoHideMenuBar` Boolean - Esconde a barra de menu automaticamente, a não ser que a tecla `Alt` seja pressionada. O padrão é `false`. -* `enableLargerThanScreen` Boolean - Possibilita que o tamanho da janela seja maior que a tela. O padrão é `false`. -* `backgroundColor` String - Cor de fundo da janela em hexadecimal, como `#66CD00` ou `#FFF`. Só é implementado no Linux e Windows. O padrão é `#000` (preto). -* `darkTheme` Boolean - Força a utilização do tema *dark* na janela, só funciona em alguns ambientes de desktop GTK+3. O padrão é `false`. -* `transparent` Boolean - Torna a janela [transparente](../../../docs/api/frameless-window.md). O padrão é `false`. -* `type` String - Define o tipo da janela, que aplica propriedades adicionais específicas da plataforma. Por padrão é indefinido e será criada uma janela de aplicativo comum. Possíveis valores: - * No Linux, os tipos possíveis são `desktop`, `dock`, `toolbar`, `splash`, - `notification`. - * No macOS, os tipos possíveis são `desktop`, `textured`. O tipo `textured` adiciona a aparência degradê metálica (`NSTexturedBackgroundWindowMask`). O tipo `desktop` coloca a janela no nível do fundo de tela do desktop (`kCGDesktopWindowLevel - 1`). Note que a janela `desktop` não irá receber foco, eventos de teclado ou mouse, mas você pode usar `globalShortcut` para receber entrada de dados ocasionalmente. -* `titleBarStyle` String, macOS - Define o estilo da barra de título da janela. Esta opção está suportada a partir da versão macOS 10.10 Yosemite. Há três possíveis valores: - * `default` ou não definido, resulta na barra de título cinza opaca padrão do Mac. - * `hidden` resulta numa barra de título oculta e a janela de conteúdo no tamanho máximo, porém a barra de título ainda possui os controles padrões de janela ("semáforo") no canto superior esquerdo. - * `hidden-inset` resulta numa barra de título oculta com uma aparência alternativa onde os botões de semáforo estão ligeiramente mais longe do canto da janela. -* `webPreferences` Object - Configurações das características da página web, propriedades: - * `nodeIntegration` Boolean - Se a integração com node está habilitada. O padrão é `true`. - * `preload` String - Define um *script* que será carregado antes que outros scripts rodem na página. Este script sempre terá acesso às APIs do node, não importa se `nodeIntegration` esteja habilitada ou não. O valor deve ser o endereço absoluto do scriot. Quando `nodeIntegration` não está habilitada, o script `preload` pode reintroduzir símbolos globais Node de volta ao escopo global. Veja um exemplo [aqui](process.md#evento-loaded). - * `partition` String - Define a sessão utilizada pela página. Se `partition` começa com `persist:`, a página irá utilizar uma sessão persistente disponível para todas as páginas do aplicativo com a mesma `partition`. Se não houver o prefixo `persist:`, a página irá utilizar uma sessão em memória. Ao utilizar a mesma `partition`, várias páginas podem compartilhar a mesma sessão. Se a `partition` for indefinida, então a sessão padrão do aplicativo será utilizada. - * `zoomFactor` Number - O fator de *zoom* da página, `3.0` representa `300%`. O padrão é `1.0`. - * `javascript` Boolean - Habilita suporte à JavaScript. O padrão é `true`. - * `webSecurity` Boolean - Quando definido como `false`, irá desabilitar a política de mesma origem (Geralmente usando sites de teste por pessoas), e definir `allowDisplayingInsecureContent` e `allowRunningInsecureContent` como - `true` se estas duas opções não tiverem sido definidas pelo usuário. O padrão é `true`. - * `allowDisplayingInsecureContent` Boolean - Permite que uma página https exiba conteúdo como imagens de URLs http. O padrão é `false`. - * `allowRunningInsecureContent` Boolean - Permite que uma página https rode JavaScript, CSS ou plugins de URLs http. O padrão é `false`. - * `images` Boolean - Habilita suporte a imagens. O padrão é `true`. - * `java` Boolean - Habilita suporte a Java. O padrão é `false`. - * `textAreasAreResizable` Boolean - Faz com que os elementos *TextArea* elements tenham tamanho variável. O padrão é `true`. - * `webgl` Boolean - Habiltia suporte a WebGL. O padrão é `true`. - * `webaudio` Boolean - Habilita suporte a WebAudio. O padrão é `true`. - * `plugins` Boolean - Se plugins devem ser habilitados. O padrão é `false`. - * `experimentalFeatures` Boolean - Habilita as características experimentais do Chromium. O padrão é `false`. - * `experimentalCanvasFeatures` Boolean - Habilita as características experimentais de canvas do Chromium. O padrão é `false`. - * `overlayScrollbars` Boolean - Habilita sobreposição das barras de rolagem. O padrão é `false`. - * `overlayFullscreenVideo` Boolean - Habilita sobreposição do vídeo em tela cheia. O padrão é `false`. - * `sharedWorker` Boolean - Habilita suporte a *Shared Worker*. O padrão é `false`. - * `directWrite` Boolean - Habilita o sistema de renderização de fontes *DirectWrite* no Windows. O padrão é `true`. - * `pageVisibility` Boolean - A página é forçada a permanecer visível ou oculta quando definido, em vez de refletir a visibilidade atual da janela. Usuários podem definir como `true` para evitar que os temporizadores do *DOM* sejam suprimidos. O padrão é `false`. - -## Eventos - -O objeto `BrowserWindow` emite os seguintes eventos: - -**Nota:** Alguns eventos só estão disponíveis em sistemas operacionais específicos e estão rotulados como tal. - -### Evento: 'page-title-updated' - -Retorna: - -* `event` Evento - -Emitido quando o documento muda seu título, chamar `event.preventDefault()` previne que o título nativo da janela mude. - -### Evento: 'close' - -Retorna: - -* `event` Evento - -Emitido quando a janela for fechar. É emitido antes dos eventos `beforeunload` e `unload` do DOM. Chamar `event.preventDefault()` cancela o fechamento. - -Normalmente você utiliza o manipulador de eventos do `beforeunload` para decidir se a janela deve ser fechada, que também será chamado quando a janela é recarregada. No Electron, retornar uma string vazia ou `false` cancela o fechamento. Por exemplo: - -```javascript -window.onbeforeunload = function(e) { - console.log('Não quero ser fechada'); - - // Diferente de navegadores comuns, nos quais uma string deve ser retornada e - // o usuário deve confirmar se a janela será fechada, o Electron dá mais opções - // aos desenvolvedores. Retornar uma string vazia ou false cancela o fechamento. - // Você também pode usar a API de diálogo para deixar que o usuário confirme o - // fechamento do aplicativo. - e.returnValue = false; -}; -``` - -### Evento: 'closed' - -Emitido quando a janela é fechada. Após você ter recebido este evento, você deve remover a referência da janela e evitar utilizá-la. - -### Evento: 'unresponsive' - -Emitido quando a página web para de responder. - -### Evento: 'responsive' - -Emitido quando a página web que não respondia volta a responder novamente. - -### Evento: 'blur' - -Emitido quando a janela perde foco. - -### Evento: 'focus' - -Emitido quando a janela ganha foco. - -### Evento: 'maximize' - -Emitido quando a janela é maximizada. - -### Evento: 'unmaximize' - -Emitido quando a janela sai do estado maximizado. - -### Evento: 'minimize' - -Emitido quando a janela é minimizada. - -### Evento: 'restore' - -Emitido quando a janela é restaurada do estado minimizado. - -### Evento: 'resize' - -Emitido quando o tamanho da janela está sendo alterado. - -### Evento: 'move' - -Emitido quando está sendo movida para uma nova posição. - -__Note__: No macOS este evento é apenas um apelido de `moved`. - -### Evento: 'moved' _macOS_ - -Emitido uma vez quando a janela é movida para uma nova posição. - -### Evento: 'enter-full-screen' - -Emitido quando a janela entra no estado tela cheia. - -### Evento: 'leave-full-screen' - -Emitido quando a janela sai do estado de tela cheia. - -### Evento: 'enter-html-full-screen' - -Emitido quando a janela entra no estado tela cheia, ocasionado por uma api de html. - -### Evento: 'leave-html-full-screen' - -Emitido quando a janela sai do estado de tela cheia, ocasionado por uma api de html. - -### Evento: 'app-command' _Windows_ - -Emitido quando um [App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx) é invocado. Estes estão tipicamente relacionado às teclas de mídia do teclado, ou comandos do browser, assim como o botão "Voltar" existente em alguns modelos de mouse no Windows. - -```js -someWindow.on('app-command', function(e, cmd) { - // Navega a janela 'para trás' quando o usuário pressiona o botão voltar do mouse - if (cmd === 'browser-backward' && someWindow.webContents.canGoBack()) { - someWindow.webContents.goBack(); - } -}); -``` - -## Métodos - -O objeto `BrowserWindow` possui os seguintes métodos: - -### `BrowserWindow.getAllWindows()` - -Retorna um array de todas as janelas abertas. - -### `BrowserWindow.getFocusedWindow()` - -Retorna a janela que está focada no aplicativo. - -### `BrowserWindow.fromWebContents(webContents)` - -* `webContents` [WebContents](../../../docs/api/web-contents.md) - -Acha uma janela de acordo com os `webContents` que ela possui. - -### `BrowserWindow.fromId(id)` - -* `id` Integer - -Acha uma janela de acordo com o seu ID. - -### `BrowserWindow.addDevToolsExtension(path)` - -* `path` String - -Adiciona a extenção DevTools localizada no endereço `path`, e retorna o nome da extenção. - -A extenção será lembrada, então você só precisa chamar esta API uma vez, esta API não é para uso de programação. - -### `BrowserWindow.removeDevToolsExtension(name)` - -* `name` String - -Remove a extenção DevTools cujo nome é `name`. - -## Propriedades de Instância - -Objetos criados com `new BrowserWindow` possuem as seguintes propriedades: - -```javascript -// Neste exemplo `win` é a nossa instância -var win = new BrowserWindow({ width: 800, height: 600 }); -``` - -### `win.webContents` - -Todas os eventos e operações relacionados à pagina web serão feitos através do objeto `WebContents` que a esta janela possui. - -Veja a [documentação do `webContents`](../../../docs/api/web-contents.md) para seus métodos e eventos. - -### `win.id` - -O ID único desta janela. - -## Métodos de instância - -Objetos criados com `new BrowserWindow` possuem os seguintes métodos de instância: - -**Nota:** Alguns métodos só estão disponíveis em sistemas operacionais específicos e estão rotulados como tal. - -### `win.destroy()` - -Força o fechamento da janela, os eventos `unload` e `beforeunload` não serão emitidos para a página web, e o evento `close` também não será emitido para esta janela, mas garante que o evento `closed` será emitido. - -Você só deve utilizar este método quando o processo renderizador (página web) congelar. - -### `win.close()` - -Tenta fechar a janela, tem o mesmo efeito que o usuário manualmente clicar o botão de fechar a janela. Entretanto, a página web pode cancelar o fechamento, veja o [evento close](#evento-close). - -### `win.focus()` - -Foca na janela. - -### `win.isFocused()` - -Retorna um boolean, indicando se a janela está com foco. - -### `win.show()` - -Exibe e dá foco à janela. - -### `win.showInactive()` - -Exibe a janela, porém não dá foco à ela. - -### `win.hide()` - -Esconde a janela. - -### `win.isVisible()` - -Retorna um boolean, indicando se a janela está visível para o usuário. - -### `win.maximize()` - -Maximiza a janela. - -### `win.unmaximize()` - -Sai do estado maximizado da janela. - -### `win.isMaximized()` - -Retorna um boolean, indicando se a janela está maximizada. - -### `win.minimize()` - -Minimiza a janela. Em algumas plataformas, a janela minimizada será exibida no *Dock*. - -### `win.restore()` - -Restaura a janela do estado minimizado para o estado anterior. - -### `win.isMinimized()` - -Retorna um boolean, indicando se a janela está minimizada. - -### `win.setFullScreen(flag)` - -* `flag` Boolean - -Define se a janela deve estar em modo tela cheia. - -### `win.isFullScreen()` - -Retorna um boolean, indicando se a janela está em modo tela cheia. - -### `win.setAspectRatio(aspectRatio[, extraSize])` _macOS_ - -* `aspectRatio` A proporção que queremos manter para uma porção do conteúdo da *view*. -* `extraSize` Object (opcional) - O tamanho extra não incluído enquanto a proporção é mantida. Propriedades: - * `width` Integer - * `height` Integer - -Isto fará com que a janela mantenha sua proporção. O `extraSize` permite que o desenvolvedor tenha espaço, definido em pixels, não incluídos no cálculo da proporção. Esta API já leva em consideração a diferença entre o tamanho da janela e o tamanho de seu conteúdo. - -Suponha que exista uma janela normal com um *player* de vídeo HD e seus controles associados. Talvez tenha 15 pixels de controles na borda esquerda, 25 pixels de controles na borda direita e 50 abaixo do player. Para que seja mantida a proporção de 16:9 (proporção padrão para HD em 1920x1080) no próprio player, nós chamaríamos esta função com os argumentos 16/9 e [ 40, 50 ]. Para o segundo argumento, não interessa onde a largura e altura extras estão no conteúdo da view--apenas que elas existam. Apenas some qualquer área de largura e altura extras que você tem dentro da view do conteúdo. - -### `win.setBounds(options)` - -`options` Object, propriedades: - -* `x` Integer -* `y` Integer -* `width` Integer -* `height` Integer - -Redefine o tamanho e move a janela para `width`, `height`, `x`, `y`. - -### `win.getBounds()` - -Retorna um objeto que contém a largura, altura, posição x e y da janela. - -### `win.setSize(width, height)` - -* `width` Integer -* `height` Integer - -Redefine o tamanho da janela para largura `width` e altura `height`. - -### `win.getSize()` - -Retorna um array que contém a largura e altura da janela. - -### `win.setContentSize(width, height)` - -* `width` Integer -* `height` Integer - -Redefine a área de cliente da janela (a página web) para largura `width` e altura `height`. - -### `win.getContentSize()` - -Retorna um array que contém a largura e altura da área de cliente da janela. - -### `win.setMinimumSize(width, height)` - -* `width` Integer -* `height` Integer - -Define o tamanho mínimo da janela para largura `width` e altura `height`. - -### `win.getMinimumSize()` - -Retorna uma array que contém o tamanho mínimo da largura e altura da janela. - -### `win.setMaximumSize(width, height)` - -* `width` Integer -* `height` Integer - -Define o tamanho máximo da janela para largura `width` e altura `height`. - -### `win.getMaximumSize()` - -Retorna uma array que contém o tamanho máximo da largura e altura da janela. - -### `win.setResizable(resizable)` - -* `resizable` Boolean - -Define se a janela pode ter seu tamanho redefinido manualmente pelo usuário. - -### `win.isResizable()` - -Retorna um boolean indicando se a janela pode ter seu tamanho redefinido manualmente pelo usuário. - -### `win.setAlwaysOnTop(flag)` - -* `flag` Boolean - -Define se a janela deve estar sempre em cima de outras janelas. Após definir isso, a janela continua sendo uma janela normal, não uma janela *toolbox* que não pode receber foco. - -### `win.isAlwaysOnTop()` - -Retorna um boolean indicando se a janela está sempre em cima de outras janelas. - -### `win.center()` - -Move a janela para o centro da tela. - -### `win.setPosition(x, y)` - -* `x` Integer -* `y` Integer - -Move a janela para `x` e `y`. - -### `win.getPosition()` - -Retorna um array com a posição atual da janela. - -### `win.setTitle(title)` - -* `title` String - -Muda o título da janela nativa para `title`. - -### `win.getTitle()` - -Retorna o título da janela nativa. - -**Nota:** O título da página web pode ser diferente do título da janela nativa. - -### `win.flashFrame(flag)` - -* `flag` Boolean - -Inicia ou para de piscar a janela para atrair a atenção do usuário. - -### `win.setSkipTaskbar(skip)` - -* `skip` Boolean - -Faz com que a janela não apareça na barra de tarefas. - -### `win.setKiosk(flag)` - -* `flag` Boolean - -Entra ou sai do modo *kiosk*. - -### `win.isKiosk()` - -Retorna um boolean indicando se janela está no modo *kiosk*. - -### `win.hookWindowMessage(message, callback)` _Windows_ - -* `message` Integer -* `callback` Function - -Engancha uma mensagem de janela. O `callback` é chamado quando a mensagem é recebida no WndProc. - -### `win.isWindowMessageHooked(message)` _Windows_ - -* `message` Integer - -Retorna `true` ou `false` indicando se a mensagem está enganchada ou não. - -### `win.unhookWindowMessage(message)` _Windows_ - -* `message` Integer - -Desengancha a mensagem de janela. - -### `win.unhookAllWindowMessages()` _Windows_ - -Desengancha todas as mensagens de janela. - -### `win.setRepresentedFilename(filename)` _macOS_ - -* `filename` String - -Define o endereço do arquivo que a janela representa, e o ícone do arquivo será exibido na barra de título da janela. - -### `win.getRepresentedFilename()` _macOS_ - -Retorna o endereço do arquivo que a janela representa. - -### `win.setDocumentEdited(edited)` _macOS_ - -* `edited` Boolean - -Define se o documento da janela foi editado, e o ícone na barra de título se torna cinza quando definido como `true`. - -### `win.isDocumentEdited()` _macOS_ - -Retorna um boolean indicando se o documento da janela foi editado. - -### `win.focusOnWebView()` - -### `win.blurWebView()` - -### `win.capturePage([rect, ]callback)` - -* `rect` Object (opcional)- A área da página a ser capturada. Propriedades: - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer -* `callback` Function - -Captura uma imagem da página dentro do `rect`. Após completar, `callback` será chamada com `callback(imagem)`. `imagem` é uma instância de [NativeImage](../../../docs/api/native-image.md) que guarda dados sobre a imagem. Omitir `rect` captura toda a página visível. - -### `win.loadURL(url[, options])` - -Igual a `webContents.loadURL(url[, options])`. - -### `win.reload()` - -Igual a `webContents.reload`. - -### `win.setMenu(menu)` _Linux_ _Windows_ - -* `menu` Menu - -Define `menu` como a barra de menu da janela, definir como `null` remove a barra de menu. - -### `win.setProgressBar(progress)` - -* `progress` Double - -Define o valor do progresso na barra de progresso. Extensão válida é [0, 1.0]. - -Remove a barra de progresso quando `progress` < 0. -Muda para o modo indeterminado quando `progress` > 1. - -Na plataforma Linux, apenas suporta o ambiente de desktop Unity, você precisa definir o nome do arquivo como `*.desktop` no campo `desktopName` no `package.json`. Por padrão, irá assumir `app.getName().desktop`. - -### `win.setOverlayIcon(overlay, description)` _Windows 7+_ - -* `overlay` [NativeImage](../../../docs/api/native-image.md) - o ícone a ser exibido no canto inferior direito da barra de tarefas. Se este parâmetro for `null`, a sobreposição é eliminada. -* `description` String - uma descrição que será providenciada a leitores de tela de acessibilidade. - -Define uma sobreposição de 16px sobre o ícone da barra de tarefas atual, geralmente utilizado para indicar algum tipo de status de aplicação, ou notificar passivamente o usuário. - -### `win.setThumbarButtons(buttons)` _Windows 7+_ - -`buttons` Array de objetos `button`: - -`button` Object, propriedades: - -* `icon` [NativeImage](../../../docs/api/native-image.md) - O ícone exibido na barra de ferramentas miniatura. -* `tooltip` String (opcional) - O texto do balão de dica do botão. -* `flags` Array (opcional) - Controla estados e comportamentos específicos do botão. Utiliza `enabled` por padrão. Pode incluir as seguintes strings: - * `enabled` - O botão está ativo e disponível para o usuário. - * `disabled` - O botão está desabilitado. Está presente, mas possui um estado visual indicando que não irá responder às ações do usuário. - * `dismissonclick` - Quando o botão é clicado, o *flyout* do botão da barra de tarefas fecha imediatamente. - * `nobackground` - Não desenhe a borda do botão, apenas utilize a imagem. - * `hidden` - O botão não é exibido para o usuário. - * `noninteractive` - O botão está habilitado, mas não interage; Não é exibido o estado de botão pressionado. Este valor está destinado a instâncias nas quais o botão é utilizado em uma notificação. -* `click` - Função - -Adiciona uma barra de ferramentes miniatura com um conjunto de botões específicos à imagem miniatura de uma janela no layout de um botão de barra de tarefas. Retorna um objeto `Boolean` indicando se a miniatura foi adicionada com sucesso. - -O número de botões na barra de ferramentas miniatura não deve ser maior que 7 devido ao espaço limitado. Uma vez que você define a barra de ferramentas miniatura, ela não pode ser removida por causa da limitação da plataforma. Mas você pode chamar a API com um array vazio para limpar todos os botões. - -### `win.showDefinitionForSelection()` _macOS_ - -Mostra um dicionário *pop-up* que procura a palavra selecionada na página. - -### `win.setAutoHideMenuBar(hide)` - -* `hide` Boolean - -Define se a barra de menu da janela deve se esconder automaticamente. Uma vez que for definida, a barra de menu só será exibida quando usuários pressionarem a tecla `Alt`. - -Se a barra de menu já estiver visível, chamar `setAutoHideMenuBar(true)` não irá escondê-la imediatamente. - -### `win.isMenuBarAutoHide()` - -Retorna um boolean indicando se a barra de menu se esconde automaticamente. - -### `win.setMenuBarVisibility(visible)` - -* `visible` Boolean - -Define se a barra de menu deve ser visível. Se a barra de menu se esconde automaticamente, os usuários ainda podem exibí-la ao pressionar a tecla `Alt`. - -### `win.isMenuBarVisible()` - -Retorna um boolean indicando se a barra de menu está visível. - -### `win.setVisibleOnAllWorkspaces(visible)` - -* `visible` Boolean - -Define se a janela deve estar visível em todos os *workspaces*. - -**Nota:** Esta API não faz nada no Windows. - -### `win.isVisibleOnAllWorkspaces()` - -Retorna um boolean indicando se a janela está visível em todos os *workspaces*. - -**Nota:** Esta API sempre retorna `false` no Windows. diff --git a/docs-translations/pt-BR/api/power-monitor.md b/docs-translations/pt-BR/api/power-monitor.md deleted file mode 100644 index 0075601293541..0000000000000 --- a/docs-translations/pt-BR/api/power-monitor.md +++ /dev/null @@ -1,35 +0,0 @@ -# powerMonitor - -> Monitorar as mudanças de estado de energia. - -Você só pode usá-lo no processo principal. Você não deve usar este módulo até que o evento `ready` do modulo `app` seja emitido. - -Por exemplo: - -```javascript -app.on('ready', () => { - require('electron').powerMonitor.on('suspend', () => { - console.log('O sistema está indo dormir'); - }); -}); -``` - -## Eventos - -O módulo `power-monitor` emite os seguintes eventos: - -### Evento: 'suspend' - -Emitido quando o sistema está a suspender. - -### Evento: 'resume' - -Emitido quando o sistema está a retomar. - -### Evento: 'on-ac' _Windows_ - -Emitido quando o sistema muda para energia AC. - -### Evento: 'on-battery' _Windows_ - -Emitido quando o sistema muda para a energia da bateria. diff --git a/docs-translations/pt-BR/api/process.md b/docs-translations/pt-BR/api/process.md deleted file mode 100644 index 814c4c15e31eb..0000000000000 --- a/docs-translations/pt-BR/api/process.md +++ /dev/null @@ -1,48 +0,0 @@ -# process -O objeto `process` no Electron tem as seguintes diferenças do objeto no upstream node: - -* `process.type` String - Tipo de processo, pode ser `browser` (processo principal) -ou `renderer`. -* `process.versions.electron` String - Versão do Electron. -* `process.versions.chrome` String - Versão do Chromium. -* `process.resourcesPath` String - Caminho para o código fonte JavaScript. -* `process.mas` Boolean - Para build da Mac App Store, este valor é `true`, para outros builds é `undefined`. - -## Eventos - -### Evento: 'loaded' - -Emitido quando o Electron carregou seu script de inicialização interno e está começando a carregar a página web ou o script principal. - -Pode ser utilizado pelo script pré-carregamento (preload.js abaixo) para adicionar símbolos globais do Node removidos para o escopo global quando a integração do node é desligada: - -```js -// preload.js -var _setImmediate = setImmediate; -var _clearImmediate = clearImmediate; -process.once('loaded', function() { - global.setImmediate = _setImmediate; - global.clearImmediate = _clearImmediate; -}); -``` - -## Propriedades - -### `process.noAsar` - -Definir isto para `true` pode desabilitar o suporte para arquivos `asar` nos módulos nativos do Node. - -# Métodos - -O objeto `process` tem os seguintes métodos: - -### `process.hang` - -Faz com que o *thread* principal do processo congele. - -### `process.setFdLimit(maxDescriptors)` _macOS_ _Linux_ - -* `maxDescriptors` Integer - -Define o limite do arquivo descritor para `maxDescriptors` ou para o limite do OS, -o que for menor para o processo atual. diff --git a/docs-translations/pt-BR/api/shell.md b/docs-translations/pt-BR/api/shell.md deleted file mode 100644 index 65e0a2d426369..0000000000000 --- a/docs-translations/pt-BR/api/shell.md +++ /dev/null @@ -1,43 +0,0 @@ -# shell - -O módulo `shell` fornece funções relacionadas à integração com o desktop. - -Um exemplo para abrir uma URL no browser padrão do usuário: - -```javascript -const shell = require('shell'); -shell.openExternal('https://github.com'); -``` - -## Métodos - -O módulo `shell` tem os seguintes métodos: - -### `shell.showItemInFolder(fullPath)` - -* `fullPath` String - -Exibe o arquivo num gerenciador de arquivos. Se possivel, seleciona o arquivo. - -### `shell.openItem(fullPath)` - -* `fullPath` String - -Abre o arquivo de maneira padrão do desktop. - -### `shell.openExternal(url)` - -* `url` String - -Abre a URL de protocolo externo de maneira padrão do desktop. (Por -exemplo, mailto: URLs no programa de email padrão do usuário) - -### `shell.moveItemToTrash(fullPath)` - -* `fullPath` String - -Move o arquivo para a lixeira e retorna um status boolean com o resultado da operação. - -### `shell.beep()` - -Toca um som beep. \ No newline at end of file diff --git a/docs-translations/pt-BR/api/window-open.md b/docs-translations/pt-BR/api/window-open.md deleted file mode 100644 index eb2b31cd0e4e6..0000000000000 --- a/docs-translations/pt-BR/api/window-open.md +++ /dev/null @@ -1,67 +0,0 @@ -# The `window.open` function - -Qunado `window.open` é chamado para criar uma nova janela de uma pagina web uma nova instância de `BrowserWindow` será criado para a `url` e um proxy será devolvido para o `windows.open`, para permitir que a página tenha limitado controle sobre ele. - -O proxy tem funcionalidade limitada padrão implementada para ser compatível com as páginas web tradicionais. -Para controle total da nova janela você deveria criar um `BrowserWindow` diretamente - - -The newly created `BrowserWindow` will inherit parent window's options by -default, to override inherited options you can set them in the `features` -string. - -O recém-criado `BrowserWindow` herdará as opções da janela pai por padrão, para substituir as opções herdadas você pode definilos no `features`(string). -### `window.open(url[, frameName][, features])` - -* `url` String -* `frameName` String (opcional) -* `features` String (opcional) - -Cria uma nova janela e retorna uma instância da classe `BrowserWindowProxy'. - -A string `features` segue o formato padrão do browser, mas cada recurso (feature) tem que ser um campo de opções do `BrowserWindow`. - -### `window.opener.postMessage(message, targetOrigin)` - -* `message` String -* `targetOrigin` String - -Envia uma mensagem para a janela pai com a origem especificada ou `*` preferência de origem não especificada. -Sends a message to the parent window with the specified origin or `*` -origin preference. - -## Class: BrowserWindowProxy - -O objeto `BrowserWindowProxy` é retornado de `window.open` e fornece uma funcionalidade limitada para a janela filha. - -### `BrowserWindowProxy.blur()` - -Remove o foco da janela filha. - -### `BrowserWindowProxy.close()` - -Forçadamente fecha a janela filha sem chamar o evento de descarregamento. - -### `BrowserWindowProxy.closed` - -Define como true após a janela filha ficar fechada. - -### `BrowserWindowProxy.eval(code)` - -* `code` String - -Avalia o código na jánela filha. - -### `BrowserWindowProxy.focus()` - -Concentra-se a janela filha (traz a janela para frente) -### `BrowserWindowProxy.postMessage(message, targetOrigin)` - -* `message` String -* `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. diff --git a/docs-translations/pt-BR/development/build-instructions-linux.md b/docs-translations/pt-BR/development/build-instructions-linux.md deleted file mode 100644 index 5e8ffe447804b..0000000000000 --- a/docs-translations/pt-BR/development/build-instructions-linux.md +++ /dev/null @@ -1,142 +0,0 @@ -# Instruções de Build (Linux) - -Siga as orientações abaixo pra fazer o build do Electron no Linux. - -## Pré-requisitos - -* Python 2.7.x. Algumas distribuições como CentOS ainda usam Python 2.6.x, - então você precisa checar a sua versão do Python com `python -V`. -* Node.js v0.12.x. Há várias maneiras de instalar o Node. Você pode baixar o - código fonte do [Node.js](http://nodejs.org) e compilar a partir dele. - Fazer isto permite que você instale o Node no seu próprio diretório home - como um usuário comum. - Ou tente repositórios como [NodeSource](https://nodesource.com/blog/nodejs-v012-iojs-and-the-nodesource-linux-repositories). -* Clang 3.4 ou mais recente. -* Cabeçalhos de desenvolvimento do GTK+ e libnotify. - -No Ubuntu, instale as seguintes bibliotecas: - -```bash -$ sudo apt-get install build-essential clang libdbus-1-dev libgtk2.0-dev \ - libnotify-dev libgnome-keyring-dev libgconf2-dev \ - libasound2-dev libcap-dev libcups2-dev libxtst-dev \ - libxss1 libnss3-dev gcc-multilib g++-multilib -``` - -No Fedora, instale as seguintes bibliotecas: - -```bash -$ sudo yum install clang dbus-devel gtk2-devel libnotify-devel libgnome-keyring-devel \ - xorg-x11-server-utils libcap-devel cups-devel libXtst-devel \ - alsa-lib-devel libXrandr-devel GConf2-devel nss-devel -``` - -Outras distribuições podem oferecer pacotes similares para instalação através -do gerenciador de pacotes como o pacman. Ou você pode compilar a partir do -código fonte. - -## Se Você Utilizar Máquinas Virtuais Para Fazer O Build - -Se você planeja fazer o build do Electron numa máquina virtual, você vai precisar -de um container de tamanho fixo de pelo menos 25 gigabytes. - -## Baixando o Código - -```bash -$ git clone https://github.com/electron/electron.git -``` - -## Bootstrapping - -O script de *boostrap* irá baixar todas as dependências de build necessárias -e criar os arquivos de projeto do build. Você deve ter o Python 2.7.x para -executar o script com sucesso. -Baixar certos arquivos pode demorar bastante. Note que estamos utilizando -`ninja` para fazer o build do Electron, então não há um `Makefile` gerado. - -```bash -$ cd electron -$ ./script/bootstrap.py -v -``` - -### Compilação Cruzada - -Se você quer fazer o build para `arm`, você também deve instalar as seguintes -dependências: - -```bash -$ sudo apt-get install libc6-dev-armhf-cross linux-libc-dev-armhf-cross \ - g++-arm-linux-gnueabihf -``` - -E para fazer a compilação cruzada para `arm` ou `ia32`, você deve passar -o parâmetro `--target_arch` para o script `bootstrap.py`: - -```bash -$ ./script/bootstrap.py -v --target_arch=arm -``` - -## Building - -Se você quiser fazer o build para `Release` e `Debug`: - -```bash -$ ./script/build.py -``` - -Este script irá fazer com que um executável bem pesado do Electron seja -criado no diretório `out/R`. O arquivo possui mais de 1.3 gigabytes. -Isso acontece por que o binário do Release contém símbolos de debugging. -Para reduzir o tamanho do arquivo, rode o script `create-dist.py`: - -```bash -$ ./script/create-dist.py -``` - -Isso irá colocar uma distribuição funcional com arquivos muito menores -no diretório `dist`. Depois de rodar o script `create-dist.py`, talvez -você queira remover o binário de 1.3+ gigabytes que ainda está em `out/R`. - -Você também pode fazer apenas o build de `Debug`: - -```bash -$ ./script/build.py -c D -``` - -Depois de completar o build, você pode encontrar o binário de debug do `electron` -em `out/D`. - -## Limpando - -Para limpar os arquivos de build: - -```bash -$ ./script/clean.py -``` - -## Troubleshooting - -Certifique-se de que você tenha instalado todas as dependências do build. - -### Error While Loading Shared Libraries: libtinfo.so.5 - -O `clang` prebuilt irá tentar fazer o link com `libtinfo.so.5`. Dependendo -da arquitetura do host, faça um link simbólico para o `libncurses` apropriado: - -```bash -$ sudo ln -s /usr/lib/libncurses.so.5 /usr/lib/libtinfo.so.5 -``` - -## Testes - -Teste suas modificações conforme o estilo de código do projeto utilizando: - -```bash -$ ./script/cpplint.py -``` - -Teste funcionalidade utilizando: - -```bash -$ ./script/test.py -``` diff --git a/docs-translations/pt-BR/development/coding-style.md b/docs-translations/pt-BR/development/coding-style.md deleted file mode 100644 index acfdf7e3dbd71..0000000000000 --- a/docs-translations/pt-BR/development/coding-style.md +++ /dev/null @@ -1,26 +0,0 @@ -# Estilo de Codificação - -Estas são as diretrizes de estilo para codificar no Electron. - -## C++ e Python - -Para C++ e Python, seguimos o [Estilo de Codificação](http://www.chromium.org/developers/coding-style) do projeto Chromium. Há também um -script `script/cpplint.py` para verificar se todos os arquivos estão em conformidade. - -A versão Python que estamos usando agora é a Python 2.7. - -O código C++ usa várias abstrações e tipos do Chromium, por isso é recomendado familiarizar-se com eles. Um bom lugar para começar é com a documentação do Chromium [Important Abstractions and Data Structures](https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures). O documento menciona alguns tipos especiais, *scoped types* (que automaticamente liberam sua memória ao sair do escopo), mecanismos de *log* etc. - -## CoffeeScript - -Para CoffeeScript, seguimos o [Guia de Estilo] (https://github.com/styleguide/javascript) do GitHub com as seguintes regras: - -* Os arquivos **NÃO DEVEM** terminar com uma nova linha, porque queremos corresponder aos padrões de estilo Google. - -* Os nomes dos arquivos devem ser concatenados com `-` em vez de `_`, por exemplo, `file-name.coffee` em vez de `file_name.coffee`, porque no [github/atom](https://github.com/github/atom) os nomes dos módulos são geralmente da forma `module-name`. Esta regra só se aplica aos arquivos com extensão `.coffee`. -* -## Nomes de APIs - -Ao criar uma nova API, devemos preferencialmente utilizar métodos getters e setters em vez do -estilo de uma função única do jQuery. Por exemplo, `.getText()` e `.setText(text)` são preferenciais a `.text([text])`. Existe uma -[discussão](https://github.com/electron/electron/issues/46) sobre este assunto. diff --git a/docs-translations/pt-BR/development/source-code-directory-structure.md b/docs-translations/pt-BR/development/source-code-directory-structure.md deleted file mode 100644 index 77c01d79113e5..0000000000000 --- a/docs-translations/pt-BR/development/source-code-directory-structure.md +++ /dev/null @@ -1,53 +0,0 @@ -# Estrutura de Diretórios do Código-Fonte - -O código-fonte do Electron é separado em algumas partes, seguindo principalmente as convenções de separação do chromium. - -Você pode se familiarizar com a [arquitetura de multiprocessamento ](http://dev.chromium.org/developers/design-documents/multi-process-architecture) do Chromium para entender melhor o código-fonte. - - -## Estrutura do Código-Fonte - -``` -Electron -├──atom - Código fonte do Electron. -| ├── app - Código de inicialização. -| ├── browser - A interface incluíndo a janela principal, UI, e todas as coisas do processo principal. Ele se comunica com o renderizador para gerenciar as páginas web. -| |   ├── lib - Código Javascript para inicializar o processo principal. -| | ├── ui - Implementação da UI para plataformas distintas. -| | | ├── cocoa - Código-fonte específico do cocoa . -| | | ├── gtk - Código-font específico do GTK+. -| | | └── win - Código-fonte específico do Windows GUI. -| | ├── default_app - A página padrão é mostrada quando -| | | Electron inicializa sem fornecer um app. -| | ├── api - Implementação do processo principal das APIs -| | | └── lib - Código Javascript, parte da implementação da API. -| | ├── net - Código relacionado a rede. -| | ├── mac - Código fonte em Object-c, específico para Mac. -| | └── resources - Icones, arquivos dependentes da plataforma, etc. -| ├── renderer - Código que é executado no processo de renderização. -| | ├── lib - Parte do código Javascript de inicialização do renderizador. -| | └── api - Implementação das APIs para o processo de renderizaçãp. -| | └── lib - Código Javascript, parte da implementação da API. -| └── common - Código que utiliza ambos os processos, o principal e o de rendezição, -| ele inclui algumas funções utilitárias e códigos para integrar com ciclo de mensagens do node no ciclo de mensagens do Chromium. -| ├── lib - Código Javascript comum para a inicialização. -| └── api - A implementação de APIs comuns e fundamentação dos -| módulos integrados com Electron's. -| └── lib - Código Javascript, parte da implementação da API. -├── chromium_src - Código-fonte copiado do Chromium. -├── docs - Documentação. -├── spec - Testes Automáticos. -├── atom.gyp - Regras de compilação do Electron. -└── common.gypi - Configuração específica do compilador e regras de construção para outros componentes - como `node` e `breakpad`. -``` - -## Estrutura de Outros Diretórios. - -* **script** - Scripts utilizado para fins de desenvolvimento como building, packaging, testes, etc. -* **tools** - Scripts auxiliares, utilizados pelos arquivos gyp, ao contrário do`script`, os scripts colocados aqui nunca devem ser invocados diretamente pelos usuários. -* **vendor** - Dependências de código-fonte de terceiros, nós não utilizamos `third_party` como nome porque ele poderia ser confundido com o diretório homônimo existente no código-fonte do Chromium. -* **node_modules** - Módulos de terceiros em node usados para compilação -* **out** - Diretório temporário saída do `ninja`. -* **dist** - Diretório temporário do `script/create-dist.py` ao criar uma distribuição -* **external_binaries** - Binários baixados de Frameworks de terceiros que não suportam a compilação com `gyp`. diff --git a/docs-translations/pt-BR/styleguide.md b/docs-translations/pt-BR/styleguide.md deleted file mode 100644 index 40a3a8a7f1001..0000000000000 --- a/docs-translations/pt-BR/styleguide.md +++ /dev/null @@ -1,77 +0,0 @@ -# Styleguide do Electron - -Localize a seção apropriada para a sua tarefa: [Lendo a documentação do Electron](#) -ou [Escrevendo documentação para o Electron](#). - -## Escrevendo documentação para o Electron - -Estas são as formas que escrevemos a documentação do Electron. - -- No Máximo um `h1` por página. -- Usar `bash` ao invés de` cmd` em blocos de código (por causa do syntax highlighter). -- Títulos `h1` deve coincidir com o nome do objeto (i.e. `browser-window` → -`BrowserWindow`). -- Nomes de arquivos separados por hífen. -- Adicionar pelo menos uma descrição a cada frase. -- Métodos de cabeçalhos são envolto em `code`. -- Cabeçalhos de eventos são envolto em single 'quotation' marks. -- Não há listas com identação com mais de 2 níveis (por causa do markdown). -- Adicione títulos nas seções: Events, Class Methods e Instance Methods. -- Use 'will' ao invéis de 'would' ao descrever os resultados. -- Eventos e métodos são com cabeçalhos `h3`. -- Argumentos opcionais escritos como `function (required[, optional])`. -- Argumentos opcionais são indicados quando chamado na lista. -- Comprimento da linha é de 80 caracteres com colunas quebradas. -- Métodos específicos para uma plataforma são postos em itálico seguindo o cabeçalho do método. - - ```### `method(foo, bar)` _macOS_``` - -## Lendo a documentação do Electron - -Aqui estão algumas dicas de como entender a sintaxe da documentacão do Electron. - -### Métodos - -Um exemplo de [method](https://developer.mozilla.org/en-US/docs/Glossary/Method) -documentação: - ---- - -`methodName(required[, optional]))` - -* `require` String, **required** -* `optional` Integer - ---- - -O nome do método é seguido pelos seus argumentos. Argumentos opcionais são -simbolizada por colchetes que cercam o argumento opcional, bem como a vírgula -requerido se este argumento opcional segue outro argumento. - -Abaixo o método é para obter informações detalhadas sobre cada um dos argumentos. O tipo -de argumento é simbolizada por qualquer um dos tipos mais comuns: [`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 Referência/Global_Objects/Object), [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) -ou um tipo personalizado como o de Electron [`webContent`](api/web-content.md). - -### Eventos - -Um exemplo de [evento](https://developer.mozilla.org/en-US/docs/Web/API/Event) -documentação: - ---- - -Event: 'wake-up' - -Returns: - -* `time` String - ---- - -O evento é uma cadeia que é utilizada após um `.on` em um método listner. Se ela retorna --lhe um valor e seu tipo é observado abaixo. Se você quiser um método para esctuar e responder -crie algo parecido com o exemplo abaixo: - -```javascript -Alarm.on('wake-up', function(time) { - console.log(time) -}) -``` \ No newline at end of file diff --git a/docs-translations/pt-BR/tutorial/application-distribution.md b/docs-translations/pt-BR/tutorial/application-distribution.md deleted file mode 100644 index d2bc020bedfe8..0000000000000 --- a/docs-translations/pt-BR/tutorial/application-distribution.md +++ /dev/null @@ -1,117 +0,0 @@ -# Distribuição de aplicações - -Para distribuir sua aplicação com o Electron, você deve nomear o diretório que contém sua aplicação como -`app` e dentro deste diretório colocar os recursos que você está utilizando (no macOS -`Electron.app/Contents/Resources/`, -no Linux e no Windows é em `resources/`): - -No macOS: - -```text -electron/Electron.app/Contents/Resources/app/ -├── package.json -├── main.js -└── index.html -``` - -No Windows e Linux: - -```text -electron/resources/app -├── package.json -├── main.js -└── index.html -``` - -Logo após execute `Electron.app` (ou `electron` no Linux e `electron.exe` no Windows), -e o Electron iniciaria a aplicação. O diretório `electron` será utilizado para criar a distribuição para -usuários finais. - -## Empacotando sua aplicação em um arquivo. - -Além de copiar todos os seus arquivos fontes para a distribuição, você também pode -empacotar seu aplicativo em um arquivo [asar](https://github.com/atom/asar) para evitar -de expor seu código fonte aos usuários finais. - -Para usar um arquivo `asar` ao invés da pasta `app` você precisa mudar o nome do -arquivo para `app.asar` e colocá-lo sob o diretório de recursos do Electron como -mostrado abaixo, então o Electron vai ler o arquivo e iniciar a aplicação a partir dele. - -No macOS: - -```text -electron/Electron.app/Contents/Resources/ -└── app.asar -``` - -No Windows e Linux: - -```text -electron/resources/ -└── app.asar -``` - -Mais detalhes podem ser encontrados em [Empacotamento da aplicação](../../../docs/tutorial/application-packaging.md). - -## Renomeando a marca Electron na sua distribuição - -Depois de empacotar seu aplicativo Electron, você vai querer renomear a marca Electron -antes de distribuí-lo aos usuários. - -### Windows - -Você pode renomear `electron.exe` para o nome que desejar e editar o seu ícone e outras -informações com ferramentas como [rcedit](https://github.com/atom/rcedit). - -### macOS - -Você pode renomear `Electron.app` para o nome que desejar e também pode mudar o nome -do `CFBundleDisplayName`, `CFBundleIdentifier` e os campos em `CFBundleName` -nos seguinte arquivos: - -* `Electron.app/Contents/Info.plist` -* `Electron.app/Contents/frameworks/Electron Helper.app/Contents/Info.plist` - -Você também pode renomear o arquivo de ajuda para evitar a exibição de `Electron Helper` no -Monitor de Atividades, mas certifique-se de também renomear o arquivo de ajuda no executável do -aplicativo. - -A estrutura de uma aplicação renomada seria assim: - -``` -MyApp.app/Contents -├── Info.plist -├── MacOS/ -│   └── MyApp -└── Frameworks/ - ├── MyApp Helper EH.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper EH - ├── MyApp Helper NP.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper NP - └── MyApp Helper.app - ├── Info.plist - └── MacOS/ -    └── MyApp Helper -``` - -### Linux - -Você pode renomear o executável `electron` para o nome que desejar. - -## Renomeando a marca Electron do código fonte. - -Também é possível fazer renomear a marca Electron do código fonte, alterando o nome do produto e -reconstruí-lo a partir da fonte, para fazer isso você precisa modificar o arquivo `atom.gyp`. - -### grunt-build-atom-shell - -A modificação do código fonte do Electron para ganhar a sua marca pode ser muito complexa, por isso, -uma tarefa para o Grunt foi criado e irá cuidar desta tarefa automaticamente para você: -[grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell). - -Esta tarefa irá automaticamente editar o arquivo `.gyp`, compilar o código -e reconstruir os módulos nativos da aplicação para utilizar o novo nome. diff --git a/docs-translations/pt-BR/tutorial/application-packaging.md b/docs-translations/pt-BR/tutorial/application-packaging.md deleted file mode 100644 index 209188b2f5f9b..0000000000000 --- a/docs-translations/pt-BR/tutorial/application-packaging.md +++ /dev/null @@ -1,158 +0,0 @@ -# Empacotamento da aplicação - -Para proteger os recursos e o código fonte da sua aplicação você pode optar por -empacotar a sua aplicação em um arquivo [asar](https://github.com/atom/asar), isto é possível com poucas -alterações em seu código. - -## Gerando um arquivo `asar` - -Um arquivo [asar][asar] é um formato parecido com tar ou zip bem simples que concatena arquivos -em um único arquivo. O Electron pode ler arquivos arbitrários a partir dele sem descompacatar -o arquivo inteiro. - -Passos para empacotar a sua aplicação em um arquivo `asar`: - -### 1. Instale o utilitário asar - -```bash -$ npm install -g asar -``` - -### 2. Empacote a sua aplicação - -```bash -$ asar pack your-app app.asar -``` - -## Usando arquivos `asar` - -No Electron existem dois conjuntos de APIs: Node APIs fornecidas pelo Node.js e Web -APIs fornecidas pelo Chromium. Ambas as APIs suportam a leitura de arquivos `asar`. - -### Node API - -As API's do Node como `fs.readFile` e `require` tratam os pacotes `asar` -como diretórios virtuais e os arquivos dentro dele como arquivos normais. - -Por exemplo, temos um arquivo `example.asar` sob `/path/to`: - -```bash -$ asar list /path/to/example.asar -/app.js -/file.txt -/dir/module.js -/static/index.html -/static/main.css -/static/jquery.min.js -``` - -Lendo um arquivo em pacote `asar`: - -```javascript -var fs = require('fs'); -fs.readFileSync('/path/to/example.asar/file.txt'); -``` - -Listando todos os arquivos a partir da raiz: - -```javascript -var fs = require('fs'); -fs.readdirSync('/path/to/example.asar'); -``` - -Utilizando um módulo dentro do pacote `asar`: - -```javascript -require('/path/to/example.asar/dir/module.js'); -``` - -Você também pode renderizar uma página web apartir de um arquivo `asar` utilizando o módulo `BrowserWindow`: - -```javascript -var BrowserWindow = require('browser-window'); -var win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('file:///path/to/example.asar/static/index.html'); -``` - -### API Web - -Em uma página web, arquivos em um pacote `asar` pode ser solicitado com o protocolo `file:`. -Como a API Node, arquivos `asar` são tratadas como diretórios. - -Por exemplo, para obter um arquivo com `$ .get`: - -```html - -``` - -### Tratando um pacote `asar` como um arquivo normal - -Para alguns casos, precisamos verificar o checksum de um pacote `asar`, para fazer isto, precisamos ler -o arquivo `asar` como um arquivo normal. Para isto, você pode usar o built-in -`original-fs` que fornece a API `fs`, sem apoio a arquivos asar`: - -```javascript -var originalFs = require('original-fs'); -originalFs.readFileSync('/path/to/example.asar'); -``` - -## Limitaçõs na API Node - -Mesmo fazendo grandes esforços para pacotes `asar` ser tratado no Node como diretórios, -ainda existem limitações devido a natureza de baixo nível do Node - -### Arquivos `asar` são somente leitura - -Os arquivos `asar` não podem ser modificados. - -### Diretório de trabalho não pode ser comportar como diretório de arquivos - -Embora pacotes `asar` são tratadas como diretórios, não há -diretórios reais no sistema de arquivos, assim você nunca pode definir o diretório de trabalho para -diretórios em pacotes `asar`, passando-os como a opção `cwd` de algumas APIs -também irá causar erros. - -### Descompactação extra em algumas APIs - -A maioria das APIs `fs` pode ler um arquivo ou obter informações de um arquivo a partir de pacotes `asar` -sem descompacta-lo, mas para algumas APIs da rota real o Electron irá extrair o arquivo necessário para um -arquivo temporário e passar o caminho do arquivo temporário para as APIs, -isso adiciona um pouco de sobrecarga para essas APIs. - -APIs que requer descompactação extras são: - -* `child_process.execFile` -* `fs.open` -* `fs.openSync` -* `process.dlopen` - Usado por `require` em módulos nativos - -### Falsas informações de status do módulo `fs.stat` - -O objeto `Stats` retornado por` fs.stat` e outras funções relacionadas não são informações confiáveis, -você não deve confiar no objeto `Stats` exceto para obter o -tamanho do arquivo e verificação de tipo de arquivo. - -## Adicionando arquivos em um pacote `asar` - -Como dito acima, algumas APIs deo Node irá descompactar o arquivo para quando o filesystem -requsistar, além dos problemas de desempenho, ele também pode levar a falsos alertas -de vírus. - -Para contornar isso, você pode descompactar alguns arquivos usando a -opção `--unpack`, um exemplo de exclusão de bibliotecas compartilhadas de módulos nativos -é: - -```bash -$ asar pack app app.asar --unpack *.node -``` - -Depois de executar o comando, além do `app.asar`, há também -`app.asar.unpacked` pasta gerada que contém os arquivos descompactados, você -deve copiá-lo juntamente com `app.asar` quando enviá-lo para os usuários. - -Mais informações no repositório [asar](https://github.com/atom/asar) diff --git a/docs-translations/pt-BR/tutorial/debugging-main-process.md b/docs-translations/pt-BR/tutorial/debugging-main-process.md deleted file mode 100644 index ee79a523e928c..0000000000000 --- a/docs-translations/pt-BR/tutorial/debugging-main-process.md +++ /dev/null @@ -1,53 +0,0 @@ -# Depurando o Processo Principal - -A janela do navegador, DevTools, pode somente depurar o processo de renderização -de scripts (por exemplo, as páginas da web). Para providenciar um modo de -depurar os scripts através do processo principal, o Electron criou as opções -`--debug` e `--debug-brk`. - -## Opções da Linha de Comando - -Use a seguinte opção na linha de comando para depurar o processo principal do -Electron: - -### `--debug=[porta]` - -Quando este comando é usado, o Electron irá executar o protocolo de depuração -V8 mandando as mensagens na `porta`. A `porta` padrão é `5858`. - -### `--debug-brk=[porta]` - -Semelhante ao `--debug`, porém pausa o script na primeira linha. - -## Usando node-inspector para depurar - -__Nota:__ O Electron usa a versão v0.11.13 do Node, a qual, atualmenta não -funciona muito bem com node-inspector, e o processo principal irá quebrar se -você inspecionar o objeto `process` pelo console do node-inspector. - -### 1. Inicie o servidor [node-inspector][node-inspector] - -```bash -$ node-inspector -``` - -### 2. Habilite o modo de depuração para o Electron - -Você pode também iniciar o Electron com um ponto de depuração, desta maneira: - -```bash -$ electron --debug=5858 sua/aplicacao -``` - -ou para pausar o script na primeira linha: - -```bash -$ electron --debug-brk=5858 sua/aplicacao -``` - -### 3. Carregue o debugger UI - -Abra este endereço http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 -usando o Chrome. - -[node-inspector]: https://github.com/node-inspector/node-inspector diff --git a/docs-translations/pt-BR/tutorial/desktop-environment-integration.md b/docs-translations/pt-BR/tutorial/desktop-environment-integration.md deleted file mode 100644 index bf1e35969b296..0000000000000 --- a/docs-translations/pt-BR/tutorial/desktop-environment-integration.md +++ /dev/null @@ -1,260 +0,0 @@ -# Integração com o ambiente desktop - -Diferentes sistemas operacionais possuem diferentes formas de integrar -aplicacões desktop em seus ambientes. Por exemplo, no Windows, as aplicações podem -inserir atalhos no JumpList da barra de tarefas, no Mac, aplicações podem implementar um -menu customizado na dock. - -Este guia explica como integrar suas aplicações no ambiente desktop com a API -do Electron. - -## Documentos Recentes (Windows & macOS) - -O Windows e o macOS disponibilizam um acesso fácil para a lista de arquivos -abertos recentemente pela aplicação através do JumpList ou Dock Menu respectivamente. - -__JumpList:__ - -![JumpList Recent Files](http://i.msdn.microsoft.com/dynimg/IC420538.png) - -__Dock menu da Aplicação:__ - - - -Para adicionar um arquivo para os documentos recentes, você pode usar a API -[app.addRecentDocument][addrecentdocument]: - -```javascript -var app = require('app'); -app.addRecentDocument('/Users/USERNAME/Desktop/work.type'); -``` - -E você pode usar a API [app.clearRecentDocuments][clearrecentdocuments] para -limpar a lista de documentos recentes. - -```javascript -app.clearRecentDocuments(); -``` - -### Notas para Windows - -A fim de ser possível usar estas funcionalidades no Windows, sua aplicação deve -estar registrada como um handler daquele tipo de documento, caso contrário, o -arquivo não será exibido no JumpList mesmo depois de você ter adicionado isto. -Você pode encontrar qualquer coisa sobre o registro da aplicacão em -[Application Registration][app-registration]. - -Quando um usuário clica em um arquivo na JumpList, uma nova instância da sua aplicacão -deve ser iniciada com o caminho do arquivo adicionado como um argumento de -linha de comando. - -### Notas para macOS - -Quando um arquivo for requisitado pelo menu de documentos recentes, o evento `open-file` -do módulo `app` irá ser emitido. - -## Dock Menu customizado (macOS) - -macOS permite que desenvolvedores especifiquem um menu customizado para a dock, -que normalmente contém alguns atalhos para as funcionalidades mais utilizadas -da sua aplicação. - -__Dock menu do Terminal.app:__ - - - -Para criar seu Dock Menu customizado, você pode usar a API `app.dock.setMenu`, -ela está disponível apenas no macOS: - -```javascript -var app = require('app'); -var Menu = require('menu'); -var dockMenu = Menu.buildFromTemplate([ - { label: 'New Window', click: function() { console.log('New Window'); } }, - { label: 'New Window with Settings', submenu: [ - { label: 'Basic' }, - { label: 'Pro'} - ]}, - { label: 'New Command...'} -]); -app.dock.setMenu(dockMenu); -``` - -## Tarefas do Usuário (Windows) - -No Windows você pode especificar ações customizadas na categoria `Tarefas` do JumpList, -esse texto foi copiado do MSDN: - -> Applications define tasks based on both the program's features and the key -> things a user is expected to do with them. Tasks should be context-free, in -> that the application does not need to be running for them to work. They -> should also be the statistically most common actions that a normal user would -> perform in an application, such as compose an email message or open the -> calendar in a mail program, create a new document in a word processor, launch -> an application in a certain mode, or launch one of its subcommands. An -> application should not clutter the menu with advanced features that standard -> users won't need or one-time actions such as registration. Do not use tasks -> for promotional items such as upgrades or special offers. -> -> It is strongly recommended that the task list be static. It should remain the -> same regardless of the state or status of the application. While it is -> possible to vary the list dynamically, you should consider that this could -> confuse the user who does not expect that portion of the destination list to -> change. - -__Tarefas do Internet Explorer:__ - -![IE](http://i.msdn.microsoft.com/dynimg/IC420539.png) - -Ao contrário do Menu Dock no macOS que é um verdadeiro menu, tarefas do usuário no Windows -funcionam como atalhos, de uma forma que quando o usuário clica em uma tarefa, um programa -deve ser executado com os argumentos especificados. - -Para setar tarefas do usuário para sua aplicação, você pode usar a API -[app.setUserTasks][setusertaskstasks]: - -```javascript -var app = require('app'); -app.setUserTasks([ - { - program: process.execPath, - arguments: '--new-window', - iconPath: process.execPath, - iconIndex: 0, - title: 'New Window', - description: 'Create a new window' - } -]); -``` - -Para limpar sua lista de tarefas, apenas chame `app.setUserTasks` com um -array vazio. - -```javascript -app.setUserTasks([]); -``` - -As tarefas do usuário são exibidas mesmo depois da aplicação ser fechada, -então o ícone e o caminho do programa especificado pela tarefa deve existir -até sua aplicação ser desinstalada. - -## Miniaturas na Barra de Ferramentas - -No Windows você pode adicionar uma miniatura na barra de ferramentas com botões -específicos para a janela e barra de tarefas para aplicação. Isso provê ao usuário -uma forma de acessar um comando específico para janela sem ser necessário restaurar -ou ativar a janela. - -Isto é ilustrado no MSDN: - -> This toolbar is simply the familiar standard toolbar common control. It has a -> maximum of seven buttons. Each button's ID, image, tooltip, and state are defined -> in a structure, which is then passed to the taskbar. The application can show, -> enable, disable, or hide buttons from the thumbnail toolbar as required by its -> current state. -> -> For example, Windows Media Player might offer standard media transport controls -> such as play, pause, mute, and stop. - -__Miniaturas da barra de tarefas do Windows Media Player:__ - -![player](https://i-msdn.sec.s-msft.com/dynimg/IC420540.png) - -Você pode usar [BrowserWindow.setThumbarButtons][setthumbarbuttons] para criar -miniaturas na barra de ferramentas para sua aplicação. - -``` -var BrowserWindow = require('browser-window'); -var path = require('path'); -var win = new BrowserWindow({ - width: 800, - height: 600 -}); -win.setThumbarButtons([ - { - tooltip: "button1", - icon: path.join(__dirname, 'button1.png'), - click: function() { console.log("button2 clicked"); } - }, - { - tooltip: "button2", - icon: path.join(__dirname, 'button2.png'), - flags:['enabled', 'dismissonclick'], - click: function() { console.log("button2 clicked."); } - } -]); -``` - -Para limpar os botões na miniatura da barra de ferramentas, apenas chame -`BrowserWindow.setThumbarButtons` com um array vazio. - -```javascript -win.setThumbarButtons([]); -``` - -## Unity Launcher Shortcuts (Linux) - -No Unity, você pode adicionar entradas customizadas para estes lançadores modificando -o arquivo `.desktop`, veja [Adding Shortcuts to a Launcher][unity-launcher]. - -__Launcher shortcuts do Audacious:__ - -![audacious](https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles?action=AttachFile&do=get&target=shortcuts.png) - -## Barra de Progresso na Barra de Tarefas (Windows & Unity) - -No Windows o botão na barra de tarefas pode ser usado para exibir uma barra de progresso. -Isto permite que a janela exiba informação sobre o progresso de algum processo sem -a necessidade do usuário mudar de janela. - -A Unity DE também tem uma funcionalidade parecida que permite especificar uma barra -de progresso no ícone do lançador. - -__Barra de Progresso no botão da barra de tarefas:__ - -![Barra de Progresso na Barra de Tarefas](https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png) - -__Barra de progresso no Unity launcher:__ - -![Unity Launcher](https://cloud.githubusercontent.com/assets/639601/5081747/4a0a589e-6f0f-11e4-803f-91594716a546.png) - -Para adicionar uma barra de progresso para uma janela, você pode ver a API: -[BrowserWindow.setProgressBar][setprogressbar]: - -```javascript -var window = new BrowserWindow({...}); -window.setProgressBar(0.5); -``` - -## Representação do arquivo na janela (macOS) - -No macOS, uma janela pode possuir a representação de um arquivo na barra de título, -permitindo que ao usuário acionar um Command-Click ou Control-Click sobre o título da janela, -uma pop-up de navegação entre arquivos é exibida. - -Você também pode inserir um estado de edição na janela para que o ícone do arquivo -possa indicar se o documento nesta janela foi modificado. - -__Menu popup da representação de arquivo:__ - - - -Para inserir o arquivo de representacão da janela, você pode usar as API -[BrowserWindow.setRepresentedFilename][setrepresentedfilename] e -[BrowserWindow.setDocumentEdited][setdocumentedited]: - -```javascript -var window = new BrowserWindow({...}); -window.setRepresentedFilename('/etc/passwd'); -window.setDocumentEdited(true); -``` - -[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath -[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments -[setusertaskstasks]: ../api/app.md#appsetusertaskstasks -[setprogressbar]: ../api/browser-window.md#browserwindowsetprogressbarprogress -[setrepresentedfilename]: ../api/browser-window.md#browserwindowsetrepresentedfilenamefilename -[setdocumentedited]: ../api/browser-window.md#browserwindowsetdocumenteditededited -[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx -[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher -[setthumbarbuttons]: ../api/browser-window.md#browserwindowsetthumbarbuttonsbuttons diff --git a/docs-translations/pt-BR/tutorial/devtools-extension.md b/docs-translations/pt-BR/tutorial/devtools-extension.md deleted file mode 100644 index c488cee959c04..0000000000000 --- a/docs-translations/pt-BR/tutorial/devtools-extension.md +++ /dev/null @@ -1,46 +0,0 @@ -# Extensão DevTools - -Para facilitar a depuração, o Electron provê suporte para a extensão [Chrome DevTools][devtools-extension]. - -Para a maioria das extensões DevTools você pode simplesmente baixar o código-fonte e usar a função `BrowserWindow.addDevToolsExtension` para carregá-las. As extensões carregadas serão lembradas, assim você não precisa carregar sempre que criar uma nova janela. - -**NOTA: Se o DevTools React não funcionar, verifique a issue https://github.com/electron/electron/issues/915** - -Por exemplo, para usar a extensão [React DevTools](https://github.com/facebook/react-devtools), primeiro você deve baixar seu código-fonte: - -```bash -$ cd /some-directory -$ git clone --recursive https://github.com/facebook/react-devtools.git -``` - -Siga as instruções em [`react-devtools/shells/chrome/Readme.md`](https://github.com/facebook/react-devtools/blob/master/shells/chrome/Readme.md) para fazer o build da extensão. - -Agora você poderá carregar a extensão no Electron abrindo o DevTools em qualquer janela, e executando o seguinte código no console do DevTools: - -```javascript -const BrowserWindow = require('electron').remote.BrowserWindow; -BrowserWindow.addDevToolsExtension('/some-directory/react-devtools/shells/chrome'); -``` - -Para remover a extensão, você pode executar a chamada `BrowserWindow.removeDevToolsExtension` -com o nome da extensão e ela não será carregada na próxima vez que você abrir o DevTools: - -```javascript -BrowserWindow.removeDevToolsExtension('React Developer Tools'); -``` - -## Formato das extensões DevTools - -Idealmente todas as extensões DevTools escritas para o navegador Chrome podem ser carregadas pelo Electron, mas elas devem estar em um diretório. Pacotes com extensão `crx` não podem ser carregados pelo Electron a não ser que tenha uma forma de extraí-los em um diretório. - -## Páginas em segundo plano (background pages) - -Atualmente o Electron não suporta páginas em segundo plano nas extensões do Chrome, então extensões com essa característica podem não funcionar no Electron. - -## APIs `chrome.*` - -Algumas extensões do Chrome podem usar a API `chrome.*`. Apesar de um esforço na implementação destas APIs no Electron, elas ainda não estão finalizadas. - -Dado que nem todas as funções `chrome.*` estão implementadas, algumas extensões que utilizam `chrome.devtools.*` podem não funcionar. Você pode reportar este erro no issue tracker para que possamos adicionar suporte a essas APIs. - -[devtools-extension]: https://developer.chrome.com/extensions/devtools diff --git a/docs-translations/pt-BR/tutorial/online-offline-events.md b/docs-translations/pt-BR/tutorial/online-offline-events.md deleted file mode 100644 index ff7bb112cee6e..0000000000000 --- a/docs-translations/pt-BR/tutorial/online-offline-events.md +++ /dev/null @@ -1,83 +0,0 @@ -# Online/Offline Event Detection - -Os eventos de detecção Online e Offline podem ser implementados no processo -de renderização utilizando a API padrão do HTML, como é mostrado no exemplo -a seguir: - -_main.js_ - -```javascript -var app = require('app'); -var BrowserWindow = require('browser-window'); -var onlineStatusWindow; - -app.on('ready', function() { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` - -Pode haver casos onde você também deseja responder a estes eventos no processo principal. -Mas o processo principal não consegue detectar esses eventos diretamente, pois não possui -um objeto `navigator`. Utilizando a ferramentas para comunicação entre processos, os eventos -podem ser direcionados para o processo principal e manipulados quando necessário. Você -pode ver isto no exemplo abaixo: - -_main.js_ - -```javascript -var app = require('app'); -var ipc = require('ipc'); -var BrowserWindow = require('browser-window'); -var onlineStatusWindow; - -app.on('ready', function() { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); -}); - -ipc.on('online-status-changed', function(event, status) { - console.log(status); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` diff --git a/docs-translations/pt-BR/tutorial/quick-start.md b/docs-translations/pt-BR/tutorial/quick-start.md deleted file mode 100644 index ad28b4f921009..0000000000000 --- a/docs-translations/pt-BR/tutorial/quick-start.md +++ /dev/null @@ -1,189 +0,0 @@ -# Introdução - -Electron permite criar aplicações desktop com puro JavaScript através de -um runtime com APIs ricas e nativas. Você pode ver isso como uma variação do -runtime do io.js que é focado em aplicações desktop em vez de web servers. - -Isso não significa que o Electron é uma ligação em JavaScript para bibliotecas -de interface gráfica (GUI). Em vez disso, Electron usa páginas web como -interface gráfica, então você pode ver isso também como um navegador Chromium -mínimo, controlado por JavaScript. - -### Processo Principal - -No Electron, o processo que executa o script principal (main) do `package.json` -é chamado __processo principal__. O script que roda no processo principal pode -mostrar uma GUI criando páginas web. - -### Processo Renderizador - -Já que o Electron usa o Chromium para mostrar as páginas web, a arquitetura -multi-processo do Chromium também é usada. Cada página web no Electron roda em -seu próprio processo, o que é chamado de __processo renderizador__. - -Em navegadores comuns, as páginas web normalmente rodam em um ambiente em sandbox -e não têm permissão de acesso para recursos nativos. Usuários Electron, entretanto, -têm o poder de usar as APIs do io.js nas páginas web, permitindo interações de baixo -nível no sistema operacional. - -### Diferenças Entre o Processo Principal e o Processo Renderizador - -O processo principal cria as páginas web criando instâncias de `BrowserWindow`. -Cada instância de `BrowserWindow` roda a página web em seu próprio processo renderizador. -Quando uma instância de `BrowserWindow` é destruída, o processo renderizador -correspondente também é finalizado. - -O processo principal gerencia todas as páginas web de seus processos renderizadores -correspondentes. Cada processo renderizador é isolado e toma conta de sua -respectiva página web. - -Nas páginas web, chamar APIs nativas relacionadas à GUI não é permitido porque -gerenciar recursos de GUI em páginas web é muito perigoso e torna fácil o vazamento de -recursos. Se você quer realizar operações com GUI em páginas web, o processo -renderizador da página web deve se comunicar com o processo principal para requisitar -que o processo principal realize estas operações. - -No Electron, nós fornecemos o módulo [ipc](../../../docs/api/ipc-renderer.md) para -comunicação entre o processo principal e o processo renderizador. Que é também um -módulo [remoto](../../../docs/api/remote.md) para comunicação RPC. - -## Crie seu Primeiro App Electron - -Geralmente, um app Electron é estruturado assim: - -```text -seu-app/ -├── package.json -├── main.js -└── index.html -``` - -O formato de `package.json` é exatamente o mesmo que o dos módulos do Node, -e o script especificado pelo campo `main` é o script de inicialização do seu app, -que irá executar o processo principal. Um exemplo do seu `package.json` deve parecer -com isso: - -```json -{ - "name" : "seu-app", - "version" : "0.1.0", - "main" : "main.js" -} -``` - -__Nota__: Se o campo `main` não estiver presente no `package.json`, o Electron irá -tentar carregar um `index.js` - -O `main.js` deve criar as janelas e os manipuladores de eventos do sistema, um típico -exemplo: - -```javascript -var app = require('app'); // Módulo para controlar o ciclo de vida do app. -var BrowserWindow = require('browser-window'); // Módulo para criar uma janela nativa do browser. - -// Mantenha uma referência global para o objeto window, se você não o fizer, -// a janela será fechada automaticamente quando o objeto JavaScript for -// coletado pelo garbage collector. -var mainWindow = null; - -// Sair quando todas as janelas estiverem fechadas. -app.on('window-all-closed', function() { - // No macOS é comum para as aplicações na barra de menu - // continuarem ativas até que o usuário saia explicitamente - // com Cmd + Q - if (process.platform != 'darwin') { - app.quit(); - } -}); - -// Esse método irá ser chamado quando o Electron finalizar -// a inicialização e estiver pronto para criar janelas do browser. -app.on('ready', function() { - // Criar a janela do navegador. - mainWindow = new BrowserWindow({width: 800, height: 600}); - - // e carrega o index.html do app. - mainWindow.loadURL('file://' + __dirname + '/index.html'); - - // Abre os DevTools. - mainWindow.openDevTools(); - - // Emitido quando a janela é fechada. - mainWindow.on('closed', function() { - // Desfaz a referência para o objeto window, normalmente você deverá - // guardar as janelas em um array se seu app suportar várias janelas, - // essa é a hora que você deverá deletar o elemento correspondente. - mainWindow = null; - }); -}); -``` - -Finalmente o `index.html` é a página web que você quer mostrar: - -```html - - - - - Hello World! - - -

Hello World!

- Nós estamos usando io.js - e Electron . - - -``` - -## Execute seu App - -Uma vez que você criou seus arquivos `main.js`, `index.html`, e `package.json` iniciais, -você provavelmente vai querer tentar executar seu app localmente para testa-lo e ter -certeza que funciona como você espera. - -### electron-prebuilt - -Se você instalou `electron-prebuilt` globalmente com `npm`, então você irá precisar apenas -rodar o seguinte comando no diretório fonte do seu app: - -```bash -electron . -``` - -Se você o instalou localmente, então execute: - -```bash -./node_modules/.bin/electron . -``` - -### Binário do Electron Baixado Manualmente - -Se você baixou o Electron manualmente, você pode também usar o binário incluído para -executar seu app diretamente. - -#### Windows - -```bash -$ .\electron\electron.exe seu-app\ -``` - -#### Linux - -```bash -$ ./electron/electron seu-app/ -``` - -#### macOS - -```bash -$ ./Electron.app/Contents/MacOS/Electron seu-app/ -``` - -`Electron.app` aqui é uma parte do pacote de lançamento do Electron, você pode baixa-lo -[aqui](https://github.com/electron/electron/releases). - -### Executar como uma distribuição - -Depois de terminar seu app, você pode criar uma distribuição seguindo o guia -[Distribuição de aplicações](./application-distribution.md) e então executar o app -empacotado. diff --git a/docs-translations/pt-BR/tutorial/supported-platforms.md b/docs-translations/pt-BR/tutorial/supported-platforms.md deleted file mode 100644 index 1db405257da66..0000000000000 --- a/docs-translations/pt-BR/tutorial/supported-platforms.md +++ /dev/null @@ -1,22 +0,0 @@ -# Plataformas Suportadas - -As plataformas suportadas por Electron são: - -### macOS - -Somente binarios em 64bit são construidos para macOS e a versão mínima suportada é macOS 10.9. - -### Windows -Suporte para Windows 7 ou superior, versões anteriores não são suportados (e não ira funcionar) - - Binarios em `x86` e `amd64` (x64) são construidos para Windows. Atencão: Versão `ARM` do Windows não é suportada agora. - -### Linux -Binario pré-construido `ia32`(`i686`) e binario `x64`(`amd64`) são construidas no Ubuntu 12.04, binario `arm` está construido contra ARM v7 com hard-float ABI e NEION para Debian Wheezy. - -Se o pré-compilador poderá ser executado por uma distribuição, depende se a distruibuicão inclui as blibliotecas que o Eletron está vinculando na plataforma de construcão, por este motivo apenas Ubuntu 12.04 é garantido para funcionar corretamente, mas as seguintes distribuições foram verificados com o pre-compilador: - - -* Ubuntu 12.04 ou superior -* Fedora 21 -* Debian 8 diff --git a/docs-translations/pt-BR/tutorial/using-native-node-modules.md b/docs-translations/pt-BR/tutorial/using-native-node-modules.md deleted file mode 100644 index a7d68ad90cfd6..0000000000000 --- a/docs-translations/pt-BR/tutorial/using-native-node-modules.md +++ /dev/null @@ -1,68 +0,0 @@ -# Usando Módulos Nativos do Node - -Os módulos nativos do Node são suportados pelo Electron, desde que o Electron -esteja usando uma versão diferente da oficial V8 do Node, você tem de -especificar manualmente a localização das headers do Electron quando compilar os -módulos nativos. - -## Compatibilidade de Módulos Nativos do Node - -Módulos nativos podem quebrar quando utilizar a nova versão do Node, V8. -Para ter certeza que o módulo que você está interessado em trabalhar com o -Electron, você deve checar se a versão do Node utilizada é compatível com a -usada pelo Electron. -Você pode verificar qual versão do Node foi utilizada no Electron olhando na -página [releases](https://github.com/electron/electron/releases) ou usando -`process.version` (veja em [Introdução](quick-start.md) -por exemplo). - -Considere usar [NAN](https://github.com/nodejs/nan/) para seus próprios -módulos, caso isso facilite o suporte da múltiplas versões do Node. Isso é -também de grande ajuda para fazer a portabilidade dos módulos antigos para as -versões mais novas do Node, assim podendo trabalhar com o Electron. - -## Como Instalar os Módulos Nativos - -Existem três maneiras de instalar os módulos nativos: - -### O Modo Fácil - -O modo mais direto para recompilar os módulos é pelo pacote -[`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild), -o que lida com passos manuais para baixar as headers e construir os módulos -nativos: - -```sh -npm install --save-dev electron-rebuild - -# Sempre que rodar npm install, execute também: -node ./node_modules/.bin/electron-rebuild -``` - -### Via npm - -Você pode usar também `npm` para instalar os módulos. Os passos são exatamente -os mesmos com os módulos Node, exceto que você precisa configurar algumas -variáveis da ambiente: - -```bash -export npm_config_disturl=https://atom.io/download/atom-shell -export npm_config_target=0.33.1 -export npm_config_arch=x64 -export npm_config_runtime=electron -HOME=~/.electron-gyp npm install module-name -``` - -### O modo node-gyp - -Para compilar os módulos do Node com as headers do Electron, você precisa dizer -ao `node-gyp` onde baixar as headers e qual versão usar: - -```bash -$ cd /path-to-module/ -$ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=https://atom.io/download/atom-shell -``` - -A tag `HOME=~/.electron-gyp` altera onde encontrar as headers de desenvolvimento. -A tag `--target=0.29.1` é a versão do Electron. A tag `--dist-url=...` especifica -onde baixar as headers. A tag `--arch=x64` diz ao módulo que é feito em 64bit. diff --git a/docs-translations/pt-BR/tutorial/using-pepper-flash-plugin.md b/docs-translations/pt-BR/tutorial/using-pepper-flash-plugin.md deleted file mode 100644 index 2f87b067d6676..0000000000000 --- a/docs-translations/pt-BR/tutorial/using-pepper-flash-plugin.md +++ /dev/null @@ -1,65 +0,0 @@ -# Usando o Plugin Pepper Flash - -Electron atualmente suporta o plugin Pepper Flash. Para usá-lo no Electron, -você deve especificar manualmente a localização do plugin e então ele será -habilitado em sua aplicação. - -## Prepare uma cópia do plugin Flash - -Tanto no macOS como no Linux, os detalhes do plugin Pepper Flash podem ser -encontrados navegando por `chrome://plugins` no navegador Chrome. Essa -localização e versão são úteis para o suporte do plugin Electron's Pepper Flash. -Você pode também copiar para outra localização. - -## Adicionando a opçao Electron - -Você pode adicionar diretamente `--ppapi-flash-path` e `ppapi-flash-version` -para a linha de comando do Electron ou usando o método -`app.commandLine.appendSwitch` após o evento pronto. Também, adicione a opção -`plugins` em `browser-window`. -Por exemplo: - -```javascript -var app = require('app'); -var BrowserWindow = require('browser-window'); - -// Mantém uma referência global da janela, se não manter, a janela irá fechar -// automaticamente quando o objeto javascript for GCed. -var mainWindow = null; - -// Sai assim que todas as janelas forem fechadas. -app.on('window-all-closed', function() { - if (process.platform != 'darwin') { - app.quit(); - } -}); - -// Epecifica o caminho do flash. -// No Windows, deve ser /path/to/pepflashplayer.dll -// No macOS, /path/to/PepperFlashPlayer.plugin -// No Linux, /path/to/libpepflashplayer.so -app.commandLine.appendSwitch('ppapi-flash-path', '/path/to/libpepflashplayer.so'); - -// Especifica a versão do flash, por exemplo, v17.0.0.169 -app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169'); - -app.on('ready', function() { - mainWindow = new BrowserWindow({ - 'width': 800, - 'height': 600, - 'web-preferences': { - 'plugins': true - } - }); - mainWindow.loadURL('file://' + __dirname + '/index.html'); - // Algo mais -}); -``` - -## Ative o plugin Flash na tag `` - -Adicione o atributo `plugins` na tag ``. - -```html - -``` diff --git a/docs-translations/ru-RU/README.md b/docs-translations/ru-RU/README.md deleted file mode 100644 index 5a358eac9f66e..0000000000000 --- a/docs-translations/ru-RU/README.md +++ /dev/null @@ -1,82 +0,0 @@ -Пожалуйста, убедитесь, что Вы используете документацию, которая соответствует вашей версии Electron. -Номер версии должен быть частью адреса страницы. Если это не так, Вы -возможно, используете документацию ветки разработки, которая может содержать изменения api, -которые не совместимы с вашей версией Electron. Если это так, -Вы можете переключиться на другую версию документации в списке -[доступные версии](http://electron.atom.io/docs/) на [atom.io](atom.io), или -если Вы используете интерфейс GitHub, откройте список "переключение ветки/тега" и -выберите тег, который соответствует вашей версии. - -## Руководства - -* [Поддерживаемые платформы](tutorial/supported-platforms.md) -* [Application Distribution](tutorial/application-distribution.md) -* [Mac App Store Submission Guide](tutorial/mac-app-store-submission-guide.md) -* [Application Packaging](tutorial/application-packaging.md) -* [Использование нативных модулей NodeJS](tutorial/using-native-node-modules.md) -* [Отладка главного процесса](tutorial/debugging-main-process.md) -* [Использование Selenium и WebDriver](tutorial/using-selenium-and-webdriver.md) -* [DevTools Extension](tutorial/devtools-extension.md) -* [Использование Pepper Flash Plugin](tutorial/using-pepper-flash-plugin.md) - -## Учебники - -* [Быстрый старт](tutorial/quick-start.md) -* [Интеграция рабочего окружения](tutorial/desktop-environment-integration.md) -* [Определение Онлайн/Оффлайн состояния](tutorial/online-offline-events.md) - -## API References - -* [Краткий обзор](api/synopsis.md) -* [Process Object](api/process.md) -* [Поддерживаемые параметры командной строки Chrome](api/chrome-command-line-switches.md) - -### Пользовательские элементы DOM: - -* [`File` Object](api/file-object.md) -* [`` Tag](api/web-view-tag.md) -* [`window.open` Function](api/window-open.md) - -### Модули для Main Process: - -* [app](api/app.md) -* [autoUpdater](api/auto-updater.md) -* [BrowserWindow](api/browser-window.md) -* [contentTracing](api/content-tracing.md) -* [dialog](api/dialog.md) -* [globalShortcut](api/global-shortcut.md) -* [ipcMain](api/ipc-main.md) -* [Menu](api/menu.md) -* [MenuItem](api/menu-item.md) -* [powerMonitor](api/power-monitor.md) -* [powerSaveBlocker](api/power-save-blocker.md) -* [protocol](api/protocol.md) -* [session](api/session.md) -* [webContents](api/web-contents.md) -* [Tray](api/tray.md) - -### Модули для Renderer Process (Web Page): - -* [ipcRenderer](api/ipc-renderer.md) -* [remote](api/remote.md) -* [webFrame](api/web-frame.md) - -### Модули для обоих процессов: - -* [clipboard](api/clipboard.md) -* [crashReporter](api/crash-reporter.md) -* [nativeImage](api/native-image.md) -* [screen](api/screen.md) -* [shell](api/shell.md) - -## Разработка - -* [Стиль кодирования](development/coding-style.md) -* [Структура папок с исходным кодом](development/source-code-directory-structure.md) -* [Technical Differences to NW.js (formerly node-webkit)](development/atom-shell-vs-node-webkit.md) -* [Обзор системы сборки](development/build-system-overview.md) -* [Инструкции по сборке (macOS)](development/build-instructions-osx.md) -* [Инструкции по сборке (Windows)](development/build-instructions-windows.md) -* [Инструкции по сборке (Linux)](development/build-instructions-linux.md) -* [Настройка сервера символов для отладчика](development/setting-up-symbol-server.md) - diff --git a/docs-translations/ru-RU/tutorial/application-distribution.md b/docs-translations/ru-RU/tutorial/application-distribution.md deleted file mode 100644 index 7659523caed2b..0000000000000 --- a/docs-translations/ru-RU/tutorial/application-distribution.md +++ /dev/null @@ -1,127 +0,0 @@ -# Распространение приложения - -Чтобы разпространять ваше приложение на Electron, папка с вашим приложением -должна называться `app` и находиться в папке ресурсов Electron (в macOS это -`Electron.app/Contents/Resources/`, в Linux и Windows - `resources/`), -вот так: - -Для macOS: - -```text -electron/Electron.app/Contents/Resources/app/ -├── package.json -├── main.js -└── index.html -``` - -Для Windows и Linux: - -```text -electron/resources/app -├── package.json -├── main.js -└── index.html -``` - -Затем запустите `Electron.app` (или `electron` в Linux, `electron.exe` в Windows), -и Electron запустится как ваше приложение. Теперь папка `electron` и есть дистрибутив, -который Вы должны распространять пользователям. - -## Упаковка вашего приложения в файл - -Если Вы `не хотите` распространять исходные коды вашего проекта, Вы можете -упаковать его в архив [asar](https://github.com/atom/asar), чтобы не -показывать пользователям исходные коды. - -Чтобы использовать `asar` для замены папки `app` на архив вам нужно -переименовать архив в `app.asar` и положить его в папку ресурсов Electron, -после чего Electron попробует считать ресурсы и запустить архив. - - -Для macOS: - -```text -electron/Electron.app/Contents/Resources/ -└── app.asar -``` - -Для Windows и Linux: - -```text -electron/resources/ -└── app.asar -``` - -Больше деталей можно найти в [инстуркции по упаковке приложения](application-packaging.md). - -## Ребрендирование скачанных исполняемых файлов - -После того, как Вы подключили ваше приложение к Electron, -Вам наверняка захочется ребрендировать его перед распространением. - -### Windows - -Вы можете переименовать `electron.exe` как пожелаете и поменять иконку и прочую -информацию приложениями вроде [rcedit](https://github.com/atom/rcedit). - -### macOS - -Вы можете переименовать `Electron.app` как пожелаете, а также изменить -поля `CFBundleDisplayName`, `CFBundleIdentifier` и `CFBundleName` в следующих -файлах: - -* `Electron.app/Contents/Info.plist` -* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` - -Вы таже можете переименовать приложение-помощник, чтобы оно не показывало `Electron Helper`, -убедитесь, что Вы переименовали его исполняемый файл. - -Структура переименованного приложения выглядит примерно так: - -``` -MyApp.app/Contents -├── Info.plist -├── MacOS/ -│   └── MyApp -└── Frameworks/ - ├── MyApp Helper EH.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper EH - ├── MyApp Helper NP.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper NP - └── MyApp Helper.app - ├── Info.plist - └── MacOS/ -    └── MyApp Helper -``` - -### Linux - -Вы можете переименовать исполняемый файл `electron` как пожелаете. - -## Rebranding by Rebuilding Electron from Source - -Вы также можете ребрендировать Electron изменив имя продукта и собрав его -из исходных кодов. Чтобы сделать это Вам нужно изменить `atom.gyp` и полностью -пересобрать Electron. - -### grunt-build-atom-shell - -Проверка и пересборка кода Electron довольно сложная задача, так что мы -сделали файл-инструкцию для Grunt, который будет делать это автоматически: -[grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell). - -Этот файл автоматически просмотрит изменения в `.gyp` файле, соберёт -Electron из исходных кодов и пересоберёт модули Node, чтобы всё подходило -под новое имя. - -## Инструменты - -Вы также можете использовать инструменты от третьих лиц, -которые сделают работу за вас: - -* [electron-packager](https://github.com/maxogden/electron-packager) -* [electron-builder](https://github.com/loopline-systems/electron-builder) diff --git a/docs-translations/ru-RU/tutorial/application-packaging.md b/docs-translations/ru-RU/tutorial/application-packaging.md deleted file mode 100644 index 6488ea1e19dbc..0000000000000 --- a/docs-translations/ru-RU/tutorial/application-packaging.md +++ /dev/null @@ -1,180 +0,0 @@ -# Упаковка приложения - -Чтобы смягчить [проблемы](https://github.com/joyent/node/issues/6960) с длинными -именами под Windows, немного ускорить `require` и скрыть ваши исходные коды, Вы -можете упаковать его в архив [asar][asar], немного поменяв исходный код. - -## Генерация архива `asar` - -Архив [asar][asar] - простой фомат похожий на tar, который собирает много файлов -в один. Electron может читать такой файл без распаковки. - -Шаги для упавки вашего приложения архив `asar`: - -### 1. Установите саму утилиту asar - -```bash -$ npm install -g asar -``` - -### 2. Упакуйте с помощью `asar pack` - -```bash -$ asar pack your-app app.asar -``` - -## Использование архивов `asar` - -В Electron есть два вида API: API Node, которые устанавливаются с помощью Node.JS и -веб API, которые предоставляюся Chromium. Оба предоставляют возможность считывать из -архивов `asar`. - -### Node API - -Со специальными патчами в Electron, части Node API вроде `fs.readFile` и `require` -считают архивы `asar` виртуальными папками и файлы в них доступны как в обычных. - -Например, у нас есть архив `example.asar` в `/path/to`: - -```bash -$ asar list /path/to/example.asar -/app.js -/file.txt -/dir/module.js -/static/index.html -/static/main.css -/static/jquery.min.js -``` - -Прочитаеем файл в архиве `asar`: - -```javascript -const fs = require('fs'); -fs.readFileSync('/path/to/example.asar/file.txt'); -``` - -Список всех файлов начиная от корня архива: - -```javascript -const fs = require('fs'); -fs.readdirSync('/path/to/example.asar'); -``` - -Используем модуль из архива: - -```javascript -require('/path/to/example.asar/dir/module.js'); -``` - -Вы также можете показывать веб-страницы из архива `asar` через `BrowserWindow`: - -```javascript -const BrowserWindow = require('electron').BrowserWindow; -var win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('file:///path/to/example.asar/static/index.html'); -``` - -### Веб API - -На веб-страницах файлы запрашиваются с помощью протокола `file:`. Как и в Node API -архивы `asar` считаются за директории. - -Пример получения файла с помощью `$.get`: - -```html - -``` - - -### Использование архива `asar` в качестве обычного файла - -Для случаев, когда Вам, например, нужно проверить хэш-сумму архива `asar`, -нужно использовать архив как файл. Для этой цели существует встроенный модуль -`original-fs`, который предоставляет доступ к `fs` без поддежки `asar`: - -```javascript -var originalFs = require('original-fs'); -originalFs.readFileSync('/path/to/example.asar'); -``` - -Вы также можете выставить `process.noAsar` в `true`, чтобы выключить поддержку `asar` -в модуле `fs`: - -```javascript -process.noAsar = true; -fs.readFileSync('/path/to/example.asar'); -``` - -## Ограничения Node API - -Хотя мы и старались как могли, чтобы сделать `asar` максимально похожим на папки, -всё ещё существуют некоторые ограничения из-за низкоуровневой архитектуры Node API. - -### Архивы только для чтения - -Архивы не могут быть изменены, так что все функции API Node, которые меняют файлы, -не буду работать с архивами `asar`. - -### Нельзя установить рабочую директорию в архиве - -Хотя архивы `asar` и считаются папками, они ими на самом деле не являются ими, -так что Вы не можете установить в них рабочую директорию. Передача -архивов `asar` в качестве аргумента `cwd` некоторым API также может вызывать ошибки. - - -### Распаковка для некоторых API - -Большинство API `fs` могут читать файлы или получить сведения о них прямо из -архива, без распаковки, однако для некоторых, которые передают путь к системным -вызовам, Electron распакует нужный файл в временную папку и передаст путь к этому -файлу. - -API которым нужна распаковка: - -* `child_process.execFile` -* `child_process.execFileSync` -* `fs.open` -* `fs.openSync` -* `process.dlopen` - используется `require` на нативных модулях - -### Подельная информация для `fs.stat` - -Объект `Stats`, возвращаемый `fs.stat`, и его друзья для остальных файлов -в архиве `asar` специально генерируются, потому что на самом деле этих файлов -не существует в файловой системе. Вам не стоит доверять информации -из объектов `Stats`, кроме, разве что, размера и типа файлов. - -### Запуск исполняемых файлов из архивов `asar` - -Существуют некоторые API Node, которые исполняют файлы, например `child_process.exec`, -`child_process.spawn` и `child_process.execFile`, но только `execFile` может -исполнять файлы из архивов `asar`. - -Так вышло потому, что `exec` и `spawn` принимают `команду`, а не `файл` как параметр, -а `команды` исполняются в оболочке. Нет никакой реальной возможности проверить, -реален ли файл или находится в архиве `asar`, и даже если мы смогли бы проверить, -то неясно, как земенить путь к файлу без побочных эффектов. - -## Добавление распакованых файлов в архив `asar` - -Как говорилось выше, некоторые API Node будут распаковывать файлы, -чтобы их использовать. Кроме увеличенного потребления ресурсов это также -может вызвать предупреждения от антивирусов. - -Чтобы обойти это, Вы можете распаковать некоторые файлы, создавая архивы, -с помощью опции `--unpack`. Пример показывает распаковку нативных модулей: - -```bash -$ asar pack app app.asar --unpack *.node -``` - -После запуска команды выше в вашей папке, кроме `app.asar`, появится -`app.asar.unpacked`, которая будет содержать распакованные файлы, эту -папку стоит копировать вместе с `app.asar` при распространении. - -[asar]: https://github.com/atom/asar diff --git a/docs-translations/ru-RU/tutorial/mac-app-store-submission-guide.md b/docs-translations/ru-RU/tutorial/mac-app-store-submission-guide.md deleted file mode 100644 index 6b711e55cbc7a..0000000000000 --- a/docs-translations/ru-RU/tutorial/mac-app-store-submission-guide.md +++ /dev/null @@ -1,152 +0,0 @@ - -#Руководство по утверждению вашего приложения в App Store - -Начиная с версии v0.34.0 Electron позволяет Вам сформировать данные для App Store к вашему приложению. -Данное руководство представляет собой пошаговую инструкцию по созданию данных файлов. - -Помните, что когда Вы подаете свое приложение на рассмотрение в App Store Вы должны обладать аккаунтом разработчика, -который стоит денег. - -## Как отправить свое приложение на рассмотрение в App Store - -Последующие шаги подробно описывают, что и в какой последовательности Вам требуется сделать, но не гарантируют, что Ваше приложение будет рассмотрено Apple. Мы также рекомендуем Вам прочитать официальную документацию по оформлению своего приложения и информации к нему, чтобы пройти проверку в App Store. - -## Получение сертификата - -Перед тем, как отправить свое приложение Вы должны получить сертефикат, как это описано в этом [руководстве](https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps "Ссылка на руководство") - -## Регистрируем свое приложение (подписываем) - -После того, как Вы получили сертефикат, Вы можете упаковать свое прилоежние следуя правилам Application Distribution, -а затем подписать свое приложение. Этот шаг является базовым, но подписывать свое приложение нам нужно всего лишь один раз. - -Во-первых, нам нужно подготовить два файла: - -`child.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.inherit - - - -``` - -`parent.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.temporary-exception.sbpl - (allow mach-lookup (global-name-regex #"^org.chromium.Chromium.rohitfork.[0-9]+$")) - - -``` - -Затем подписываем свое приложение, с помощью специального сценария: - -```bash - #!/bin/bash - - # Имя вашего приложения. - APP="YourApp" - # Путь до вашейго приложения. - APP_PATH="/path/to/YourApp.app" - # Путь до вашего установочного пакета. - RESULT_PATH="~/Desktop/$APP.pkg" - # Имя сертификата которое вы хотите. - APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)" - INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)" - - FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" - - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework" - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib" - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib" - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework" - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper" - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH" - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP" - codesign -s "$APP_KEY" -f --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" - codesign -s "$APP_KEY" -f --entitlements child.plist "$APP_PATH/Contents/MacOS/$APP" - codesign -s "$APP_KEY" -f --entitlements parent.plist "$APP_PATH" - - productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" -``` - -Если вы только начали разрабатывать под macOS, то мы советуем Вам прочитать [App SandBox](https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html "Ссылка для новичков в разработке приложений для macOS") - -## Обновление приложения - -После того, как Вы подписали свое приложение Вы сможете загрузить его в Itunes Connect для обработки, убедитесь, что Вы создали [запись](https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html "ссылка на показ как создавать запись в Itunes Connect") перед отправкой. - -## Объяснение использования 'temporary-exception' - -Когда песочница Apple временно исключила ваше приложение, согласно [документации](https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/AppSandboxTemporaryExceptionEntitlements.html "Документация по исключениям") Вам нужно объяснить насколько это важное исключение: - ->Примечание: если Вы временно исключаете свое приложение, обязательно прочитайте и выполните рекомендации по правам на исключение. ->которые предоставляются в Itunes Connect. Самое важное указать почему ваше приложение должно быть исключенно. - -Вы можете объяснить, что ваше приложение построено на основе браузера Chromium, который использует Mach из-за его мультипроцессной архитектуры. Но есть еще вероятность, что ваше приложение не удалось проверить именно из-за этого. - -## Отправка приложения на проверку - -Следующие шаги описаны в официальной [документации](https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html "Официальная статья по отправке приложения на проверку") - -# Ограничения в Mac App Store - -Для того чтобы удовлетворить всем просьбам SandBox App Store, некоторые из модулей были отключены: -- crashReporter -- autoUpdater - -А также следующие проблемы были несколько изменены: -- Захват видео на некоторых машинах может не работать -- Некоторые специальные возможности могут не работать -- Приложения не будут в курсе изменения DNS - -Также из-за использования SandBox App Store некоторые возможности могут быть не доступны или ограничены, подробнее о ограничениях -Вы можете прочитать в [документации](https://developer.apple.com/app-sandboxing/ "Ссылка на ограничения в SandBox AppStore") - -# Криптографические алгоритмы которые использует Electron - -Смотря в какой стране и городе Вы находитесь, Apple может потребовать от Вас задокументировать алгоритмы криптографии которые Вы используете -и если потребуется, то попросит Вас предоставить копию регистрации вашего алгоритма шифрования. - -Electron использует следующие алгоритмы шифрования: -- AES - NIST SP 800-38A, NIST SP 800-38D, RFC 3394 -- HMAC - FIPS 198-1 -- ECDSA - ANS X9.62–2005 -- ECDH - ANS X9.63–2001 -- HKDF - NIST SP 800-56C -- PBKDF2 - RFC 2898 -- RSA - RFC 3447 -- SHA - FIPS 180-4 -- Blowfish - https://www.schneier.com/cryptography/blowfish/ -- CAST - RFC 2144, RFC 2612 -- DES - FIPS 46-3 -- DH - RFC 2631 -- DSA - ANSI X9.30 -- EC - SEC 1 -- IDEA - “On the Design and Security of Block Ciphers” book by X. Lai -- MD2 - RFC 1319 -- MD4 - RFC 6150 -- MD5 - RFC 1321 -- MDC2 - ISO/IEC 10118-2 -- RC2 - RFC 2268 -- RC4 - RFC 4345 -- RC5 - http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf -- RIPEMD - ISO/IEC 10118-3 - -Если Вы используете необычный алгоритм, то вот статья о том, как получить разрешение на использование собственного алгоритма шифрования в -рамках закона США - [статья](https://pupeno.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/ "Статья о том как получить разрешение на свой алгоритм шифрования") diff --git a/docs-translations/ru-RU/tutorial/quick-start.md b/docs-translations/ru-RU/tutorial/quick-start.md deleted file mode 100644 index c08e67264708d..0000000000000 --- a/docs-translations/ru-RU/tutorial/quick-start.md +++ /dev/null @@ -1,225 +0,0 @@ -# Быстрый старт - -Electron позволяет Вам делать приложения для рабочего стола на чистом JavaScript, -предоставляя среду с богатым API. Можете представлять его как Node.js приложение, которое -ориентировано для рабочего стола, а не для веб сервера. - -Однако это не значит, что Electron — лишь привязка к GUI билиотекам. На деле -Electron использует веб-страницы как интерфейс, так что Вы можете считать его -небольшим Chroumium браузером, который контролируется с помощью JavaScript. - -### Главный процесс - -В Electron процесс, который запускает `main` из `package.json` называется -__главным процессом__. Скрипт, который работает в главном процессе может -показывать GUI, создавая веб-страницы. - -### Процесс-рендерер - -Так как Electron использует Chromium для показа веб-страниц, -мульти-процессовая архитектура показа страниц Chromium тоже используется. -Каждая веб-страница в Electron работает в своём собственном процессе, -который называется __процесс-рендерер__. - -В обычных браузерах веб-страницы обычно запускаются в "песочнице" и им недоступны -реальные ресурсы компьютера. Пользователи Electron напротив могут использовать API -Node.js на страницах, что допускает более низкоуровневую работу с операционной системой. - -### Разница мужду главным процессом и процессом-рендерером - -Главный процесс создаёт веб-страницы используя `BrowserWindow`. Каждый экземпляр -`BrowserWindow` показывает веб-страницу через свой собственный процесс-рендерер. -Если экземпляр `BrowserWindow` уничтожается, то и соответствующий процесс-рендерер тоже -завершается. - -Главный процесс управляет всеми веб-страницами и соответствующими им процессами-редерерами. -Каждый процесс-рендерер изолирован и управляет только своей веб-страницей. - -На веб-страницах не позволяется вызывать нативные API, которые управляют GUI, -потому что это очень опасно и может легко вызвать утечку ресурсов. Если вы хотите -выполнить действия с GUI на странице, процесс-рендерер этой страницы должен -"попросить" главный процесс сделать эти действия. - -В Electron есть несолько способов общения между процессам. Например, модули -[`ipcRenderer`](../api/ipc-renderer.md) и [`ipcMain`](../api/ipc-main.md) используются -для отправки сообщений, а [remote](../api/remote.md) - для коммуникации в RPC стиле. -В FAQ также есть пункт о том, [как разделять информацию между страницами][share-data] - -## Первое приложение на Electron - -Как правило, приложение Electron структурировано следующим образом: - -```text -your-app/ -├── package.json -├── main.js -└── index.html -``` - -Формат `package.json` точно такой же, как у модулей Node и скрипт, объявленый -как `main`, будет выполняться при запуске вашего приложения, работая в -главном процессе. Например, Ваш `package.json` может выглядеть вот так: - -```json -{ - "name" : "your-app", - "version" : "0.1.0", - "main" : "main.js" -} -``` - -__Заметка__: Если поле `main` отсутствует в `package.json`, Electron попробует -загрузить `index.js`. - - -`main.js` должен создавать окно и управлять системными событиями, -типичный пример: - -```javascript -const electron = require('electron') -// Модуль, контролирующий основное: сам Electron. -const app = electron.app -// Модуль, создающий окно приложения. -const BrowserWindow = electron.BrowserWindow - -// Удерживайте глобальное обращение к объекту окна, если Вы так не сделаете, то -// окно само закроется после того, как объект будет собран сборщиком мусора. -let mainWindow - -function createWindow () { - // Создаём окно браузера - mainWindow = new BrowserWindow({width: 800, height: 600}) - - // и загружаем index.html приложения. - mainWindow.loadURL('file://' + __dirname + '/index.html') - - // Открываем DevTools. - mainWindow.webContents.openDevTools() - - // Будет выполнено, когда пользователь закроет окно - mainWindow.on('closed', function () { - // Убрать обращение на объект окна, обычно стоит хранить окна в массиве, - // если ваше приложение поддерживает несколько, сейчас стоит удалить - // соответствующий элемент. - mainWindow = null - }) -} - -//Этот метод будет вызван, когда Electron закончит инициализацию -//и будет готов создавать окна браузера. -//Некоторые API возможно использовать только после того, как -//это произойдёт. -app.on('ready', createWindow) - -// Выйти, если все окна закрыты -app.on('window-all-closed', function () { - //На macOS приложение и его строка меню обычно остаются активными, - //пока пользователь не завершит их с помощью `Cmd + Q`. - if (process.platform !== 'darwin') { - app.quit() - } -}) - -app.on('activate', function () { - //На macOS приложение обычно пересоздаёт окно, когда - //пользователь кликает на его иконку в доке, если не открыто - //других окон. - if (mainWindow === null) { - createWindow() - } -}) - -//В этот файл Вы можете включить остальной код вашего главного процесса. -//Вы также можете разложить его по отдельным файлам и подключить с помощью require. - -``` - -Наконец, `index.html`, страница, которую Вы хотите показать: - -```html - - - - - Hello World! - - -

Привет, мир!

- Мы используем Node , - Chrome , - и Electron . - - -``` - -## Запуск вашего приложения - -После того как Вы создали `main.js`, `index.html` и `package.json` Вам скорее всего захочется -запустить приложение, чтобы проверить, что оно работает так, как надо. - -### electron-prebuilt - -[`electron-prebuilt`](https://github.com/electron-userland/electron-prebuilt) — `npm` модуль, -который содержит прекомпилированную версию Electron. - -Если вы установили Electron глобально через `npm`, то Вам нужно будет всего лишь -запустить сдедующее в папке вашего проекта: - -```bash -electron . -``` - -Если Вы установили Electron локально, то выполните это: - -```bash -./node_modules/.bin/electron . -``` - -### Исполняемые файлы Electron, скачанные вручную - -Если Вы скачали Electron вручную, то Вы можете использовать -исполняемые файлы прямо в папке вашего проекта. - -#### Windows - -```bash -$ .\electron\electron.exe your-app\ -``` - -#### Linux - -```bash -$ ./electron/electron your-app/ -``` - -#### macOS - -```bash -$ ./Electron.app/Contents/MacOS/Electron your-app/ -``` - -`Electron.app` — часть реализного пакета Electron, Вы можете скачать его -[тут](https://github.com/electron/electron/releases). - -### Запустить как дистрибутив - -Когда Вы закончили написание вашего приложения, Вы можете создать -дистрибутив, следуя инструкциям [отсюда](./application-distribution.md) и -затем запустить полученное приложение. - -### Попробуйте этот пример - -Скопируйте и запустите этот обучающий код, используя репозиторий [`atom/electron-quick-start`](https://github.com/electron/electron-quick-start) - -**Заметка**: Для запуска требуется [Git](https://git-scm.com) и [Node.js](https://nodejs.org/en/download/) (который включает в себя [npm](https://npmjs.org)). - -```bash -# Клонируем репозиторий -$ git clone https://github.com/electron/electron-quick-start -# Переходим в папку скачанного репозитория -$ cd electron-quick-start -# Устанавливаем зависимости и запускаем -$ npm install && npm start -``` - -[share-data]: ../faq/electron-faq.md#how-to-share-data-between-web-pages diff --git a/docs-translations/ru-RU/tutorial/supported-platforms.md b/docs-translations/ru-RU/tutorial/supported-platforms.md deleted file mode 100644 index 0c929daa11963..0000000000000 --- a/docs-translations/ru-RU/tutorial/supported-platforms.md +++ /dev/null @@ -1,24 +0,0 @@ -# Платформы поддерживаемые Electron: - -Следующие платформы поддерживаются Electron: - -### macOS - -Поддерживает только 64-x битные macOS. Минимально поддерживаемой версией является macOS 10.9 - -### Windows - -Поддерживаются операционные системы Windows 7 и выше, старые операционные системы не поддерживаются (и не работают). - -Поддерживаются бинарники `x86` и `amd64` (x64) для Windows. Будьте внимательны, `ARM` версия Windows не поддерживается на данный момент. - -### Linux - -Подготовленные бинарники Electron для `ia32`(`i686`) и `x64`(`amd64`) архитектур сделаны на Ubuntu 12.04, -`arm` бинарник сделан на ARM v7 с hard-float ABI и NEON для Debian Wheezy. - -Гарантированно будет работать в дистрибутивах: - -* Ubuntu 12.04 и выше -* Fedora 21 -* Debian 8 diff --git a/docs-translations/th-TH/README.md b/docs-translations/th-TH/README.md deleted file mode 100644 index 0a1863674abd0..0000000000000 --- a/docs-translations/th-TH/README.md +++ /dev/null @@ -1,73 +0,0 @@ -## คู่มือ - -* [แพลตฟอร์มที่รองรับ](tutorial/supported-platforms.md) -* [การเผยแพร่แอปพลิเคชัน](tutorial/application-distribution.md) -* [แนวทางการส่งแอปเข้า Mac App Store](tutorial/mac-app-store-submission-guide.md) -* [การบรรจุแอปพลิเคชัน](tutorial/application-packaging.md) -* [การใช้โมดูลของ Node](tutorial/using-native-node-modules.md) -* [การหาข้อผิดพลาดในกระบวนการหลัก](tutorial/debugging-main-process.md) -* [การใช้งาน Selenium และ WebDriver](tutorial/using-selenium-and-webdriver.md) -* [ส่วนเสริมของ DevTools](tutorial/devtools-extension.md) -* [การใช้งานส่วนเสริม Pepper Flash](tutorial/using-pepper-flash-plugin.md) - -## แนะนำ - -* [เริ่มต้นอย่างคราวๆ](tutorial/quick-start.md) -* [การร่วมกันของสภาพแวดล้อมบนเดสทอป](tutorial/desktop-environment-integration.md) -* [การตรวจจับเหตุการณ์ออนไลน์หรือออฟไลน์](tutorial/online-offline-events.md) - -## แหล่งอ้างอิงของ API - -* [สรุปความ](api/synopsis.md) -* [โปรเซสออบเจค](api/process.md) -* [คำสั่งสำหรับเปลี่ยนแปลงค่าของ Chrome ที่รองรับ](api/chrome-command-line-switches.md) - -### การปรับแต่ง DOM: - -* [วัตถุ `File`](api/file-object.md) -* [แท็ก ``](api/web-view-tag.md) -* [ฟังก์ชัน `window.open`](api/window-open.md) - -### โมดูลสำหรับกระบวนการหลัก : - -* [app](api/app.md) -* [auto-updater](api/auto-updater.md) -* [browser-window](api/browser-window.md) -* [content-tracing](api/content-tracing.md) -* [dialog](api/dialog.md) -* [global-shortcut](api/global-shortcut.md) -* [ipc (main process)](api/ipc-main-process.md) -* [menu](api/menu.md) -* [menu-item](api/menu-item.md) -* [power-monitor](api/power-monitor.md) -* [power-save-blocker](api/power-save-blocker.md) -* [protocol](api/protocol.md) -* [session](api/session.md) -* [web-contents](api/web-contents.md) -* [tray](api/tray.md) - -### โมดูลสำหรับกระบวนการ Renderer (เว็บเพจ): - -* [ipc (renderer)](api/ipc-renderer.md) -* [remote](api/remote.md) -* [web-frame](api/web-frame.md) - -### Modules for Both Processes: - -* [clipboard](api/clipboard.md) -* [crash-reporter](api/crash-reporter.md) -* [native-image](api/native-image.md) -* [screen](api/screen.md) -* [shell](api/shell.md) - -## การพัฒนา - -* [ลักษณะการเขียนโค้ด](development/coding-style.md) -* [โครงสร้างไดเรคทอรี่ของซอร์สโค้ด](development/source-code-directory-structure.md) -* [ความแตกต่างทางเทคนิคจาก NW.js (หรือ node-webkit)](development/atom-shell-vs-node-webkit.md) -* [ภาพรวมการสร้างระบบ](development/build-system-overview.md) -* [ขั้นตอนการสร้าง (macOS)](development/build-instructions-osx.md) -* [ขั้นตอนการสร้าง (Windows)](development/build-instructions-windows.md) -* [ขั้นตอนการสร้าง (Linux)](development/build-instructions-linux.md) -* [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md) -* [การติดตั้งเซิร์ฟเวอร์ Symbol Server ใน debugger](development/setting-up-symbol-server.md) diff --git a/docs-translations/tr-TR/README.md b/docs-translations/tr-TR/README.md deleted file mode 100644 index 5717a5cea32b3..0000000000000 --- a/docs-translations/tr-TR/README.md +++ /dev/null @@ -1,86 +0,0 @@ -Lütfen kullandığınız dokümanın Electron versiyonunuzla aynı olduğundan emin olun. -Versiyon numarası okuduğunuz dokümanın URL'sindekiyle aynı olmalı. Eğer aynı değilse, muhtemelen geliştirme aşamasındaki API değişikliklerini içerebilecek dokümantasyonudur. -Eğer öyleyse, atom.io üzerinden [mevcut sürümler](http://electron.atom.io/docs/)e göz atabilirsiniz ya da eğer GitHub arayüzünü kullanıyorsanız "Switch branches/tags" açılır menüsünden versiyonunuza uygun olanı seçebilirsiniz. - -## SSS(Sıkça Sorulan Sorular) - -Bir problem(issue) bildirmeden önce sıkça sorulan sorulara göz atın: -* [Electron SSS](https://github.com/electron/electron/tree/master/docs/faq/electron-faq.md) - -## Klavuzlar - -* [Desteklenen Platformlar ](https://github.com/electron/electron/tree/master/docs/tutorial/supported-platforms.md) -* [Uygulama Dağıtımı](https://github.com/electron/electron/tree/master/docs/tutorial/application-distribution.md) -* [Mac Uygulama Mağazası Başvuru Klavuzu](https://github.com/electron/electron/tree/master/docs/tutorial/mac-app-store-submission-guide.md) -* [Uygulama Paketleme](https://github.com/electron/electron/tree/master/docs/tutorial/application-packaging.md) -* [Native Node Modüllerini Kullanma](https://github.com/electron/electron/tree/master/docs/tutorial/using-native-node-modules.md) -* [Ana Süreç(Main Process) Hata ayıklama](https://github.com/electron/electron/tree/master/docs/tutorial/debugging-main-process.md) -* [Selenium ve WebDriver kullanımı](https://github.com/electron/electron/tree/master/docs/tutorial/using-selenium-and-webdriver.md) -* [DevTools Eklentisi](https://github.com/electron/electron/tree/master/docs/tutorial/devtools-extension.md) -* [Pepper Flash Kullanımı](https://github.com/electron/electron/tree/master/docs/tutorial/using-pepper-flash-plugin.md) -* [Widevine CDM Kullanımı](https://github.com/electron/electron/tree/master/docs/tutorial/using-widevine-cdm-plugin.md) -* [CI Sistem Testleri (Travis, Jenkins)](https://github.com/electron/electron/tree/master/docs/tutorial/testing-on-headless-ci.md) - -## Eğitimler - -* [Quick Start](https://github.com/electron/electron/tree/master/docs/tutorial/quick-start.md) -* [Desktop Environment Integration](https://github.com/electron/electron/tree/master/docs/tutorial/desktop-environment-integration.md) -* [Online/Offline Event Detection](https://github.com/electron/electron/tree/master/docs/tutorial/online-offline-events.md) - -## API Kaynakları - -* [Synopsis](https://github.com/electron/electron/tree/master/docs/api/synopsis.md) -* [Process Object](https://github.com/electron/electron/tree/master/docs/api/process.md) -* [Desteklenen Chrome Komut Satırı Anahtarları](https://github.com/electron/electron/tree/master/docs/api/chrome-command-line-switches.md) -* [Environment Değişkenleri](https://github.com/electron/electron/tree/master/docs/api/environment-variables.md) - -### Özel DOM Elementleri: - -* [`File` Nesnesi](api/file-object.md) -* [`` Etiketi](https://github.com/electron/electron/tree/master/docs/api/web-view-tag.md) -* [`window.open` Fonksiyonu](https://github.com/electron/electron/tree/master/docs/api/window-open.md) - -### Ana Süreç(Main Process) Modülleri: - -* [app](https://github.com/electron/electron/tree/master/docs/api/app.md) -* [autoUpdater](https://github.com/electron/electron/tree/master/docs/api/auto-updater.md) -* [BrowserWindow](https://github.com/electron/electron/tree/master/docs/api/browser-window.md) -* [contentTracing](https://github.com/electron/electron/tree/master/docs/api/content-tracing.md) -* [dialog](https://github.com/electron/electron/tree/master/docs/api/dialog.md) -* [globalShortcut](https://github.com/electron/electron/tree/master/docs/api/global-shortcut.md) -* [ipcMain](https://github.com/electron/electron/tree/master/docs/api/ipc-main.md) -* [Menu](https://github.com/electron/electron/tree/master/docs/api/menu.md) -* [MenuItem](https://github.com/electron/electron/tree/master/docs/api/menu-item.md) -* [powerMonitor](https://github.com/electron/electron/tree/master/docs/api/power-monitor.md) -* [powerSaveBlocker](https://github.com/electron/electron/tree/master/docs/api/power-save-blocker.md) -* [protocol](https://github.com/electron/electron/tree/master/docs/api/protocol.md) -* [session](https://github.com/electron/electron/tree/master/docs/api/session.md) -* [webContents](https://github.com/electron/electron/tree/master/docs/api/web-contents.md) -* [Tray](https://github.com/electron/electron/tree/master/docs/api/tray.md) - -### Renderer Process Modülelri (Web Page): - -* [desktopCapturer](https://github.com/electron/electron/tree/master/docs/api/desktop-capturer.md) -* [ipcRenderer](https://github.com/electron/electron/tree/master/docs/api/ipc-renderer.md) -* [remote](https://github.com/electron/electron/tree/master/docs/api/remote.md) -* [webFrame](https://github.com/electron/electron/tree/master/docs/api/web-frame.md) - -### Her İki Süreç İçin Geçerli Modüller: - -* [clipboard](https://github.com/electron/electron/tree/master/docs/api/clipboard.md) -* [crashReporter](https://github.com/electron/electron/tree/master/docs/api/crash-reporter.md) -* [nativeImage](https://github.com/electron/electron/tree/master/docs/api/native-image.md) -* [screen](https://github.com/electron/electron/tree/master/docs/api/screen.md) -* [shell](https://github.com/electron/electron/tree/master/docs/api/shell.md) - -## Geliştirme - -* [Kodlama Stili](https://github.com/electron/electron/tree/master/docs/development/coding-style.md) -* [Kaynak Kod Dizin Yapısı](https://github.com/electron/electron/tree/master/docs/development/source-code-directory-structure.md) -* [NW.js(node-webkit adıyla bilinen) İle Arasındaki Teknik Farklılıklar](https://github.com/electron/electron/tree/master/docs/development/atom-shell-vs-node-webkit.md) -* [Build Sisyem Genel Bakış](https://github.com/electron/electron/tree/master/docs/development/build-system-overview.md) -* [(macOS) Build Komutları](https://github.com/electron/electron/tree/master/docs/development/build-instructions-osx.md) -* [(Windows) Build Komutları](https://github.com/electron/electron/tree/master/docs/development/build-instructions-windows.md) -* [(Linux) Build Komutları](https://github.com/electron/electron/tree/master/docs/development/build-instructions-linux.md) -* [(Windows) Hata Ayıklama Komutları](https://github.com/electron/electron/tree/master/docs/development/debug-instructions-windows.md) -* [Simge Sunucusu(Symbol Server) Hata Ayıklama Kurulumu](https://github.com/electron/electron/tree/master/docs/development/setting-up-symbol-server.md) diff --git a/docs-translations/tr-TR/api/accelerator.md b/docs-translations/tr-TR/api/accelerator.md deleted file mode 100644 index be1acfbed1cf2..0000000000000 --- a/docs-translations/tr-TR/api/accelerator.md +++ /dev/null @@ -1,49 +0,0 @@ -# Hızlandırıcı - -> Kısayol Tanımlama. - -Hızlandırıcılar `+` karakteriyle birden fazla niteleyici ile kombinlenebilir. - -Örnek: - -* `CommandOrControl+A` -* `CommandOrControl+Shift+Z` - -## Platform bilgileri - -Linux ve Windows'ta `Command` tuşu herhangi bir etki göstermez. Bunun yerine -`CommandOrControl` niteleyicisini kullanın. Bu işlem macOS'te `Command`, -Linux ve Windows'ta `Control` tuşunun işlevini sağlar. `Alt` ise tüm platformlarda mevcuttur. - -`Super` tuşu Windows ve Linux'te `Windows` tuşuna, macOS'te ise `Cmd` tuşuna eşleştirilmiştir. - -## Mevcut düzenleyiciler - -* `Command` (ya da kısa tanım için `Cmd`) -* `Control` (ya da kısa tanım için `Ctrl`) -* `CommandOrControl` (ya da kısa tanım için `CmdOrCtrl`) -* `Alt` -* `Option` -* `AltGr` -* `Shift` -* `Super` - -## Mevcut tuş kodları - -* `0`dan `9`a -* `A`dan `Z`ye -* `F1`dan `F24`e -* Noktalama işaretleri `~`, `!`, `@`, `#`, `$`, vb. -* `Plus` -* `Space` -* `Backspace` -* `Delete` -* `Insert` -* `Return` (ya da `Enter`) -* `Up`, `Down`, `Left` ve `Right` -* `Home` ve `End` -* `PageUp` ve `PageDown` -* `Escape` (ya da kısa tanım için `Esc`) -* `VolumeUp`, `VolumeDown` ve `VolumeMute` -* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` ve `MediaPlayPause` -* `PrintScreen` diff --git a/docs-translations/tr-TR/api/file-object.md b/docs-translations/tr-TR/api/file-object.md deleted file mode 100644 index a99bdb329c5d0..0000000000000 --- a/docs-translations/tr-TR/api/file-object.md +++ /dev/null @@ -1,29 +0,0 @@ -# `File` nesnesi - -> Dosya ve dosya sistemlerinde HTML5 `File` nesnesini native olarak çalışır. - -DOM Dosya arayüzü HTML5 dosya API'sini kullanarak kullanıcılara doğrudan native dosyalar üzerinde çalışmasına olanak sağlar. Electron'da `File` arayüzü için `path` özelliğini eklemiştir. - -`dragged-onto-the-app`'dan tam dosya yolu alma örneği: - -```html -
- Dosyalarınızı buraya sürükleyin -
- - -``` diff --git a/docs-translations/tr-TR/styleguide.md b/docs-translations/tr-TR/styleguide.md deleted file mode 100644 index e9092d1d7c886..0000000000000 --- a/docs-translations/tr-TR/styleguide.md +++ /dev/null @@ -1,95 +0,0 @@ -# Electron Dokümantasyonu Stil Rehberi - -Size uygun bölümü bulun: [Electron Dokümantasyonunu okumak](#reading-electron-documentation) -ya da [Electron Dokümantasyonunu yazmak](#writing-electron-documentation). - -## Electron Dokümantasyonunu Yazmak - -Electron Dokümantasyonunu geliştirmek için aşağıdaki yöntemleri takip edin. - -- Her sayfada en fazla bir tane `h1` etiketi olmalıdır. -- Kod bloklarında `cmd` yerine `bash` kullanın.(syntax highlighter için). -- `h1` Başlığı nesne ismiyle eşleşmeli (ör. `browser-window` → - `BrowserWindow`). - - Hyphen separated filenames, however, are fine. -- No headers following headers, add at least a one-sentence description. -- Methods headers are wrapped in `code` ticks. -- Event headers are wrapped in single 'quotation' marks. -- No nesting lists more than 2 levels (unfortunately because of markdown - renderer). -- Add section titles: Events, Class Methods and Instance Methods. -- Use 'will' over 'would' when describing outcomes. -- Events and methods are `h3` headers. -- Optional arguments written as `function (required[, optional])`. -- Optional arguments are denoted when called out in list. -- Line length is 80-column wrapped. -- Platform specific methods are noted in italics following method header. - - ```### `method(foo, bar)` _macOS_``` -- Prefer 'in the ___ process' over 'on' - -### Dokümantasyon Çevirisi - -Electron Dokümantasyonunun çevirileri `docs-translations` klasörü içerisindedir. - -To add another set (or partial set): - -- Create a subdirectory named by language abbreviation. -- Within that subdirectory, duplicate the `docs` directory, keeping the - names of directories and files same. -- Translate the files. -- Update the `README.md` within your language directory to link to the files - you have translated. -- Add a link to your translation directory on the main Electron [README](https://github.com/electron/electron#documentation-translations). - -## Electron Dokümantasyonunu Okumak - -Electron Dokümantasyon sözdizimini(syntax) anlayabileceğiniz bir kaç ipucu: - -### Metodlar - -[Method](https://developer.mozilla.org/en-US/docs/Glossary/Method) dokümantasyonunun bir örneği: - ---- - -`methodName(required[, optional]))` - -* `require` String (**required**) -* `optional` Integer - ---- - -The method name is followed by the arguments it takes. Optional arguments are -notated by brackets surrounding the optional argument as well as the comma -required if this optional argument follows another argument. - -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) -or a custom type like Electron's [`webContent`](https://github.com/electron/electron/tree/master/docs/api/web-content.md). - -### Events - -[event](https://developer.mozilla.org/en-US/docs/Web/API/Event) Dokümantasyonunun bir örneği: - ---- - -Event: 'wake-up' - -Returns: - -* `time` String - ---- - -The event is a string that is used after a `.on` listener method. If it returns -a value it and its type is noted below. If you were to listen and respond to -this event it might look something like this: - -```javascript -Alarm.on('wake-up', function(time) { - console.log(time) -}) -``` diff --git a/docs-translations/uk-UA/README.md b/docs-translations/uk-UA/README.md deleted file mode 100644 index 8600bdcd77330..0000000000000 --- a/docs-translations/uk-UA/README.md +++ /dev/null @@ -1,83 +0,0 @@ -Будь ласка, переконайтесь що ви використовуєте документацію, яка відповідає вашій версії Electron. -Номер версії повинен бути присутнім в URL адресі сторінки. Якщо це не так, Ви можливо, -використовуєте документацію із development гілки, -яка може містити зміни в API, які не сумісні з вашою версією Electron. -Якщо це так, тоді Ви можете переключитись на іншу версію документації -із списку [доступних версій](http://electron.atom.io/docs/) на atom.io, -або якщо ви використовуєте інтеррфейс GitHub, -тоді відкрийте список "Switch branches/tags" і виберіть потрібну вам -версію із списку тегів. - -## Довідник - -* [Підтримувані платформи](tutorial/supported-platforms.md) -* [Application Distribution](tutorial/application-distribution.md) -* [Mac App Store Submission Guide](tutorial/mac-app-store-submission-guide.md) -* [Упаковка додатку](tutorial/application-packaging.md) -* [Використання Native Node модулів](tutorial/using-native-node-modules.md) -* [Debugging Main Process](tutorial/debugging-main-process.md) -* [Використання Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md) -* [DevTools Extension](tutorial/devtools-extension.md) -* [Використання Pepper Flash плагіну](tutorial/using-pepper-flash-plugin.md) - -## Підручники - -* [Швидкий старт](tutorial/quick-start.md) -* [Desktop Environment Integration](tutorial/desktop-environment-integration.md) -* [Online/Offline Event Detection](tutorial/online-offline-events.md) - -## API References - -* [Synopsis](api/synopsis.md) -* [Process Object](api/process.md) -* [Supported Chrome Command Line Switches](api/chrome-command-line-switches.md) -* [Environment Variables](api/environment-variables.md) - -### Користувальницькі елементи DOM - -* [`File` Object](api/file-object.md) -* [`` Tag](api/web-view-tag.md) -* [`window.open` Function](api/window-open.md) - -### Модулі для Main Process: - -* [app](api/app.md) -* [autoUpdater](api/auto-updater.md) -* [BrowserWindow](api/browser-window.md) -* [contentTracing](api/content-tracing.md) -* [dialog](api/dialog.md) -* [globalShortcut](api/global-shortcut.md) -* [ipcMain](api/ipc-main.md) -* [Menu](api/menu.md) -* [MenuItem](api/menu-item.md) -* [powerMonitor](api/power-monitor.md) -* [powerSaveBlocker](api/power-save-blocker.md) -* [protocol](api/protocol.md) -* [session](api/session.md) -* [webContents](api/web-contents.md) -* [Tray](api/tray.md) - -### Модулі для Renderer Process (Web Page): - -* [ipcRenderer](api/ipc-renderer.md) -* [remote](api/remote.md) -* [webFrame](api/web-frame.md) - -### Модулі для Both Processes: - -* [clipboard](api/clipboard.md) -* [crashReporter](api/crash-reporter.md) -* [nativeImage](api/native-image.md) -* [screen](api/screen.md) -* [shell](api/shell.md) - -## Розробка - -* [Стиль кодування](development/coding-style.md) -* [Source Code Directory Structure](development/source-code-directory-structure.md) -* [Technical Differences to NW.js (formerly node-webkit)](development/atom-shell-vs-node-webkit.md) -* [Build System Overview](development/build-system-overview.md) -* [Build Instructions (macOS)](development/build-instructions-osx.md) -* [Build Instructions (Windows)](development/build-instructions-windows.md) -* [Build Instructions (Linux)](development/build-instructions-linux.md) -* [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md) diff --git a/docs-translations/uk-UA/styleguide.md b/docs-translations/uk-UA/styleguide.md deleted file mode 100644 index 94c70e5ce2544..0000000000000 --- a/docs-translations/uk-UA/styleguide.md +++ /dev/null @@ -1,97 +0,0 @@ -# Electron Documentation Styleguide - -Find the appropriate section for your task: [reading Electron documentation](#reading-electron-documentation) -or [writing Electron documentation](#writing-electron-documentation). - -## Написання документації для Electron - -Існує кілька способів за допомогою яких ми ствоюємо документацію для Electron. - -- Maximum one `h1` title per page. -- Use `bash` instead of `cmd` in code blocks (because of syntax highlighter). -- Doc `h1` titles should match object name (i.e. `browser-window` → - `BrowserWindow`). - - Hyphen separated filenames, however, are fine. -- No headers following headers, add at least a one-sentence description. -- Methods headers are wrapped in `code` ticks. -- Event headers are wrapped in single 'quotation' marks. -- No nesting lists more than 2 levels (unfortunately because of markdown - renderer). -- Add section titles: Events, Class Methods and Instance Methods. -- Use 'will' over 'would' when describing outcomes. -- Events and methods are `h3` headers. -- Optional arguments written as `function (required[, optional])`. -- Optional arguments are denoted when called out in list. -- Line length is 80-column wrapped. -- Platform specific methods are noted in italics following method header. - - ```### `method(foo, bar)` _macOS_``` -- Prefer 'in the ___ process' over 'on' - -### Переклад документації - -Переклади документації знаходяться в дерикторії `docs-translations`. - -Щоб додати переклад (або частковий переклад) документації: - -- Create a subdirectory named by language abbreviation. -- Within that subdirectory, duplicate the `docs` directory, keeping the - names of directories and files same. -- Translate the files. -- Update the `README.md` within your language directory to link to the files - you have translated. -- Add a link to your translation directory on the main Electron [README](https://github.com/electron/electron#documentation-translations). - -## Читання документації Electron - -Кілька порад для того щоб легше зрозуміти синтаксис документації Electron. - -### Методи - -Приклад [методу](https://developer.mozilla.org/en-US/docs/Glossary/Method) -в документації: - ---- - -`methodName(required[, optional]))` - -* `require` String, **required** -* `optional` Integer - ---- - -The method name is followed by the arguments it takes. Optional arguments are -notated by brackets surrounding the optional argument as well as the comma -required if this optional argument follows another argument. - -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) -or a custom type like Electron's [`webContent`](api/web-content.md). - -### Події - -Приклад [події](https://developer.mozilla.org/en-US/docs/Web/API/Event) -в документації: - ---- - -Подія: 'wake-up' - -Повердає: - -* `time` Текст - ---- - -The event is a string that is used after a `.on` listener method. If it returns -a value it and its type is noted below. If you were to listen and respond to -this event it might look something like this: - -```javascript -Alarm.on('wake-up', function(time) { - console.log(time) -}) -``` diff --git a/docs-translations/zh-CN/README.md b/docs-translations/zh-CN/README.md deleted file mode 100644 index d3948c2bd2b95..0000000000000 --- a/docs-translations/zh-CN/README.md +++ /dev/null @@ -1,79 +0,0 @@ -## 常见问题 - -+ [Electron 常见问题](faq/electron-faq.md) - -## 向导 - -* [支持平台](tutorial/supported-platforms.md) -* [分发应用](tutorial/application-distribution.md) -* [提交应用到 Mac App Store](tutorial/mac-app-store-submission-guide.md) -* [打包应用](tutorial/application-packaging.md) -* [使用 Node 原生模块](tutorial/using-native-node-modules.md) -* [主进程调试](tutorial/debugging-main-process.md) -* [使用 Selenium 和 WebDriver](tutorial/using-selenium-and-webdriver.md) -* [使用开发人员工具扩展](tutorial/devtools-extension.md) -* [使用 Pepper Flash 插件](tutorial/using-pepper-flash-plugin.md) -* [使用 Widevine CDM 插件](tutorial/using-widevine-cdm-plugin.md) - -## 教程 - -* [快速入门](tutorial/quick-start.md) -* [桌面环境集成](tutorial/desktop-environment-integration.md) -* [在线/离线事件探测](tutorial/online-offline-events.md) - -## API文档 - -* [简介](api/synopsis.md) -* [进程对象](api/process.md) -* [支持的 Chrome 命令行开关](api/chrome-command-line-switches.md) -* [环境变量](api/environment-variables.md) - -自定义的 DOM 元素: - -* [`File` 对象](api/file-object.md) -* [`` 标签](api/web-view-tag.md) -* [`window.open` 函数](api/window-open.md) - -在主进程内可用的模块: - -* [app](api/app.md) -* [autoUpdater](api/auto-updater.md) -* [BrowserWindow](api/browser-window.md) -* [contentTracing](api/content-tracing.md) -* [dialog](api/dialog.md) -* [globalShortcut](api/global-shortcut.md) -* [ipcMain](api/ipc-main.md) -* [Menu](api/menu.md) -* [MenuItem](api/menu-item.md) -* [powerMonitor](api/power-monitor.md) -* [powerSaveBlocker](api/power-save-blocker.md) -* [protocol](api/protocol.md) -* [session](api/session.md) -* [webContents](api/web-contents.md) -* [Tray](api/tray.md) - -在渲染进程(网页)内可用的模块: - -* [desktopCapturer](api/desktop-capturer.md) -* [ipcRenderer](api/ipc-renderer.md) -* [remote](api/remote.md) -* [webFrame](api/web-frame.md) - -在两种进程中都可用的模块: - -* [clipboard](api/clipboard.md) -* [crashReporter](api/crash-reporter.md) -* [nativeImage](api/native-image.md) -* [screen](api/screen.md) -* [shell](api/shell.md) - -## 开发 - -* [代码规范](development/coding-style.md) -* [源码目录结构](development/source-code-directory-structure.md) -* [与 NW.js(原 node-webkit)在技术上的差异](development/atom-shell-vs-node-webkit.md) -* [构建系统概览](development/build-system-overview.md) -* [构建步骤(macOS)](development/build-instructions-osx.md) -* [构建步骤(Windows)](development/build-instructions-windows.md) -* [构建步骤(Linux)](development/build-instructions-linux.md) -* [在调试中使用 Symbol Server](development/setting-up-symbol-server.md) diff --git a/docs-translations/zh-CN/api/accelerator.md b/docs-translations/zh-CN/api/accelerator.md deleted file mode 100644 index 0b1e2cd3f4dfa..0000000000000 --- a/docs-translations/zh-CN/api/accelerator.md +++ /dev/null @@ -1,43 +0,0 @@ -# Accelerator - -一个 `Accelerator` 是一个表示某个快捷键组合的字符串。它包含了用 `+` 连接的若干个按键。 - -例如: - -* `Command+A` -* `Ctrl+Shift+Z` - -## 运行平台相关的提示 - -在 Linux 和 Windows 上,`Command` 键并不存在,因此我们通常用 `CommandOrControl` 来表示“在 macOS 下为 `Command` 键,但在 -Linux 和 Windows 下为 `Control` 键。 - -`Super` 键是指 Linux 和 Windows 上的 `Windows` 键,但是在 macOS 下为 `Command` 键。 - -## 可用的功能按键 - -* `Command`(缩写为 `Cmd`) -* `Control`(缩写为 `Ctrl`) -* `CommandOrControl`(缩写为 `CmdOrCtrl`) -* `Alt` -* `Shift` -* `Super` - -## 可用的普通按键 - -* `0` 到 `9` -* `A` 到 `Z` -* `F1` 到 `F24` -* 类似与 `~`、`!`、`@`、`#`、`$` 的标点符号。 -* `Plus` -* `Space` -* `Backspace` -* `Delete` -* `Insert` -* `Return`(和 `Enter` 等同) -* `Up`、`Down`、`Left` 和 `Right` -* `Home` 和 `End` -* `PageUp` 和 `PageDown` -* `Escape`(缩写为 `Esc`) -* `VolumeUp`、`VolumeDown` 和 `VolumeMute` -* `MediaNextTrack`、`MediaPreviousTrack`、`MediaStop` 和 `MediaPlayPause` diff --git a/docs-translations/zh-CN/api/app.md b/docs-translations/zh-CN/api/app.md deleted file mode 100644 index c2f244f438823..0000000000000 --- a/docs-translations/zh-CN/api/app.md +++ /dev/null @@ -1,483 +0,0 @@ -# app - -`app` 模块是为了控制整个应用的生命周期设计的。 - -下面的这个例子将会展示如何在最后一个窗口被关闭时退出应用: - -```javascript -var app = require('app'); -app.on('window-all-closed', function() { - app.quit(); -}); -``` - -## 事件列表 - -`app` 对象会触发以下的事件: - -### 事件:'will-finish-launching' - -当应用程序完成基础的启动的时候被触发。在 Windows 和 Linux 中, -`will-finish-launching` 事件与 `ready` 事件是相同的; 在 macOS 中, -这个时间相当于 `NSApplication` 中的 `applicationWillFinishLaunching` 提示。 -你应该经常在这里为 `open-file` 和 `open-url` 设置监听器,并启动崩溃报告和自动更新。 - -在大多数的情况下,你应该只在 `ready` 事件处理器中完成所有的业务。 - -### 事件:'ready' - -当 Electron 完成初始化时被触发。 - -### 事件:'window-all-closed' - -当所有的窗口都被关闭时触发。 - -这个事件仅在应用还没有退出时才能触发。 如果用户按下了 `Cmd + Q`, -或者开发者调用了 `app.quit()` ,Electron 将会先尝试关闭所有的窗口再触发 `will-quit` 事件, -在这种情况下 `window-all-closed` 不会被触发。 - -### 事件:'before-quit' - -返回: - -* `event` Event - -在应用程序开始关闭它的窗口的时候被触发。 -调用 `event.preventDefault()` 将会阻止终止应用程序的默认行为。 - -### 事件:'will-quit' - -返回: - -* `event` Event - -当所有的窗口已经被关闭,应用即将退出时被触发。 -调用 `event.preventDefault()` 将会阻止终止应用程序的默认行为。 - -你可以在 `window-all-closed` 事件的描述中看到 `will-quit` 事件 -和 `window-all-closed` 事件的区别。 - -### 事件:'quit' -返回: - -* `event` Event -* `exitCode` Integer - -当应用程序正在退出时触发。 - -### 事件:'open-file' _macOS_ - -返回: - -* `event` Event -* `path` String - -当用户想要在应用中打开一个文件时触发。`open-file` 事件常常在应用已经打开并且系统想要再次使用应用打开文件时被触发。 - `open-file` 也会在一个文件被拖入 dock 且应用还没有运行的时候被触发。 -请确认在应用启动的时候(甚至在 `ready` 事件被触发前)就对 `open-file` 事件进行监听,以处理这种情况。 - -如果你想处理这个事件,你应该调用 `event.preventDefault()` 。 -在 Windows系统中, 你需要通过解析 process.argv 来获取文件路径。 - -### 事件:'open-url' _macOS_ - -返回: - -* `event` Event -* `url` String - -当用户想要在应用中打开一个url的时候被触发。URL格式必须要提前标识才能被你的应用打开。 - -如果你想处理这个事件,你应该调用 `event.preventDefault()` 。 - -### 事件:'activate' _macOS_ - -返回: - -* `event` Event -* `hasVisibleWindows` Boolean - -当应用被激活时触发,常用于点击应用的 dock 图标的时候。 - -### 事件:'browser-window-blur' - -返回: - -* `event` Event -* `window` BrowserWindow - -当一个 [BrowserWindow](browser-window.md) 失去焦点的时候触发。 - -### 事件:'browser-window-focus' - -返回: - -* `event` Event -* `window` BrowserWindow - -当一个 [BrowserWindow](browser-window.md) 获得焦点的时候触发。 - -### 事件:'browser-window-created' - -返回: - -* `event` Event -* `window` BrowserWindow - -当一个 [BrowserWindow](browser-window.md) 被创建的时候触发。 - -### 事件:'certificate-error' - -返回: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `url` String - URL 地址 -* `error` String - 错误码 -* `certificate` Object - * `data` Buffer - PEM 编码数据 - * `issuerName` String - 发行者的公有名称 -* `callback` Function - -当对 `url` 验证 `certificate` 证书失败的时候触发,如果需要信任这个证书,你需要阻止默认行为 `event.preventDefault()` 并且 -调用 `callback(true)`。 - -```javascript -session.on('certificate-error', function(event, webContents, url, error, certificate, callback) { - if (url == "https://github.com") { - // 验证逻辑。 - event.preventDefault(); - callback(true); - } else { - callback(false); - } -}); -``` - -### 事件:'select-client-certificate' - - -返回: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `url` String - URL 地址 -* `certificateList` [Object] - * `data` Buffer - PEM 编码数据 - * `issuerName` String - 发行者的公有名称 -* `callback` Function - -当一个客户端认证被请求的时候被触发。 - -`url` 指的是请求客户端认证的网页地址,调用 `callback` 时需要传入一个证书列表中的证书。 - -需要通过调用 `event.preventDefault()` 来防止应用自动使用第一个证书进行验证。如下所示: - -```javascript -app.on('select-certificate', function(event, host, url, list, callback) { - event.preventDefault(); - callback(list[0]); -}) -``` -### 事件: 'login' - -返回: - -* `event` Event -* `webContents` [WebContents](web-contents.md) -* `request` Object - * `method` String - * `url` URL - * `referrer` URL -* `authInfo` Object - * `isProxy` Boolean - * `scheme` String - * `host` String - * `port` Integer - * `realm` String -* `callback` Function - -当 `webContents` 要做进行一次 HTTP 登陆验证时被触发。 - -默认情况下,Electron 会取消所有的验证行为,如果需要重写这个行为,你需要用 `event.preventDefault()` 来阻止默认行为,并且 -用 `callback(username, password)` 来进行验证。 - -```javascript -app.on('login', function(event, webContents, request, authInfo, callback) { - event.preventDefault(); - callback('username', 'secret'); -}) -``` -### 事件:'gpu-process-crashed' - -当 GPU 进程崩溃时触发。 - -## 方法列表 - -`app` 对象拥有以下的方法: - -**请注意** 有的方法只能用于特定的操作系统。 - -### `app.quit()` - -试图关掉所有的窗口。`before-quit` 事件将会最先被触发。如果所有的窗口都被成功关闭了, -`will-quit` 事件将会被触发,默认下应用将会被关闭。 - -这个方法保证了所有的 `beforeunload` 和 `unload` 事件处理器被正确执行。假如一个窗口的 `beforeunload` 事件处理器返回 `false`,那么整个应用可能会取消退出。 - -### `app.hide()` _macOS_ - -隐藏所有的应用窗口,不是最小化. - -### `app.show()` _macOS_ - -隐藏后重新显示所有的窗口,不会自动选中他们。 - -### `app.exit(exitCode)` - -* `exitCode` 整数 - -带着`exitCode`退出应用. - -所有的窗口会被立刻关闭,不会询问用户。`before-quit` 和 `will-quit` 这2个事件不会被触发 - -### `app.getAppPath()` - -返回当前应用所在的文件路径。 - -### `app.getPath(name)` - -* `name` String - -返回一个与 `name` 参数相关的特殊文件夹或文件路径。当失败时抛出一个 `Error` 。 - -你可以通过名称请求以下的路径: - -* `home` 用户的 home 文件夹(主目录) -* `appData` 当前用户的应用数据文件夹,默认对应: - * `%APPDATA%` Windows 中 - * `$XDG_CONFIG_HOME` or `~/.config` Linux 中 - * `~/Library/Application Support` macOS 中 -* `userData` 储存你应用程序设置文件的文件夹,默认是 `appData` 文件夹附加应用的名称 -* `temp` 临时文件夹 -* `exe` 当前的可执行文件 -* `module` `libchromiumcontent` 库 -* `desktop` 当前用户的桌面文件夹 -* `documents` 用户文档目录的路径 -* `downloads` 用户下载目录的路径. -* `music` 用户音乐目录的路径. -* `pictures` 用户图片目录的路径. -* `videos` 用户视频目录的路径. - -### `app.setPath(name, path)` - -* `name` String -* `path` String - -重写某个 `name` 的路径为 `path`,`path` 可以是一个文件夹或者一个文件,这个和 `name` 的类型有关。 -如果这个路径指向的文件夹不存在,这个文件夹将会被这个方法创建。 -如果错误则会抛出 `Error`。 - -`name` 参数只能使用 `app.getPath` 中定义过 `name`。 - -默认情况下,网页的 cookie 和缓存都会储存在 `userData` 文件夹。 -如果你想要改变这个位置,你需要在 `app` 模块中的 `ready` 事件被触发之前重写 `userData` 的路径。 - -### `app.getVersion()` - -返回加载应用程序的版本。如果应用程序的 `package.json` 文件中没有写版本号, -将会返回当前包或者可执行文件的版本。 - -### `app.getName()` - -返回当前应用程序的 `package.json` 文件中的名称。 - -由于 npm 的命名规则,通常 `name` 字段是一个短的小写字符串。但是应用名的完整名称通常是首字母大写的,你应该单独使用一个 -`productName` 字段,用于表示你的应用程序的完整名称。Electron 会优先使用这个字段作为应用名。 - -### `app.setName(name)` - -* `name` String - -重写当前应用的名字 - -### `app.getLocale()` - -返回当前应用程序的语言。 - -### `app.addRecentDocument(path)` _macOS_ _Windows_ - -* `path` String - -在最近访问的文档列表中添加 `path`。 - -这个列表由操作系统进行管理。在 Windows 中您可以通过任务条进行访问,在 macOS 中你可以通过 dock 菜单进行访问。 - -### `app.clearRecentDocuments()` _macOS_ _Windows_ - -清除最近访问的文档列表。 - -### `app.setUserTasks(tasks)` _Windows_ - -* `tasks` [Task] - 一个由 Task 对象构成的数组 - -将 `tasks` 添加到 Windows 中 JumpList 功能的 [Tasks][tasks] 分类中。 - -`tasks` 中的 `Task` 对象格式如下: - -`Task` Object -* `program` String - 执行程序的路径,通常你应该说明当前程序的路径为 `process.execPath` 字段。 -* `arguments` String - 当 `program` 执行时的命令行参数。 -* `title` String - JumpList 中显示的标题。 -* `description` String - 对这个任务的描述。 -* `iconPath` String - JumpList 中显示的图标的绝对路径,可以是一个任意包含一个图标的资源文件。通常来说,你可以通过指明 `process.execPath` 来显示程序中的图标。 -* `iconIndex` Integer - 图标文件中的采用的图标位置。如果一个图标文件包括了多个图标,就需要设置这个值以确定使用的是哪一个图标。 -如果这个图标文件中只包含一个图标,那么这个值为 0。 - -### `app.allowNTLMCredentialsForAllDomains(allow)` - -* `allow` Boolean - -动态设置是否总是为 HTTP NTLM 或 Negotiate 认证发送证书。通常来说,Electron 只会对本地网络(比如和你处在一个域中的计算机)发 -送 NTLM / Kerberos 证书。但是假如网络设置得不太好,可能这个自动探测会失效,所以你可以通过这个接口自定义 Electron 对所有 URL -的行为。 - -### `app.makeSingleInstance(callback)` - -* `callback` Function - -这个方法可以让你的应用在同一时刻最多只会有一个实例,否则你的应用可以被运行多次并产生多个实例。你可以利用这个接口保证只有一个实例正 -常运行,其余的实例全部会被终止并退出。 - -如果多个实例同时运行,那么第一个被运行的实例中 `callback` 会以 `callback(argv, workingDirectory)` 的形式被调用。其余的实例 -会被终止。 -`argv` 是一个包含了这个实例的命令行参数列表的数组,`workingDirectory` 是这个实例目前的运行目录。通常来说,我们会用通过将应用在 -主屏幕上激活,并且取消最小化,来提醒用户这个应用已经被打开了。 - -在 `app` 的 `ready` 事件后,`callback` 才有可能被调用。 - -如果当前实例为第一个实例,那么在这个方法将会返回 `false` 来保证它继续运行。否则将会返回 `true` 来让它立刻退出。 - -在 macOS 中,如果用户通过 Finder、`open-file` 或者 `open-url` 打开应用,系统会强制确保只有一个实例在运行。但是如果用户是通过 -命令行打开,这个系统机制会被忽略,所以你仍然需要靠这个方法来保证应用为单实例运行的。 - -下面是一个简单的例子。我们可以通过这个例子了解如何确保应用为单实例运行状态。 - -```js -var myWindow = null; - -var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { - // 当另一个实例运行的时候,这里将会被调用,我们需要激活应用的窗口 - if (myWindow) { - if (myWindow.isMinimized()) myWindow.restore(); - myWindow.focus(); - } - return true; -}); - -// 这个实例是多余的实例,需要退出 -if (shouldQuit) { - app.quit(); - return; -} - -// 创建窗口、继续加载应用、应用逻辑等…… -app.on('ready', function() { -}); - -``` -### `app.setAppUserModelId(id)` _Windows_ - -* `id` String - -改变当前应用的 [Application User Model ID][app-user-model-id] 为 `id`. - -### `app.isAeroGlassEnabled()` _Windows_ - -如果 [DWM composition](https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx)(Aero Glass) 启用 -了,那么这个方法会返回 `true`,否则是 `false`。你可以用这个方法来决定是否要开启透明窗口特效,因为如果用户没开启 DWM,那么透明窗 -口特效是无效的。 - -举个例子: - -```js -let browserOptions = {width: 1000, height: 800}; - -// 只有平台支持的时候才使用透明窗口 -if (process.platform !== 'win32' || app.isAeroGlassEnabled()) { - browserOptions.transparent = true; - browserOptions.frame = false; -} - -// 创建窗口 -win = new BrowserWindow(browserOptions); - -// 转到某个网页 -if (browserOptions.transparent) { - win.loadURL('file://' + __dirname + '/index.html'); -} else { - // 没有透明特效,我们应该用某个只包含基本样式的替代解决方案。 - win.loadURL('file://' + __dirname + '/fallback.html'); -} -``` -### `app.commandLine.appendSwitch(switch[, value])` - -通过可选的参数 `value` 给 Chromium 中添加一个命令行开关。 - -**注意** 这个方法不会影响 `process.argv`,我们通常用这个方法控制一些底层 Chromium 行为。 - -### `app.commandLine.appendArgument(value)` - -给 Chromium 中直接添加一个命令行参数,这个参数 `value` 的引号和格式必须正确。 - -**注意** 这个方法不会影响 `process.argv`。 - -### `app.dock.bounce([type])` _macOS_ - -* `type` String - 可选参数,可以是 `critical` 或 `informational`。默认为 `informational`。 - -当传入的是 `critical` 时,dock 中的应用将会开始弹跳,直到这个应用被激活或者这个请求被取消。 - -当传入的是 `informational` 时,dock 中的图标只会弹跳一秒钟。但是,这个请求仍然会激活,直到应用被激活或者请求被取消。 - -这个方法返回的返回值表示这个请求的 ID。 - -### `app.dock.cancelBounce(id)` _macOS_ - -* `id` Integer - -取消这个 `id` 对应的请求。 - -### `app.dock.setBadge(text)` _macOS_ - -* `text` String - -设置应用在 dock 中显示的字符串。 - -### `app.dock.getBadge()` _macOS_ - -返回应用在 dock 中显示的字符串。 - -### `app.dock.hide()` _macOS_ - -隐藏应用在 dock 中的图标。 - -### `app.dock.show()` _macOS_ - -显示应用在 dock 中的图标。 - -### `app.dock.setMenu(menu)` _macOS_ - -* `menu` [Menu](menu.md) - -设置应用的 [dock 菜单][dock-menu]. - -### `app.dock.setIcon(image)` _macOS_ - -* `image` [NativeImage](native-image.md) - -设置应用在 dock 中显示的图标。 - -[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 -[tasks]:http://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 diff --git a/docs-translations/zh-CN/api/auto-updater.md b/docs-translations/zh-CN/api/auto-updater.md deleted file mode 100644 index 845b4c24d9bf2..0000000000000 --- a/docs-translations/zh-CN/api/auto-updater.md +++ /dev/null @@ -1,88 +0,0 @@ -# autoUpdater - -这个模块提供了一个到 `Squirrel` 自动更新框架的接口。 - -## 平台相关的提示 - -虽然 `autoUpdater` 模块提供了一套各平台通用的接口,但是在每个平台间依然会有一些微小的差异。 - -### macOS - -在 macOS 上,`autoUpdater` 模块依靠的是内置的 [Squirrel.Mac][squirrel-mac],这意味着你不需要依靠其他的设置就能使用。关于 -更新服务器的配置,你可以通过阅读 [Server Support][server-support] 这篇文章来了解。 - -### Windows - -在 Windows 上,你必须使用安装程序将你的应用装到用户的计算机上,所以比较推荐的方法是用 [grunt-electron-installer][installer] 这个模块来自动生成一个 Windows 安装向导。 - -Squirrel 自动生成的安装向导会生成一个带 [Application User Model ID][app-user-model-id] 的快捷方式。 -Application User Model ID 的格式是 `com.squirrel.PACKAGE_ID.YOUR_EXE_WITHOUT_DOT_EXE`, 比如 -像 `com.squirrel.slack.Slack` 和 `com.squirrel.code.Code` 这样的。你应该在自己的应用中使用 `app.setAppUserModelId` 方法设置相同的 API,不然 Windows 将不能正确地把你的应用固定在任务栏上。 - -服务器端的配置和 macOS 也是不一样的,你可以阅读 [Squirrel.Windows][squirrel-windows] 这个文档来获得详细信息。 - -### Linux - -Linux 下没有任何的自动更新支持,所以我们推荐用各个 Linux 发行版的包管理器来分发你的应用。 - -## 事件列表 - -`autoUpdater` 对象会触发以下的事件: - -### 事件:'error' - -返回: - -* `error` Error - -当更新发生错误的时候触发。 - -### 事件:'checking-for-update' - -当开始检查更新的时候触发。 - -### 事件:'update-available' - -当发现一个可用更新的时候触发,更新包下载会自动开始。 - -### 事件:'update-not-available' - -当没有可用更新的时候触发。 - -### 事件:'update-downloaded' - -返回: - -* `event` Event -* `releaseNotes` String - 新版本更新公告 -* `releaseName` String - 新的版本号 -* `releaseDate` Date - 新版本发布的日期 -* `updateURL` String - 更新地址 - -在更新下载完成的时候触发。 - -在 Windows 上只有 `releaseName` 是有效的。 - -## 方法列表 - -`autoUpdater` 对象有以下的方法: - -### `autoUpdater.setFeedURL(url)` - -* `url` String - -设置检查更新的 `url`,并且初始化自动更新。这个 `url` 一旦设置就无法更改。 - -### `autoUpdater.checkForUpdates()` - -向服务端查询现在是否有可用的更新。在调用这个方法之前,必须要先调用 `setFeedURL`。 - -### `autoUpdater.quitAndInstall()` - -在下载完成后,重启当前的应用并且安装更新。这个方法应该仅在 `update-downloaded` 事件触发后被调用。 - -[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/atom/grunt-electron-installer -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx diff --git a/docs-translations/zh-CN/api/browser-window.md b/docs-translations/zh-CN/api/browser-window.md deleted file mode 100644 index d28ffc9f45ea2..0000000000000 --- a/docs-translations/zh-CN/api/browser-window.md +++ /dev/null @@ -1,753 +0,0 @@ -# BrowserWindow - - `BrowserWindow` 类让你有创建一个浏览器窗口的权力。例如: - -```javascript -// In the main process. -const BrowserWindow = require('electron').BrowserWindow; - -// Or in the renderer process. -const BrowserWindow = require('electron').remote.BrowserWindow; - -var win = new BrowserWindow({ width: 800, height: 600, show: false }); -win.on('closed', function() { - win = null; -}); - -win.loadURL('https://github.com'); -win.show(); -``` - -你也可以不通过chrome创建窗口,使用 -[Frameless Window](frameless-window.md) API. - -## Class: BrowserWindow - -`BrowserWindow` 是一个 -[EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter). - -通过 `options` 可以创建一个具有本质属性的 `BrowserWindow` . - -### `new BrowserWindow([options])` - -* `options` Object - * `width` Integer - 窗口宽度,单位像素. 默认是 `800`. - * `height` Integer - 窗口高度,单位像素. 默认是 `600`. - * `x` Integer - 窗口相对于屏幕的左偏移位置.默认居中. - * `y` Integer - 窗口相对于屏幕的顶部偏移位置.默认居中. - * `useContentSize` Boolean - `width` 和 `height` 使用web网页size, 这意味着实际窗口的size应该包括窗口框架的size,稍微会大一点,默认为 `false`. - * `center` Boolean - 窗口屏幕居中. - * `minWidth` Integer - 窗口最小宽度,默认为 `0`. - * `minHeight` Integer - 窗口最小高度,默认为 `0`. - * `maxWidth` Integer - 窗口最大宽度,默认无限制. - * `maxHeight` Integer - 窗口最大高度,默认无限制. - * `resizable` Boolean - 是否可以改变窗口size,默认为 `true`. - * `movable` Boolean - 窗口是否可以拖动. 在 Linux 上无效. 默认为 `true`. - * `minimizable` Boolean - 窗口是否可以最小化. 在 Linux 上无效. 默认为 `true`. - * `maximizable` Boolean - 窗口是否可以最大化. 在 Linux 上无效. 默认为 `true`. - * `closable` Boolean - 窗口是否可以关闭. 在 Linux 上无效. 默认为 `true`. - * `alwaysOnTop` Boolean - 窗口是否总是显示在其他窗口之前. 在 Linux 上无效. 默认为 `false`. - * `fullscreen` Boolean - 窗口是否可以全屏幕. 当明确设置值为 `false` ,全屏化按钮将会隐藏,在 macOS 将禁用. 默认 `false`. - * `fullscreenable` Boolean - 在 macOS 上,全屏化按钮是否可用,默认为 `true`. - * `skipTaskbar` Boolean - 是否在任务栏中显示窗口. 默认是`false`. - * `kiosk` Boolean - kiosk 方式. 默认为 `false`. - * `title` String - 窗口默认title. 默认 `"Electron"`. - * `icon` [NativeImage](native-image.md) - 窗口图标, 如果不设置,窗口将使用可用的默认图标. - * `show` Boolean - 窗口创建的时候是否显示. 默认为 `true`. - * `frame` Boolean - 指定 `false` 来创建一个 - [Frameless Window](frameless-window.md). 默认为 `true`. - * `acceptFirstMouse` Boolean - 是否允许单击web view来激活窗口 . 默认为 `false`. - * `disableAutoHideCursor` Boolean - 当 typing 时是否隐藏鼠标.默认 `false`. - * `autoHideMenuBar` Boolean - 除非点击 `Alt`,否则隐藏菜单栏.默认为 `false`. - * `enableLargerThanScreen` Boolean - 是否允许允许改变窗口大小大于屏幕. 默认是 `false`. - * `backgroundColor` String -窗口的 background color 值为十六进制,如 `#66CD00` 或 `#FFF` 或 `#80FFFFFF` (支持透明度). 默认为在 Linux 和 Windows 上为 - `#000` (黑色) , Mac上为 `#FFF`(或透明). - * `hasShadow` Boolean - 窗口是否有阴影. 只在 macOS 上有效. 默认为 `true`. - * `darkTheme` Boolean - 为窗口使用 dark 主题, 只在一些拥有 GTK+3 桌面环境上有效. 默认为 `false`. - * `transparent` Boolean - 窗口 [透明](frameless-window.md). - 默认为 `false`. - * `type` String - 窗口type, 默认普通窗口. 下面查看更多. - * `titleBarStyle` String - 窗口标题栏样式. 下面查看更多. - * `webPreferences` Object - 设置界面特性. 下面查看更多. - -`type` 的值和效果不同平台展示效果不同,具体: - -* Linux, 可用值为 `desktop`, `dock`, `toolbar`, `splash`, - `notification`. -* macOS, 可用值为 `desktop`, `textured`. - * `textured` type 添加金属梯度效果 - (`NSTexturedBackgroundWindowMask`). - * `desktop` 设置窗口在桌面背景窗口水平 - (`kCGDesktopWindowLevel - 1`). 注意桌面窗口不可聚焦, 不可不支持键盘和鼠标事件, 但是可以使用 `globalShortcut` 来解决输入问题. - -`titleBarStyle` 只在 macOS 10.10 Yosemite 或更新版本上支持. -可用值: - -* `default` 以及无值, 显示在 Mac 标题栏上为不透明的标准灰色. -* `hidden` 隐藏标题栏,内容充满整个窗口, 然后它依然在左上角,仍然受标准窗口控制. -* `hidden-inset`主体隐藏,显示小的控制按钮在窗口边缘. - -`webPreferences` 参数是个对象,它的属性: - -* `nodeIntegration` Boolean - 是否完整支持node. 默认为 `true`. -* `preload` String - 界面的其它脚本运行之前预先加载一个指定脚本. 这个脚本将一直可以使用 node APIs 无论 node integration 是否开启. 脚本路径为绝对路径. - 当 node integration 关闭, 预加载的脚本将从全局范围重新引入node的全局引用标志. 查看例子 - [here](process.md#event-loaded). -* `session` [Session](session.md#class-session) - 设置界面session. 而不是直接忽略session对象 , 也可用 `partition` 来代替, 它接受一个 partition 字符串. 当同时使用 `session` 和 `partition`, `session` 优先级更高. - 默认使用默认 session. -* `partition` String - 通过session的partition字符串来设置界面session. 如果 `partition` 以 `persist:` 开头, 这个界面将会为所有界面使用相同的 `partition`. 如果没有 `persist:` 前缀, 界面使用历史session. 通过分享同一个 `partition`, 所有界面使用相同的session. 默认使用默认 session. -* `zoomFactor` Number - 界面默认缩放值, `3.0` 表示 - `300%`. 默认 `1.0`. -* `javascript` Boolean - 开启javascript支持. 默认为`true`. -* `webSecurity` Boolean - 当设置为 `false`, 它将禁用同源策略 (通常用来测试网站), 并且如果有2个非用户设置的参数,就设置 - `allowDisplayingInsecureContent` 和 `allowRunningInsecureContent` 的值为 - `true`. 默认为 `true`. -* `allowDisplayingInsecureContent` Boolean -允许一个使用 https的界面来展示由 http URLs 传过来的资源. 默认`false`. -* `allowRunningInsecureContent` Boolean - Boolean -允许一个使用 https的界面来渲染由 http URLs 提交的html,css,javascript. 默认为 `false`. -* `images` Boolean - 开启图片使用支持. 默认 `true`. -* `textAreasAreResizable` Boolean - textArea 可以编辑. 默认为 `true`. -* `webgl` Boolean - 开启 WebGL 支持. 默认为 `true`. -* `webaudio` Boolean - 开启 WebAudio 支持. 默认为 `true`. -* `plugins` Boolean - 是否开启插件支持. 默认为 `false`. -* `experimentalFeatures` Boolean - 开启 Chromium 的 可测试 特性. - 默认为 `false`. -* `experimentalCanvasFeatures` Boolean - 开启 Chromium 的 canvas 可测试特性. 默认为 `false`. -* `directWrite` Boolean - 开启窗口的 DirectWrite font 渲染系统. 默认为 `true`. -* `blinkFeatures` String - 以 `,` 分隔的特性列表, 如 - `CSSVariables,KeyboardEventKey`. 被支持的所有特性可在 [setFeatureEnabledFromString][blink-feature-string] - 中找到. -* `defaultFontFamily` Object - 设置 font-family 默认字体. - * `standard` String - 默认为 `Times New Roman`. - * `serif` String - 默认为 `Times New Roman`. - * `sansSerif` String - 默认为 `Arial`. - * `monospace` String - 默认为 `Courier New`. -* `defaultFontSize` Integer - 默认为 `16`. -* `defaultMonospaceFontSize` Integer - 默认为 `13`. -* `minimumFontSize` Integer - 默认为 `0`. -* `defaultEncoding` String - 默认为 `ISO-8859-1`. - -## 事件 - - `BrowserWindow` 对象可触发下列事件: - -**注意:** 一些事件只能在特定os环境中触发,已经尽可能地标出. - -### Event: 'page-title-updated' - -返回: - -* `event` Event - -当文档改变标题时触发,使用 `event.preventDefault()` 可以阻止原窗口的标题改变. - -### Event: 'close' - -返回: - -* `event` Event - -在窗口要关闭的时候触发. 它在DOM的 `beforeunload` and `unload` 事件之前触发.使用 `event.preventDefault()` 可以取消这个操作 - -通常你想通过 `beforeunload` 处理器来决定是否关闭窗口,但是它也会在窗口重载的时候被触发. 在 Electron 中,返回一个空的字符串或 `false` 可以取消关闭.例如: - -```javascript -window.onbeforeunload = function(e) { - console.log('I do not want to be closed'); - - // Unlike usual browsers, in which a string should be returned and the user is - // prompted to confirm the page unload, Electron gives developers more options. - // Returning empty string or false would prevent the unloading now. - // You can also use the dialog API to let the user confirm closing the application. - e.returnValue = false; -}; -``` - -### Event: 'closed' - -当窗口已经关闭的时候触发.当你接收到这个事件的时候,你应当删除对已经关闭的窗口的引用对象和避免再次使用它. - -### Event: 'unresponsive' - -在界面卡死的时候触发事件. - -### Event: 'responsive' - -在界面恢复卡死的时候触发. - -### Event: 'blur' - -在窗口失去焦点的时候触发. - -### Event: 'focus' - -在窗口获得焦点的时候触发. - -### Event: 'maximize' - -在窗口最大化的时候触发. - -### Event: 'unmaximize' - -在窗口退出最大化的时候触发. - -### Event: 'minimize' - -在窗口最小化的时候触发. - -### Event: 'restore' - -在窗口从最小化恢复的时候触发. - -### Event: 'resize' - -在窗口size改变的时候触发. - -### Event: 'move' - -在窗口移动的时候触发. - -注意:在 macOS 中别名为 `moved`. - -### Event: 'moved' _macOS_ - -在窗口移动的时候触发. - -### Event: 'enter-full-screen' - -在的窗口进入全屏状态时候触发. - -### Event: 'leave-full-screen' - -在的窗口退出全屏状态时候触发. - -### Event: 'enter-html-full-screen' - -在的窗口通过 html api 进入全屏状态时候触发. - -### Event: 'leave-html-full-screen' - -在的窗口通过 html api 退出全屏状态时候触发. - -### Event: 'app-command' _Windows_ - -在请求一个[App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx)的时候触发. -典型的是键盘媒体或浏览器命令, Windows上的 "Back" 按钮用作鼠标也会触发. - -```js -someWindow.on('app-command', function(e, cmd) { - // Navigate the window back when the user hits their mouse back button - if (cmd === 'browser-backward' && someWindow.webContents.canGoBack()) { - someWindow.webContents.goBack(); - } -}); -``` - -### Event: 'scroll-touch-begin' _macOS_ - -在滚动条事件开始的时候触发. - -### Event: 'scroll-touch-end' _macOS_ - -在滚动条事件结束的时候触发. - -## 方法 - -`BrowserWindow` 对象有如下方法: - -### `BrowserWindow.getAllWindows()` - -返回一个所有已经打开了窗口的对象数组. - -### `BrowserWindow.getFocusedWindow()` - -返回应用当前获得焦点窗口,如果没有就返回 `null`. - -### `BrowserWindow.fromWebContents(webContents)` - -* `webContents` [WebContents](web-contents.md) - -根据 `webContents` 查找窗口. - -### `BrowserWindow.fromId(id)` - -* `id` Integer - -根据 id 查找窗口. - -### `BrowserWindow.addDevToolsExtension(path)` - -* `path` String - -添加位于 `path` 的开发者工具栏扩展,并且返回扩展项的名字. - -这个扩展会被添加到历史,所以只需要使用这个API一次,这个api不可用作编程使用. - -### `BrowserWindow.removeDevToolsExtension(name)` - -* `name` String - -删除开发者工具栏名为 `name` 的扩展. - -## 实例属性 - -使用 `new BrowserWindow` 创建的实例对象,有如下属性: - -```javascript -// In this example `win` is our instance -var win = new BrowserWindow({ width: 800, height: 600 }); -``` - -### `win.webContents` - -这个窗口的 `WebContents` 对象,所有与界面相关的事件和方法都通过它完成的. - -查看 [`webContents` documentation](web-contents.md) 的方法和事件. - -### `win.id` - -窗口的唯一id. - -## 实例方法 - -使用 `new BrowserWindow` 创建的实例对象,有如下方法: - -**注意:** 一些方法只能在特定os环境中调用,已经尽可能地标出. - -### `win.destroy()` - -强制关闭窗口, `unload` and `beforeunload` 不会触发,并且 `close` 也不会触发, 但是它保证了 `closed` 触发. - -### `win.close()` - -尝试关闭窗口,这与用户点击关闭按钮的效果一样. 虽然网页可能会取消关闭,查看 [close event](#event-close). - -### `win.focus()` - -窗口获得焦点. - -### `win.isFocused()` - -返回 boolean, 窗口是否获得焦点. - -### `win.show()` - -展示并且使窗口获得焦点. - -### `win.showInactive()` - -展示窗口但是不获得焦点. - -### `win.hide()` - -隐藏窗口. - -### `win.isVisible()` - -返回 boolean, 窗口是否可见. - -### `win.maximize()` - -窗口最大化. - -### `win.unmaximize()` - -取消窗口最大化. - -### `win.isMaximized()` - -返回 boolean, 窗口是否最大化. - -### `win.minimize()` - -窗口最小化. 在一些os中,它将在dock中显示. - -### `win.restore()` - -将最小化的窗口恢复为之前的状态. - -### `win.isMinimized()` - -返回 boolean, 窗口是否最小化. - -### `win.setFullScreen(flag)` - -* `flag` Boolean - -设置是否全屏. - -### `win.isFullScreen()` - -返回 boolean, 窗口是否全屏化. - -### `win.setAspectRatio(aspectRatio[, extraSize])` _macOS_ - -* `aspectRatio` 维持部分视图内容窗口的高宽比值. -* `extraSize` Object (可选) - 维持高宽比值时不包含的额外size. - * `width` Integer - * `height` Integer - -由一个窗口来维持高宽比值. `extraSize` 允许开发者使用它,它的单位为像素,不包含在 `aspectRatio` 中.这个 API 可用来区分窗口的size和内容的size . - -想象一个普通可控的HD video 播放器窗口. 假如左边缘有15控制像素,右边缘有25控制像素,在播放器下面有50控制像素.为了在播放器内保持一个 16:9 的高宽比例,我们可以调用这个api传入参数16/9 and -[ 40, 50 ].第二个参数不管网页中的额外的宽度和高度在什么位置,只要它们存在就行.只需要把网页中的所有额外的高度和宽度加起来就行. - -### `win.setBounds(options[, animate])` - -* `options` Object - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer -* `animate` Boolean (可选) _macOS_ - -重新设置窗口的宽高值,并且移动到指定的 `x`, `y` 位置. - -### `win.getBounds()` - -返回一个对象,它包含了窗口的宽,高,x坐标,y坐标. - -### `win.setSize(width, height[, animate])` - -* `width` Integer -* `height` Integer -* `animate` Boolean (可选) _macOS_ - -重新设置窗口的宽高值. - -### `win.getSize()` - -返回一个数组,它包含了窗口的宽,高. - -### `win.setContentSize(width, height[, animate])` - -* `width` Integer -* `height` Integer -* `animate` Boolean (可选) _macOS_ - -重新设置窗口客户端的宽高值(例如网页界面). - -### `win.getContentSize()` - -返回一个数组,它包含了窗口客户端的宽,高. - -### `win.setMinimumSize(width, height)` - -* `width` Integer -* `height` Integer - -设置窗口最小化的宽高值. - -### `win.getMinimumSize()` - -返回一个数组,它包含了窗口最小化的宽,高. - -### `win.setMaximumSize(width, height)` - -* `width` Integer -* `height` Integer - -设置窗口最大化的宽高值. - -### `win.getMaximumSize()` - -返回一个数组,它包含了窗口最大化的宽,高. - -### `win.setResizable(resizable)` - -* `resizable` Boolean - -设置窗口是否可以被用户改变size. - -### `win.isResizable()` - -返回 boolean,窗口是否可以被用户改变size. - -### `win.setMovable(movable)` _macOS_ _Windows_ - -* `movable` Boolean - -设置窗口是否可以被用户拖动. Linux 无效. - -### `win.isMovable()` _macOS_ _Windows_ - -返回 boolean,窗口是否可以被用户拖动. Linux 总是返回 `true`. - -### `win.setMinimizable(minimizable)` _macOS_ _Windows_ - -* `minimizable` Boolean - -设置窗口是否可以最小化. Linux 无效. - -### `win.isMinimizable()` _macOS_ _Windows_ - -返回 boolean,窗口是否可以最小化. Linux 总是返回 `true`. - -### `win.setMaximizable(maximizable)` _macOS_ _Windows_ - -* `maximizable` Boolean - -设置窗口是否可以最大化. Linux 无效. - -### `win.isMaximizable()` _macOS_ _Windows_ - -返回 boolean,窗口是否可以最大化. Linux 总是返回 `true`. - -### `win.setFullScreenable(fullscreenable)` - -* `fullscreenable` Boolean - -设置点击最大化按钮是否可以全屏或最大化窗口. - -### `win.isFullScreenable()` - -返回 boolean,点击最大化按钮是否可以全屏或最大化窗口. - -### `win.setClosable(closable)` _macOS_ _Windows_ - -* `closable` Boolean - -设置窗口是否可以人为关闭. Linux 无效. - -### `win.isClosable()` _macOS_ _Windows_ - -返回 boolean,窗口是否可以人为关闭. Linux 总是返回 `true`. - -### `win.setAlwaysOnTop(flag)` - -* `flag` Boolean - -是否设置这个窗口始终在其他窗口之上.设置之后,这个窗口仍然是一个普通的窗口,不是一个不可以获得焦点的工具箱窗口. - -### `win.isAlwaysOnTop()` - -返回 boolean,当前窗口是否始终在其它窗口之前. - -### `win.center()` - -窗口居中. - -### `win.setPosition(x, y[, animate])` - -* `x` Integer -* `y` Integer -* `animate` Boolean (可选) _macOS_ - -移动窗口到对应的 `x` and `y` 坐标. - -### `win.getPosition()` - -返回一个包含当前窗口位置的数组. - -### `win.setTitle(title)` - -* `title` String - -改变原窗口的title. - -### `win.getTitle()` - -返回原窗口的title. - -**注意:** 界面title可能和窗口title不相同. - -### `win.flashFrame(flag)` - -* `flag` Boolean - -开始或停止显示窗口来获得用户的关注. - -### `win.setSkipTaskbar(skip)` - -* `skip` Boolean - -让窗口不在任务栏中显示. - -### `win.setKiosk(flag)` - -* `flag` Boolean - -进入或离开 kiosk 模式. - -### `win.isKiosk()` - -返回 boolean,是否进入或离开 kiosk 模式. - -### `win.getNativeWindowHandle()` - -以 `Buffer` 形式返回这个具体平台的窗口的句柄. - -windows上句柄类型为 `HWND` ,macOS `NSView*` , Linux `Window`. - -### `win.hookWindowMessage(message, callback)` _Windows_ - -* `message` Integer -* `callback` Function - -拦截windows 消息,在 WndProc 接收到消息时触发 `callback`函数. - -### `win.isWindowMessageHooked(message)` _Windows_ - -* `message` Integer - -返回 `true` or `false` 来代表是否拦截到消息. - -### `win.unhookWindowMessage(message)` _Windows_ - -* `message` Integer - -不拦截窗口消息. - -### `win.unhookAllWindowMessages()` _Windows_ - -窗口消息全部不拦截. - -### `win.setRepresentedFilename(filename)` _macOS_ - -* `filename` String - -设置窗口当前文件路径,并且将这个文件的图标放在窗口标题栏上. - -### `win.getRepresentedFilename()` _macOS_ - -获取窗口当前文件路径. - -### `win.setDocumentEdited(edited)` _macOS_ - -* `edited` Boolean - -明确指出窗口文档是否可以编辑,如果可以编辑则将标题栏的图标变成灰色. - -### `win.isDocumentEdited()` _macOS_ - -返回 boolean,当前窗口文档是否可编辑. - -### `win.focusOnWebView()` - -### `win.blurWebView()` - -### `win.capturePage([rect, ]callback)` - -* `rect` Object (可选) - 捕获Page位置 - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer -* `callback` Function - -捕获 `rect` 中的page 的快照.完成后将调用回调函数 `callback` 并返回 `image` . `image` 是存储了快照信息的[NativeImage](native-image.md)实例.如果不设置 `rect` 则将捕获所有可见page. - -### `win.loadURL(url[, options])` - -类似 `webContents.loadURL(url[, options])`. - -### `win.reload()` - -类似 `webContents.reload`. - -### `win.setMenu(menu)` _Linux_ _Windows_ - -* `menu` Menu - -设置菜单栏的 `menu` ,设置它为 `null` 则表示不设置菜单栏. - -### `win.setProgressBar(progress)` - -* `progress` Double - -在进度条中设置进度值,有效范围 [0, 1.0]. - -当进度小于0时则不显示进度; -当进度大于0时显示结果不确定. - -在libux上,只支持Unity桌面环境,需要指明 `*.desktop` 文件并且在 `package.json` 中添加文件名字.默认它为 `app.getName().desktop`. - -### `win.setOverlayIcon(overlay, description)` _Windows 7+_ - -* `overlay` [NativeImage](native-image.md) - 在底部任务栏右边显示图标. -* `description` String - 描述. - -向当前任务栏添加一个 16 x 16 像素的图标,通常用来覆盖一些应用的状态,或者直接来提示用户. - -### `win.setHasShadow(hasShadow)` _macOS_ - -* `hasShadow` (Boolean) - -设置窗口是否应该有阴影.在Windows和Linux系统无效. - -### `win.hasShadow()` _macOS_ - -返回 boolean,设置窗口是否有阴影.在Windows和Linux系统始终返回 -`true`. - -### `win.setThumbarButtons(buttons)` _Windows 7+_ - -* `buttons` Array - -在窗口的任务栏button布局出为缩略图添加一个有特殊button的缩略图工具栏. 返回一个 `Boolean` 对象来指示是否成功添加这个缩略图工具栏. - -因为空间有限,缩略图工具栏上的 button 数量不应该超过7个.一旦设置了,由于平台限制,就不能移动它了.但是你可使用一个空数组来调用api来清除 buttons . - -所有 `buttons` 是一个 `Button` 对象数组: - -* `Button` Object - * `icon` [NativeImage](native-image.md) - 在工具栏上显示的图标. - * `click` Function - * `tooltip` String (可选) - tooltip 文字. - * `flags` Array (可选) - 控制button的状态和行为. 默认它是 `['enabled']`. - -`flags` 是一个数组,它包含下面这些 `String`s: - -* `enabled` - button 为激活状态并且开放给用户. -* `disabled` -button 不可用. 目前它有一个可见的状态来表示它不会响应你的行为. -* `dismissonclick` - 点击button,这个缩略窗口直接关闭. -* `nobackground` - 不绘制边框,仅仅使用图像. -* `hidden` - button 对用户不可见. -* `noninteractive` - button 可用但是不可响应; 也不显示按下的状态. 它的值意味着这是一个在通知单使用 button 的实例. - -### `win.showDefinitionForSelection()` _macOS_ - -在界面查找选中文字时显示弹出字典. - -### `win.setAutoHideMenuBar(hide)` - -* `hide` Boolean - -设置窗口的菜单栏是否可以自动隐藏. 一旦设置了,只有当用户按下 `Alt` 键时则显示. - -如果菜单栏已经可见,调用 `setAutoHideMenuBar(true)` 则不会立刻隐藏. - -### `win.isMenuBarAutoHide()` - -返回 boolean,窗口的菜单栏是否可以自动隐藏. - -### `win.setMenuBarVisibility(visible)` - -* `visible` Boolean - -设置菜单栏是否可见.如果菜单栏自动隐藏,用户仍然可以按下 `Alt` 键来显示. - -### `win.isMenuBarVisible()` - -返回 boolean,菜单栏是否可见. - -### `win.setVisibleOnAllWorkspaces(visible)` - -* `visible` Boolean - -设置窗口是否在所有地方都可见. - -**注意:** 这个api 在windows无效. - -### `win.isVisibleOnAllWorkspaces()` - -返回 boolean,窗口是否在所有地方都可见. - -**注意:** 在 windows上始终返回 false. - -### `win.setIgnoreMouseEvents(ignore)` _macOS_ - -* `ignore` Boolean - -忽略窗口的所有鼠标事件. - -[blink-feature-string]: https://code.google.com/p/chromium/codesearch#chromium/src/out/Debug/gen/blink/platform/RuntimeEnabledFeatures.cpp&sq=package:chromium&type=cs&l=527 diff --git a/docs-translations/zh-CN/api/chrome-command-line-switches.md b/docs-translations/zh-CN/api/chrome-command-line-switches.md deleted file mode 100644 index 78b84b77276c9..0000000000000 --- a/docs-translations/zh-CN/api/chrome-command-line-switches.md +++ /dev/null @@ -1,140 +0,0 @@ -# 支持的 Chrome 命令行开关 - -这页列出了Chrome浏览器和Electron支持的命令行开关. 你也可以在[app][app]模块的[ready][ready]事件发出之前使用[app.commandLine.appendSwitch][append-switch] 来添加它们到你应用的main脚本里面: - -```javascript -const app = require('electron').app; -app.commandLine.appendSwitch('remote-debugging-port', '8315'); -app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1'); - -app.on('ready', function() { - // Your code here -}); -``` - -## --client-certificate=`path` - -设置客户端的证书文件 `path` . - -## --ignore-connections-limit=`domains` - -忽略用 `,` 分隔的 `domains` 列表的连接限制. - -## --disable-http-cache - -禁止请求 HTTP 时使用磁盘缓存. - -## --remote-debugging-port=`port` - -在指定的 `端口` 通过 HTTP 开启远程调试. - -## --js-flags=`flags` - -指定引擎过渡到 JS 引擎. - -在启动Electron时,如果你想在主进程中激活 `flags` ,它将被转换. - -```bash -$ electron --js-flags="--harmony_proxies --harmony_collections" your-app -``` - -## --proxy-server=`address:port` - -使用一个特定的代理服务器,它将比系统设置的优先级更高.这个开关只有在使用 HTTP 协议时有效,它包含 HTTPS 和 WebSocket 请求. 值得注意的是,不是所有的代理服务器都支持 HTTPS 和 WebSocket 请求. - -## --proxy-bypass-list=`hosts` - -让 Electron 使用(原文:bypass) 提供的以 semi-colon 分隔的hosts列表的代理服务器.这个开关只有在使用 `--proxy-server` 时有效. - -例如: - -```javascript -app.commandLine.appendSwitch('proxy-bypass-list', ';*.google.com;*foo.com;1.2.3.4:5678') -``` - - -将会为所有的hosts使用代理服务器,除了本地地址 (`localhost`, -`127.0.0.1` etc.), `google.com` 子域, 以 `foo.com` 结尾的hosts,和所有类似 `1.2.3.4:5678`的. - -## --proxy-pac-url=`url` - -在指定的 `url` 上使用 PAC 脚本. - -## --no-proxy-server - -不使用代理服务并且总是使用直接连接.忽略所有的合理代理标志. - -## --host-rules=`rules` - -一个逗号分隔的 `rule` 列表来控制主机名如何映射. - -例如: - -* `MAP * 127.0.0.1` 强制所有主机名映射到 127.0.0.1 -* `MAP *.google.com proxy` 强制所有 google.com 子域 使用 "proxy". -* `MAP test.com [::1]:77` 强制 "test.com" 使用 IPv6 回环地址. 也强制使用端口 77. -* `MAP * baz, EXCLUDE www.google.com` 重新全部映射到 "baz", 除了 - "www.google.com". - -这些映射适用于终端网络请求 -(TCP 连接 -和 主机解析 以直接连接的方式, 和 `CONNECT` 以代理连接, 还有 终端 host 使用 `SOCKS` 代理连接). - -## --host-resolver-rules=`rules` - -类似 `--host-rules` ,但是 `rules` 只适合主机解析. - -## --ignore-certificate-errors - -忽略与证书相关的错误. - -## --ppapi-flash-path=`path` - -设置Pepper Flash插件的路径 `path` . - -## --ppapi-flash-version=`version` - -设置Pepper Flash插件版本号. - -## --log-net-log=`path` - -使网络日志事件能够被读写到 `path`. - -## --ssl-version-fallback-min=`version` - -设置最简化的 SSL/TLS 版本号 ("tls1", "tls1.1" or "tls1.2"),TLS 可接受回退. - -## --cipher-suite-blacklist=`cipher_suites` - -指定逗号分隔的 SSL 密码套件 列表实效. - -## --disable-renderer-backgrounding - -防止 Chromium 降低隐藏的渲染进程优先级. - -这个标志对所有渲染进程全局有效,如果你只想在一个窗口中禁止使用,你可以采用 hack 方法[playing silent audio][play-silent-audio]. - -## --enable-logging - -打印 Chromium 信息输出到控制台. - -如果在用户应用加载完成之前解析`app.commandLine.appendSwitch` ,这个开关将实效,但是你可以设置 `ELECTRON_ENABLE_LOGGING` 环境变量来达到相同的效果. - -## --v=`log_level` - -设置默认最大活跃 V-logging 标准; 默认为 0.通常 V-logging 标准值为肯定值. - -这个开关只有在 `--enable-logging` 开启时有效. - -## --vmodule=`pattern` - -赋予每个模块最大的 V-logging levels 来覆盖 `--v` 给的值.E.g. `my_module=2,foo*=3` 会改变所有源文件 `my_module.*` and `foo*.*` 的代码中的 logging level . - -任何包含向前的(forward slash)或者向后的(backward slash)模式将被测试用于阻止整个路径名,并且不仅是E.g模块.`*/foo/bar/*=2` 将会改变所有在 `foo/bar` 下的源文件代码中的 logging level . - -这个开关只有在 `--enable-logging` 开启时有效. - -[app]: app.md -[append-switch]: app.md#appcommandlineappendswitchswitch-value -[ready]: app.md#event-ready -[play-silent-audio]: https://github.com/atom/atom/pull/9485/files diff --git a/docs-translations/zh-CN/api/clipboard.md b/docs-translations/zh-CN/api/clipboard.md deleted file mode 100644 index 2678bc5a34b90..0000000000000 --- a/docs-translations/zh-CN/api/clipboard.md +++ /dev/null @@ -1,117 +0,0 @@ -# clipboard - -`clipboard` 模块提供方法来供复制和粘贴操作 . -下面例子展示了如何将一个字符串写道 clipboard 上: - -```javascript -const clipboard = require('electron').clipboard; -clipboard.writeText('Example String'); -``` - -在 X Window 系统上, 有一个可选的 clipboard. 你可以为每个方法使用 `selection` 来控制它: - -```javascript -clipboard.writeText('Example String', 'selection'); -console.log(clipboard.readText('selection')); -``` - -## 方法 - -`clipboard` 模块有以下方法: - -**注意:** 测试 APIs 已经标明,并且在将来会被删除 . - -### `clipboard.readText([type])` - -* `type` String (可选) - -以纯文本形式从 clipboard 返回内容 . - -### `clipboard.writeText(text[, type])` - -* `text` String -* `type` String (可选) - -以纯文本形式向 clipboard 添加内容 . - -### `clipboard.readHTML([type])` - -* `type` String (可选) - -返回 clipboard 中的标记内容. - -### `clipboard.writeHTML(markup[, type])` - -* `markup` String -* `type` String (可选) - -向 clipboard 添加 `markup` 内容 . - -### `clipboard.readImage([type])` - -* `type` String (可选) - -从 clipboard 中返回 [NativeImage](native-image.md) 内容. - -### `clipboard.writeImage(image[, type])` - -* `image` [NativeImage](native-image.md) -* `type` String (可选) - -向 clipboard 中写入 `image` . - -### `clipboard.readRTF([type])` - -* `type` String (可选) - -从 clipboard 中返回 RTF 内容. - -### `clipboard.writeRTF(text[, type])` - -* `text` String -* `type` String (可选) - -向 clipboard 中写入 RTF 格式的 `text` . - -### `clipboard.clear([type])` - -* `type` String (可选) - -清空 clipboard 内容. - -### `clipboard.availableFormats([type])` - -* `type` String (可选) - -返回 clipboard 支持的格式数组 . - -### `clipboard.has(data[, type])` _Experimental_ - -* `data` String -* `type` String (可选) - -返回 clipboard 是否支持指定 `data` 的格式. - -```javascript -console.log(clipboard.has('

selection

')); -``` - -### `clipboard.read(data[, type])` _Experimental_ - -* `data` String -* `type` String (可选) - -读取 clipboard 的 `data`. - -### `clipboard.write(data[, type])` - -* `data` Object - * `text` String - * `html` String - * `image` [NativeImage](native-image.md) -* `type` String (可选) - -```javascript -clipboard.write({text: 'test', html: "test"}); -``` -向 clipboard 写入 `data` . \ No newline at end of file diff --git a/docs-translations/zh-CN/api/content-tracing.md b/docs-translations/zh-CN/api/content-tracing.md deleted file mode 100644 index fd1edc9bc2f09..0000000000000 --- a/docs-translations/zh-CN/api/content-tracing.md +++ /dev/null @@ -1,129 +0,0 @@ -# contentTracing - -`content-tracing` 模块是用来收集由底层的Chromium content 模块 产生的搜索数据. 这个模块不具备web接口,所有需要我们在chrome浏览器中添加 `chrome://tracing/` 来加载生成文件从而查看结果. - -```javascript -const contentTracing = require('electron').contentTracing; - -const options = { - categoryFilter: '*', - traceOptions: 'record-until-full,enable-sampling' -} - -contentTracing.startRecording(options, function() { - console.log('Tracing started'); - - setTimeout(function() { - contentTracing.stopRecording('', function(path) { - console.log('Tracing data recorded to ' + path); - }); - }, 5000); -}); -``` - -## 方法 - - `content-tracing` 模块的方法如下: - -### `contentTracing.getCategories(callback)` - -* `callback` Function - -获得一组分类组. 分类组可以更改为新的代码路径。 - -一旦所有的子进程都接受到了`getCategories`方法请求, 分类组将调用 `callback`. - -### `contentTracing.startRecording(options, callback)` - -* `options` Object - * `categoryFilter` String - * `traceOptions` String -* `callback` Function - -开始向所有进程进行记录.(recording) - -一旦收到可以开始记录的请求,记录将会立马启动并且在子进程是异步记录听的. 当所有的子进程都收到 `startRecording` 请求的时候,`callback` 将会被调用. - -`categoryFilter`是一个过滤器,它用来控制那些分类组应该被用来查找.过滤器应当有一个可选的 `-` 前缀来排除匹配的分类组.不允许同一个列表既是包含又是排斥. - -例子: - -* `test_MyTest*`, -* `test_MyTest*,test_OtherStuff`, -* `"-excluded_category1,-excluded_category2` - -`traceOptions` 控制着哪种查找应该被启动,这是一个用逗号分隔的列表.可用参数如下: - -* `record-until-full` -* `record-continuously` -* `trace-to-console` -* `enable-sampling` -* `enable-systrace` - -前3个参数是来查找记录模块,并且以后都互斥.如果在`traceOptions` 中超过一个跟踪 -记录模式,那最后一个的优先级最高.如果没有指明跟踪 -记录模式,那么它默认为 `record-until-full`. - -在 `traceOptions` 中的参数被解析应用之前,查找参数初始化默认为 (`record_mode` 设置为 -`record-until-full`, `enable_sampling` 和 `enable_systrace` 设置为 `false`). - -### `contentTracing.stopRecording(resultFilePath, callback)` - -* `resultFilePath` String -* `callback` Function - -停止对所有子进程的记录. - -子进程通常缓存查找数据,并且仅仅将数据截取和发送给主进程.这有利于在通过 IPC 发送查找数据之前减小查找时的运行开销,这样做很有价值.因此,发送查找数据,我们应当异步通知所有子进程来截取任何待查找的数据. - -一旦所有子进程接收到了 `stopRecording` 请求,将调用 `callback` ,并且返回一个包含查找数据的文件. - -如果 `resultFilePath` 不为空,那么将把查找数据写入其中,否则写入一个临时文件.实际文件路径如果不为空,则将调用 `callback` . - -### `contentTracing.startMonitoring(options, callback)` - -* `options` Object - * `categoryFilter` String - * `traceOptions` String -* `callback` Function - -开始向所有进程进行监听.(monitoring) - -一旦收到可以开始监听的请求,记录将会立马启动并且在子进程是异步记监听的. 当所有的子进程都收到 `startMonitoring` 请求的时候,`callback` 将会被调用. - -### `contentTracing.stopMonitoring(callback)` - -* `callback` Function - -停止对所有子进程的监听. - -一旦所有子进程接收到了 `stopMonitoring` 请求,将调用 `callback` . - -### `contentTracing.captureMonitoringSnapshot(resultFilePath, callback)` - -* `resultFilePath` String -* `callback` Function - -获取当前监听的查找数据. - -子进程通常缓存查找数据,并且仅仅将数据截取和发送给主进程.因为如果直接通过 IPC 来发送查找数据的代价昂贵,我们宁愿避免不必要的查找运行开销.因此,为了停止查找,我们应当异步通知所有子进程来截取任何待查找的数据. - -一旦所有子进程接收到了 `captureMonitoringSnapshot` 请求,将调用 `callback` ,并且返回一个包含查找数据的文件. - -### `contentTracing.getTraceBufferUsage(callback)` - -* `callback` Function - -通过查找 buffer 进程来获取百分比最大使用量.当确定了TraceBufferUsage 的值确定的时候,就调用 `callback` . - -### `contentTracing.setWatchEvent(categoryName, eventName, callback)` - -* `categoryName` String -* `eventName` String -* `callback` Function - -任意时刻在任何进程上指定事件发生时将调用 `callback` . - -### `contentTracing.cancelWatchEvent()` - -取消 watch 事件. 如果启动查找,这或许会造成 watch 事件的回调函数 出错. \ No newline at end of file diff --git a/docs-translations/zh-CN/api/crash-reporter.md b/docs-translations/zh-CN/api/crash-reporter.md deleted file mode 100644 index f8422bf454cfd..0000000000000 --- a/docs-translations/zh-CN/api/crash-reporter.md +++ /dev/null @@ -1,66 +0,0 @@ -# crashReporter - -`crash-reporter` 模块开启发送应用崩溃报告. - -下面是一个自动提交崩溃报告给服务器的例子 : - -```javascript -const crashReporter = require('electron').crashReporter; - -crashReporter.start({ - productName: 'YourName', - companyName: 'YourCompany', - submitURL: 'https://your-domain.com/url-to-submit', - autoSubmit: true -}); -``` - -可以使用下面的项目来创建一个服务器,用来接收和处理崩溃报告 : - -* [socorro](https://github.com/mozilla/socorro) -* [mini-breakpad-server](https://github.com/atom/mini-breakpad-server) - -## 方法 - -`crash-reporter` 模块有如下方法: - -### `crashReporter.start(options)` - -* `options` Object - * `companyName` String - * `submitURL` String - 崩溃报告发送的路径,以post方式. - * `productName` String (可选) - 默认为 `Electron`. - * `autoSubmit` Boolean - 是否自动提交. - 默认为 `true`. - * `ignoreSystemCrashHandler` Boolean - 默认为 `false`. - * `extra` Object - 一个你可以定义的对象,附带在崩溃报告上一起发送 . 只有字符串属性可以被正确发送,不支持嵌套对象. - -只可以在使用其它 `crashReporter` APIs 之前使用这个方法. - -**注意:** 在 macOS, Electron 使用一个新的 `crashpad` 客户端, 与 Windows 和 Linux 的 `breakpad` 不同. 为了开启崩溃点搜集,你需要在主进程和其它每个你需要搜集崩溃报告的渲染进程中调用 `crashReporter.start` API 来初始化 `crashpad`. - -### `crashReporter.getLastCrashReport()` - -返回最后一个崩溃报告的日期和 ID.如果没有过崩溃报告发送过来,或者还没有开始崩溃报告搜集,将返回 `null` . - -### `crashReporter.getUploadedReports()` - -返回所有上载的崩溃报告,每个报告包含了上载日期和 ID. - -## crash-reporter Payload - -崩溃报告将发送下面 `multipart/form-data` `POST` 型的数据给 `submitURL` : - -* `ver` String - Electron 版本. -* `platform` String - 例如 'win32'. -* `process_type` String - 例如 'renderer'. -* `guid` String - 例如 '5e1286fc-da97-479e-918b-6bfb0c3d1c72' -* `_version` String - `package.json` 版本. -* `_productName` String - `crashReporter` `options` - 对象中的产品名字. -* `prod` String - 基础产品名字. 这种情况为 Electron. -* `_companyName` String - `crashReporter` `options` - 对象中的公司名字. -* `upload_file_minidump` File - 崩溃报告按照 `minidump` 的格式. -* `crashReporter` 中的 `extra` 对象的所有等级和一个属性. - `options` object \ No newline at end of file diff --git a/docs-translations/zh-CN/api/desktop-capturer.md b/docs-translations/zh-CN/api/desktop-capturer.md deleted file mode 100644 index 954520d05eaa4..0000000000000 --- a/docs-translations/zh-CN/api/desktop-capturer.md +++ /dev/null @@ -1,64 +0,0 @@ -# desktopCapturer - -`desktopCapturer` 模块可用来获取可用资源,这个资源可通过 `getUserMedia` 捕获得到. - -```javascript -// 在渲染进程中. -var desktopCapturer = require('electron').desktopCapturer; - -desktopCapturer.getSources({types: ['window', 'screen']}, function(error, sources) { - if (error) throw error; - for (var i = 0; i < sources.length; ++i) { - if (sources[i].name == "Electron") { - navigator.webkitGetUserMedia({ - audio: false, - video: { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: sources[i].id, - minWidth: 1280, - maxWidth: 1280, - minHeight: 720, - maxHeight: 720 - } - } - }, gotStream, getUserMediaError); - return; - } - } -}); - -function gotStream(stream) { - document.querySelector('video').src = URL.createObjectURL(stream); -} - -function getUserMediaError(e) { - console.log('getUserMediaError'); -} -``` - -当调用 `navigator.webkitGetUserMedia` 时创建一个约束对象,如果使用 `desktopCapturer` 的资源,必须设置 `chromeMediaSource` 为 `"desktop"` ,并且 `audio` 为 `false`. - -如果你想捕获整个桌面的 audio 和 video,你可以设置 `chromeMediaSource` 为 `"screen"` ,和 `audio` 为 `true`. -当使用这个方法的时候,不可以指定一个 `chromeMediaSourceId`. - -## 方法 - -`desktopCapturer` 模块有如下方法: - -### `desktopCapturer.getSources(options, callback)` - -* `options` Object - * `types` Array - 一个 String 数组,列出了可以捕获的桌面资源类型, 可用类型为 `screen` 和 `window`. - * `thumbnailSize` Object (可选) - 建议缩略可被缩放的 size, 默认为 `{width: 150, height: 150}`. -* `callback` Function - -发起一个请求,获取所有桌面资源,当请求完成的时候使用 `callback(error, sources)` 调用 `callback` . - -`sources` 是一个 `Source` 对象数组, 每个 `Source` 表示了一个捕获的屏幕或单独窗口,并且有如下属性 : -* `id` String - 在 `navigator.webkitGetUserMedia` 中使用的捕获窗口或屏幕的 id . 格式为 `window:XX` 祸 - `screen:XX`,`XX` 是一个随机数. -* `name` String - 捕获窗口或屏幕的描述名 . 如果资源为屏幕,名字为 `Entire Screen` 或 `Screen `; 如果资源为窗口, 名字为窗口的标题. -* `thumbnail` [NativeImage](NativeImage.md) - 缩略图. - -**注意:** 不能保证 `source.thumbnail` 的 size 和 `options` 中的 `thumnbailSize` 一直一致. 它也取决于屏幕或窗口的缩放比例. \ No newline at end of file diff --git a/docs-translations/zh-CN/api/dialog.md b/docs-translations/zh-CN/api/dialog.md deleted file mode 100644 index dd691fa6469d1..0000000000000 --- a/docs-translations/zh-CN/api/dialog.md +++ /dev/null @@ -1,94 +0,0 @@ -# dialog - -`dialog` 模块提供了api来展示原生的系统对话框,例如打开文件框,alert框,所以web应用可以给用户带来跟系统应用相同的体验. - -对话框例子,展示了选择文件和目录: - -```javascript -var win = ...; // BrowserWindow in which to show the dialog -const dialog = require('electron').dialog; -console.log(dialog.showOpenDialog({ properties: [ 'openFile', 'openDirectory', 'multiSelections' ]})); -``` - -**macOS 上的注意事项**: 如果你想像sheets一样展示对话框,只需要在`browserWindow` 参数中提供一个 `BrowserWindow` 的引用对象. - -## 方法 - -`dialog` 模块有以下方法: - -### `dialog.showOpenDialog([browserWindow, ]options[, callback])` - -* `browserWindow` BrowserWindow (可选) -* `options` Object - * `title` String - * `defaultPath` String - * `filters` Array - * `properties` Array - 包含了对话框的特性值, 可以包含 `openFile`, `openDirectory`, `multiSelections` and - `createDirectory` -* `callback` Function (可选) - -成功使用这个方法的话,就返回一个可供用户选择的文件路径数组,失败返回 `undefined`. - -`filters` 当需要限定用户的行为的时候,指定一个文件数组给用户展示或选择. 例如: - -```javascript -{ - filters: [ - { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, - { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] }, - { name: 'Custom File Type', extensions: ['as'] }, - { name: 'All Files', extensions: ['*'] } - ] -} -``` - -`extensions` 数组应当只包含扩展名,不应该包含通配符或'.'号 (例如 -`'png'` 正确,但是 `'.png'` 和 `'*.png'` 不正确). 展示全部文件的话, 使用 -`'*'` 通配符 (不支持其他通配符). - -如果 `callback` 被调用, 将异步调用 API ,并且结果将用过 `callback(filenames)` 展示. - -**注意:** 在 Windows 和 Linux ,一个打开的 dialog 不能既是文件选择框又是目录选择框, 所以如果在这些平台上设置 `properties` 的值为 -`['openFile', 'openDirectory']` , 将展示一个目录选择框. - -### `dialog.showSaveDialog([browserWindow, ]options[, callback])` - -* `browserWindow` BrowserWindow (可选) -* `options` Object - * `title` String - * `defaultPath` String - * `filters` Array -* `callback` Function (可选) - -成功使用这个方法的话,就返回一个可供用户选择的文件路径数组,失败返回 `undefined`. - -`filters` 指定展示一个文件类型数组, 例子 -`dialog.showOpenDialog` . - -如果 `callback` 被调用, 将异步调用 API ,并且结果将用过 `callback(filenames)` 展示. - -### `dialog.showMessageBox([browserWindow, ]options[, callback])` - -* `browserWindow` BrowserWindow (可选) -* `options` Object - * `type` String - 可以是 `"none"`, `"info"`, `"error"`, `"question"` 或 - `"warning"`. 在 Windows, "question" 与 "info" 展示图标相同, 除非你使用 "icon" 参数. - * `buttons` Array - buttons 内容,数组. - * `defaultId` Integer - 在message box 对话框打开的时候,设置默认button选中,值为在 buttons 数组中的button索引. - * `title` String - message box 的标题,一些平台不显示. - * `message` String - message box 内容. - * `detail` String - 额外信息. - * `icon` [NativeImage](native-image.md) - * `cancelId` Integer - 当用户关闭对话框的时候,不是通过点击对话框的button,就返回值.默认值为对应 "cancel" 或 "no" 标签button 的索引值, 或者如果没有这种button,就返回0. 在 macOS 和 Windows 上, "Cancel" button 的索引值将一直是 `cancelId`, 不管之前是不是特别指出的. - * `noLink` Boolean - 在 Windows ,Electron 将尝试识别哪个button 是普通 button (如 "Cancel" 或 "Yes"), 然后再对话框中以链接命令(command links)方式展现其它的 button . 这能让对话框展示得很炫酷.如果你不喜欢这种效果,你可以设置 `noLink` 为 `true`. -* `callback` Function - -展示 message box, 它会阻塞进程,直到 message box 关闭为止.返回点击按钮的索引值. - -如果 `callback` 被调用, 将异步调用 API ,并且结果将用过 `callback(response)` 展示. - -### `dialog.showErrorBox(title, content)` - -展示一个传统的包含错误信息的对话框. - -在 `app` 模块触发 `ready` 事件之前,这个 api 可以被安全调用,通常它被用来在启动的早期阶段报告错误. 在 Linux 上,如果在 `app` 模块触发 `ready` 事件之前调用,message 将会被触发显示stderr,并且没有实际GUI 框显示. \ No newline at end of file diff --git a/docs-translations/zh-CN/api/download-item.md b/docs-translations/zh-CN/api/download-item.md deleted file mode 100644 index e869e8f305704..0000000000000 --- a/docs-translations/zh-CN/api/download-item.md +++ /dev/null @@ -1,96 +0,0 @@ -# DownloadItem - -`DownloadItem`(下载项)是一个在Electron中展示下载项的 -[EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter)。 -它被用于`Session`模块中的`will-download`事件,允许用户去控制下载项。 - -```javascript -// In the main process. -win.webContents.session.on('will-download', function(event, item, webContents) { - // Set the save path, making Electron not to prompt a save dialog. - item.setSavePath('/tmp/save.pdf'); - console.log(item.getMimeType()); - console.log(item.getFilename()); - console.log(item.getTotalBytes()); - item.on('updated', function() { - console.log('Received bytes: ' + item.getReceivedBytes()); - }); - item.on('done', function(e, state) { - if (state == "completed") { - console.log("Download successfully"); - } else { - console.log("Download is cancelled or interrupted that can't be resumed"); - } - }); -``` - -## 事件 - -### 事件: 'updated' - -当`downloadItem`获得更新时发射。 - -### 事件: 'done' - -* `event` Event -* `state` String - * `completed` - 下载成功完成。 - * `cancelled` - 下载被取消。 - * `interrupted` - 与文件服务器错误的中断连接。 - -当下载处于一个终止状态时发射。这包括了一个完成的下载,一个被取消的下载(via `downloadItem.cancel()`), -和一个被意外中断的下载(无法恢复)。 - -## 方法 - -`downloadItem`对象有以下一些方法: - -### `downloadItem.setSavePath(path)` - -* `path` String - 设置下载项的保存文件路径. - -这个API仅仅在`session`的`will-download`回调函数中可用。 -如果用户没有这个API去设置保存路径,Electron会用原始程序去确定保存路径(通常提示一个保存对话框)。 - -### `downloadItem.pause()` - -暂停下载。 - -### `downloadItem.resume()` - -恢复被暂停的下载。 - -### `downloadItem.cancel()` - -取消下载操作。 - -### `downloadItem.getURL()` - -以`String`形式返回一个该下载项的下载源url。 - -### `downloadItem.getMimeType()` - -返回一个表示mime类型的`String`。 - -### `downloadItem.hasUserGesture()` - -返回一个`Boolean`表示下载是否有用户动作。 - -### `downloadItem.getFilename()` - -返回一个表示下载项文件名的`String`。 - -**Note:** 此文件名不一定总是保存在本地硬盘上的实际文件名。 -如果用户在下载保存对话框中修改了文件名,保存的文件的实际名称会与`downloadItem.getFilename()`方法返回的文件名不同。 - -### `downloadItem.getTotalBytes()` - -返回一个表示下载项总字节数大小的`Integer`。如果大小未知,返回0。 - -### `downloadItem.getReceivedBytes()` - -返回一个表示下载项已经接收的字节数大小的`Integer`。 - -### `downloadItem.getContentDisposition()` - -以`String`形式返回响应头(response header)中的`Content-Disposition`域。 diff --git a/docs-translations/zh-CN/api/environment-variables.md b/docs-translations/zh-CN/api/environment-variables.md deleted file mode 100644 index 0a35eb59dfdbe..0000000000000 --- a/docs-translations/zh-CN/api/environment-variables.md +++ /dev/null @@ -1,53 +0,0 @@ -# 环境变量 - -一些 Electron 的行为受到环境变量的控制,因为他们的初始化比命令行和应用代码更早. - -POSIX shells 的例子: - -```bash -$ export ELECTRON_ENABLE_LOGGING=true -$ electron -``` - -Windows 控制台: - -```powershell -> set ELECTRON_ENABLE_LOGGING=true -> electron -``` - -## `ELECTRON_RUN_AS_NODE` - -类似node.js普通进程启动方式. - -## `ELECTRON_ENABLE_LOGGING` - -打印 Chrome 的内部日志到控制台. - -## `ELECTRON_LOG_ASAR_READS` - -当 Electron 读取 ASA 文档,把 read offset 和文档路径做日志记录到系统 `tmpdir`.结果文件将提供给 ASAR 模块来优化文档组织. - -## `ELECTRON_ENABLE_STACK_DUMPING` - -当 Electron 崩溃的时候,打印堆栈记录到控制台. - -如果 `crashReporter` 已经启动那么这个环境变量实效. - -## `ELECTRON_DEFAULT_ERROR_MODE` _Windows_ - -当 Electron 崩溃的时候,显示windows的崩溃对话框. - -如果 `crashReporter` 已经启动那么这个环境变量实效. - -## `ELECTRON_NO_ATTACH_CONSOLE` _Windows_ - -不可使用当前控制台. - -## `ELECTRON_FORCE_WINDOW_MENU_BAR` _Linux_ - -不可再 Linux 上使用全局菜单栏. - -## `ELECTRON_HIDE_INTERNAL_MODULES` - -关闭旧的内置模块如 `require('ipc')` 的通用模块. \ No newline at end of file diff --git a/docs-translations/zh-CN/api/file-object.md b/docs-translations/zh-CN/api/file-object.md deleted file mode 100644 index ef320b36994e2..0000000000000 --- a/docs-translations/zh-CN/api/file-object.md +++ /dev/null @@ -1,29 +0,0 @@ -# `File`对象 - -为了让用户能够通过HTML5的file API直接操作本地文件,DOM的File接口提供了对本地文件的抽象。Electron在File接口中增加了一个path属性,它是文件在系统中的真实路径。 - ---- - -获取拖动到APP中文件的真实路径的例子: - -``` -
- Drag your file here -
- - -``` diff --git a/docs-translations/zh-CN/api/frameless-window.md b/docs-translations/zh-CN/api/frameless-window.md deleted file mode 100644 index eb9a889263c3d..0000000000000 --- a/docs-translations/zh-CN/api/frameless-window.md +++ /dev/null @@ -1,87 +0,0 @@ -# Frameless Window - -无边框窗口指的是不包含除页面本身以外任何其它可视部分的窗口([chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome))。 -像工具栏,是窗口的一部分,但并不属于页面。这些是[`BrowserWindow`](browser-window.md) 类的选项。 - -## 创建无边框窗口 - -为了创建一个无边框窗口,你需要设置[BrowserWindow](browser-window.md)的`frame`为`false`: - - - -```javascript -const BrowserWindow = require('electron').BrowserWindow; -var win = new BrowserWindow({ width: 800, height: 600, frame: false }); -``` - -### macOS上的替代方案 - -在macOS 10.10 Yosemite或者更新的版本中,有一个替代方案去生成一个无边框窗口。 -不同于设置`frame`为`false`会隐藏标题栏以及失去对窗口的控制,你可能想隐藏标题栏使你的页面内容显示在整个窗口上 -,同时又想保持对窗口的控制("traffic lights")。你可以通过指定`titleBarStyle`这一新选项达到目标: - -```javascript -var win = new BrowserWindow({ 'titleBarStyle': 'hidden' }); -``` - -## 透明窗口 - -通过设置`transparent` 选项为 `true`,你能使无边框窗口透明: - -```javascript -var win = new BrowserWindow({ transparent: true, frame: false }); -``` - -### 限制 - -* 你无法点击透明的区域。我们正在采用一个新的API去设置窗口的外形以解决这个问题, - 详见[our issue](https://github.com/electron/electron/issues/1335)。 -* 透明窗口是不可调整大小的。在某些平台上,设置`resizable`为`true`也许会造成这个透明窗口停止工作。 -* `blur`滤光器器只适用于网页,所以没法将模糊效果用于窗口之下(i.e. 其它在用户的系统中打开的应用)。 -* 在Windows系统中,当DWM被禁用时透明窗口不会工作。 -* Linux用户需要在命令行中输入`--enable-transparent-visuals --disable-gpu` - 去禁用GPU以及允许ARGB去渲染透明窗口,这是由于一个Linux上的上游bug[alpha channel doesn't work on some - NVidia drivers](https://code.google.com/p/chromium/issues/detail?id=369209)造成的 -* 在Mac上,透明窗口的阴影不会显示出来. - -## 可拖动区域 - -默认情况下,无边框窗口是不可拖动的。应用在CSS中设置`-webkit-app-region: drag` -告诉Electron哪个区域是可拖动的(比如系统标准的标题栏),应用也可以设置`-webkit-app-region: no-drag` -在可拖动区域中排除不可拖动的区域。需要注意的是,目前只支持矩形区域。 - -为了让整个窗口可拖动,你可以在`body`的样式中添加`-webkit-app-region: drag`: - -```html - - -``` - -另外需要注意的是,如果你设置了整个窗口可拖动,你必须标记按钮为不可拖动的(non-draggable), -否则用户不能点击它们: - -```css -button { - -webkit-app-region: no-drag; -} -``` - -如果你设置一个自定义的标题栏可拖动,你同样需要设置标题栏中所有的按钮为不可拖动(non-draggable)。 - -## 文本选择 - -在一个无边框窗口中,拖动动作会与文本选择发生冲突。比如,当你拖动标题栏,偶尔会选中标题栏上的文本。 -为了防止这种情况发生,你需要向下面这样在一个可拖动区域中禁用文本选择: - -```css -.titlebar { - -webkit-user-select: none; - -webkit-app-region: drag; -} -``` - -## 上下文菜单 - -在一些平台上,可拖动区域会被认为是非客户端框架(non-client frame),所有当你点击右键时,一个系统菜单会弹出。 -为了保证上下文菜单在所有平台下正确的显示,你不应该在可拖动区域使用自定义上下文菜单。 - diff --git a/docs-translations/zh-CN/api/global-shortcut.md b/docs-translations/zh-CN/api/global-shortcut.md deleted file mode 100644 index ff0b28832a10d..0000000000000 --- a/docs-translations/zh-CN/api/global-shortcut.md +++ /dev/null @@ -1,60 +0,0 @@ -# global-shortcut - -`global-shortcut` 模块可以便捷的为您设置(注册/注销)各种自定义操作的快捷键. - -**Note**: 使用此模块注册的快捷键是系统全局的(QQ截图那种), 不要在应用模块(app module)响应 `ready` -消息前使用此模块(注册快捷键). - -```javascript -var app = require('app'); -var globalShortcut = require('global-shortcut'); - -app.on('ready', function() { - // Register a 'ctrl+x' shortcut listener. - var ret = globalShortcut.register('ctrl+x', function() { - console.log('ctrl+x is pressed'); - }) - - if (!ret) { - console.log('registration failed'); - } - - // Check whether a shortcut is registered. - console.log(globalShortcut.isRegistered('ctrl+x')); -}); - -app.on('will-quit', function() { - // Unregister a shortcut. - globalShortcut.unregister('ctrl+x'); - - // Unregister all shortcuts. - globalShortcut.unregisterAll(); -}); -``` - -## Methods - -`global-shortcut` 模块包含以下函数: - -### `globalShortcut.register(accelerator, callback)` - -* `accelerator` [Accelerator](accelerator.md) -* `callback` Function - -注册 `accelerator` 快捷键. 当用户按下注册的快捷键时将会调用 `callback` 函数. - -### `globalShortcut.isRegistered(accelerator)` - -* `accelerator` [Accelerator](accelerator.md) - -查询 `accelerator` 快捷键是否已经被注册过了,将会返回 `true`(已被注册) 或 `false`(未注册). - -### `globalShortcut.unregister(accelerator)` - -* `accelerator` [Accelerator](accelerator.md) - -注销全局快捷键 `accelerator`. - -### `globalShortcut.unregisterAll()` - -注销本应用注册的所有全局快捷键. diff --git a/docs-translations/zh-CN/api/ipc-main-process.md b/docs-translations/zh-CN/api/ipc-main-process.md deleted file mode 100644 index 75d5785b2e5f1..0000000000000 --- a/docs-translations/zh-CN/api/ipc-main-process.md +++ /dev/null @@ -1,68 +0,0 @@ -# ipc (主进程) - -在主进程使用`ipc`模块时,`ipc`负责捕获从渲染进程(网页)发送的同步或者是异步消息. - -## 发送消息 - -主进程也可以向渲染进程发送信息,具体可以看[WebContents.send](web-contents.md#webcontentssendchannel-args). - -- 当发送消息的时候,事件名字为`channel`. -- 回复一个同步消息的时候,你需要使用`event.returnValue` -- 回复一个异步消息的时候,使用`event.sender.send(...)` - -下面是一个主进程和渲染进程的通信例子. - -```javascript -// 在主进程中. -var ipc = require('ipc'); -ipc.on('asynchronous-message', function(event, arg) { - console.log(arg); // 打印 "ping" - event.sender.send('asynchronous-reply', 'pong'); -}); - -ipc.on('synchronous-message', function(event, arg) { - console.log(arg); // 打印 "ping" - event.returnValue = 'pong'; -}); -``` - -```javascript -// 在渲染进程(网页). -var ipc = require('ipc'); -console.log(ipc.sendSync('synchronous-message', 'ping')); // 打印 "pong" - -ipc.on('asynchronous-reply', function(arg) { - console.log(arg); // 打印 "pong" -}); -ipc.send('asynchronous-message', 'ping'); -``` - -## 监听消息 - -`ipc`模块有下列几种方法来监听事件. - -### `ipc.on(channel, callback)` - -* `channel` - 事件名称. -* `callback` - 回调函数. - -当事件发生的时候,会传入`callback` `event`和`arg`参数. - -## IPC 事件 - -传入`callback`的`event`对象含有下列方法. - -### `Event.returnValue` - -在同步消息中,设置这个值将会被返回. - -### `Event.sender` - -返回一个可以发送消息的`WebContents`. - -### `Event.sender.send(channel[.arg1][,arg2][,...])` - -* `channel` - 事件名称. -* `arg` (选用) - -这个可以发送一个可带参数的异步消息回渲染进程. diff --git a/docs-translations/zh-CN/api/ipc-main.md b/docs-translations/zh-CN/api/ipc-main.md deleted file mode 100644 index aef9c454a067c..0000000000000 --- a/docs-translations/zh-CN/api/ipc-main.md +++ /dev/null @@ -1,85 +0,0 @@ -# ipcMain - -`ipcMain` 模块是类 -[EventEmitter](https://nodejs.org/api/events.html) 的实例.当在主进程中使用它的时候,它控制着由渲染进程(web page)发送过来的异步或同步消息.从渲染进程发送过来的消息将触发事件. - -## 发送消息 - -同样也可以从主进程向渲染进程发送消息,查看更多 [webContents.send][web-contents-send] . - -* 发送消息,事件名为 `channel`. -* 回应同步消息, 你可以设置 `event.returnValue`. -* 回应异步消息, 你可以使用 - `event.sender.send(...)`. - -一个例子,在主进程和渲染进程之间发送和处理消息: - -```javascript -// In main process. -const ipcMain = require('electron').ipcMain; -ipcMain.on('asynchronous-message', function(event, arg) { - console.log(arg); // prints "ping" - event.sender.send('asynchronous-reply', 'pong'); -}); - -ipcMain.on('synchronous-message', function(event, arg) { - console.log(arg); // prints "ping" - event.returnValue = 'pong'; -}); -``` - -```javascript -// In renderer process (web page). -const ipcRenderer = require('electron').ipcRenderer; -console.log(ipcRenderer.sendSync('synchronous-message', 'ping')); // prints "pong" - -ipcRenderer.on('asynchronous-reply', function(event, arg) { - console.log(arg); // prints "pong" -}); -ipcRenderer.send('asynchronous-message', 'ping'); -``` - -## 监听消息 - -`ipcMain` 模块有如下监听事件方法: - -### `ipcMain.on(channel, listener)` - -* `channel` String -* `listener` Function - -监听 `channel`, 当新消息到达,将通过 `listener(event, args...)` 调用 `listener`. - -### `ipcMain.once(channel, listener)` - -* `channel` String -* `listener` Function - -为事件添加一个一次性用的`listener` 函数.这个 `listener` 只有在下次的消息到达 `channel` 时被请求调用,之后就被删除了. - -### `ipcMain.removeListener(channel, listener)` - -* `channel` String -* `listener` Function - -为特定的 `channel` 从监听队列中删除特定的 `listener` 监听者. - -### `ipcMain.removeAllListeners([channel])` - -* `channel` String (可选) - -删除所有监听者,或特指的 `channel` 的所有监听者. - -## 事件对象 - -传递给 `callback` 的 `event` 对象有如下方法: - -### `event.returnValue` - -将此设置为在一个同步消息中返回的值. - -### `event.sender` - -返回发送消息的 `webContents` ,你可以调用 `event.sender.send` 来回复异步消息,更多信息 [webContents.send][web-contents-send]. - -[web-contents-send]: web-contents.md#webcontentssendchannel-arg1-arg2- \ No newline at end of file diff --git a/docs-translations/zh-CN/api/ipc-renderer.md b/docs-translations/zh-CN/api/ipc-renderer.md deleted file mode 100644 index beeaa6d762324..0000000000000 --- a/docs-translations/zh-CN/api/ipc-renderer.md +++ /dev/null @@ -1,69 +0,0 @@ -# ipcRenderer - -`ipcRenderer` 模块是一个 -[EventEmitter](https://nodejs.org/api/events.html) 类的实例. 它提供了有限的方法,你可以从渲染进程向主进程发送同步或异步消息. 也可以收到主进程的相应. - -查看 [ipcMain](ipc-main.md) 代码例子. - -## 消息监听 - -`ipcRenderer` 模块有下列方法来监听事件: - -### `ipcRenderer.on(channel, listener)` - -* `channel` String -* `listener` Function - -监听 `channel`, 当有新消息到达,使用 `listener(event, args...)` 调用 `listener` . - -### `ipcRenderer.once(channel, listener)` - -* `channel` String -* `listener` Function - -为这个事件添加一个一次性 `listener` 函数.这个 `listener` 将在下一次有新消息被发送到 `channel` 的时候被请求调用,之后就被删除了. - -### `ipcRenderer.removeListener(channel, listener)` - -* `channel` String -* `listener` Function - -从指定的 `channel` 中的监听者数组删除指定的 `listener` . - -### `ipcRenderer.removeAllListeners([channel])` - -* `channel` String (optional) - -删除所有的监听者,或者删除指定 `channel` 中的全部. - -## 发送消息 - -`ipcRenderer` 模块有如下方法来发送消息: - -### `ipcRenderer.send(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (可选) - -通过 `channel` 向主进程发送异步消息,也可以发送任意参数.参数会被JSON序列化,之后就不会包含函数或原型链. - -主进程通过使用 `ipcMain` 模块来监听 `channel`,从而处理消息. - -### `ipcRenderer.sendSync(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (可选) - -通过 `channel` 向主进程发送同步消息,也可以发送任意参数.参数会被JSON序列化,之后就不会包含函数或原型链. - -主进程通过使用 `ipcMain` 模块来监听 `channel`,从而处理消息, -通过 `event.returnValue` 来响应. - -__注意:__ 发送同步消息将会阻塞整个渲染进程,除非你知道你在做什么,否则就永远不要用它 . - -### `ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (可选) - -类似 `ipcRenderer.send` ,但是它的事件将发往 host page 的 `` 元素,而不是主进程. \ No newline at end of file diff --git a/docs-translations/zh-CN/api/menu-item.md b/docs-translations/zh-CN/api/menu-item.md deleted file mode 100644 index 6d5d59d934e41..0000000000000 --- a/docs-translations/zh-CN/api/menu-item.md +++ /dev/null @@ -1,57 +0,0 @@ -# 菜单项 -菜单项模块允许你向应用或[menu][1]添加选项。 - -查看[menu][1]例子。 - -## 类:MenuItem -使用下面的方法创建一个新的 `MenuItem` - -###new MenuItem(options) -* `options` Object - * `click` Function - 当菜单项被点击的时候,使用 `click(menuItem,browserWindow)` 调用 - * `role` String - 定义菜单项的行为,在指定 `click` 属性时将会被忽略 - * `type` String - 取值 `normal`,`separator`,`checkbox`or`radio` - * `label` String - * `sublabel` String - * `accelerator` [Accelerator][2] - * `icon` [NativeImage][3] - * `enabled` Boolean - * `visible` Boolean - * `checked` Boolean - * `submenu` Menu - 应当作为 `submenu` 菜单项的特定类型,当它作为 `type: 'submenu'` 菜单项的特定类型时可以忽略。如果它的值不是 `Menu`,将自动转为 `Menu.buildFromTemplate`。 - * `id` String - 标志一个菜单的唯一性。如果被定义使用,它将被用作这个菜单项的参考位置属性。 - * `position` String - 定义给定的菜单的具体指定位置信息。 - -在创建菜单项时,如果有匹配的方法,建议指定 `role` 属性,不需要人为操作它的行为,这样菜单使用可以给用户最好的体验。 - - -`role`属性值可以为: - -* `undo` -* `redo` -* `cut` -* `copy` -* `paste` -* `selectall` -* `minimize` - 最小化当前窗口 -* `close` - 关闭当前窗口 - -在 macOS 上,`role` 还可以有以下值: - -* `about` - 匹配 `orderFrontStandardAboutPanel` 行为 -* `hide` - 匹配 `hide` 行为 -* `hideothers` - 匹配 `hideOtherApplications` 行为 -* `unhide` - 匹配 `unhideAllApplications` 行为 -* `front` - 匹配 `arrangeInFront` 行为 -* `window` - "Window" 菜单项 -* `help` - "Help" 菜单项 -* `services` - "Services" 菜单项 - - - - - - - [1]:https://github.com/heyunjiang/electron/blob/master/docs-translations/zh-CN/api/menu.md - [2]:https://github.com/heyunjiang/electron/blob/master/docs/api/accelerator.md - [3]:https://github.com/heyunjiang/electron/blob/master/docs/api/native-image.md \ No newline at end of file diff --git a/docs-translations/zh-CN/api/menu.md b/docs-translations/zh-CN/api/menu.md deleted file mode 100644 index ea2535cc8b001..0000000000000 --- a/docs-translations/zh-CN/api/menu.md +++ /dev/null @@ -1,355 +0,0 @@ -# 菜单 - -`menu` 类可以用来创建原生菜单,它可用作应用菜单和 -[context 菜单](https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/PopupGuide/ContextMenus). - -这个模块是一个主进程的模块,并且可以通过 `remote` 模块给渲染进程调用. - -每个菜单有一个或几个菜单项 [menu items](menu-item.md),并且每个菜单项可以有子菜单. - -下面这个例子是在网页(渲染进程)中通过 [remote](remote.md) 模块动态创建的菜单,并且右键显示: - -```html - - -``` - -例子,在渲染进程中使用模板api创建应用菜单: - -```javascript -var 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: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.reload(); - } - }, - { - label: 'Toggle Full Screen', - accelerator: (function() { - if (process.platform == 'darwin') - return 'Ctrl+Command+F'; - else - return 'F11'; - })(), - click: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); - } - }, - { - label: 'Toggle Developer Tools', - accelerator: (function() { - if (process.platform == 'darwin') - return 'Alt+Command+I'; - else - return 'Ctrl+Shift+I'; - })(), - click: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.toggleDevTools(); - } - }, - ] - }, - { - label: 'Window', - role: 'window', - submenu: [ - { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize' - }, - { - label: 'Close', - accelerator: 'CmdOrCtrl+W', - role: 'close' - }, - ] - }, - { - label: 'Help', - role: 'help', - submenu: [ - { - label: 'Learn More', - click: function() { require('electron').shell.openExternal('http://electron.atom.io') } - }, - ] - }, -]; - -if (process.platform == 'darwin') { - var name = require('electron').remote.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: function() { app.quit(); } - }, - ] - }); - // Window menu. - template[3].submenu.push( - { - type: 'separator' - }, - { - label: 'Bring All to Front', - role: 'front' - } - ); -} - -var menu = Menu.buildFromTemplate(template); -Menu.setApplicationMenu(menu); -``` - -## 类: Menu - -### `new Menu()` - -创建一个新的菜单. - -## 方法 - -`菜单` 类有如下方法: - -### `Menu.setApplicationMenu(menu)` - -* `menu` Menu - -在 macOS 上设置应用菜单 `menu` . -在windows 和 linux,是为每个窗口都在其顶部设置菜单 `menu`. - -### `Menu.sendActionToFirstResponder(action)` _macOS_ - -* `action` String - -发送 `action` 给应用的第一个响应器.这个用来模仿 Cocoa 菜单的默认行为,通常你只需要使用 `MenuItem` 的属性 `role`. - -查看更多 macOS 的原生 action [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) . - -### `Menu.buildFromTemplate(template)` - -* `template` Array - -一般来说,`template` 只是用来创建 [MenuItem](menu-item.md) 的数组 `参数` . - -你也可以向 `template` 元素添加其它东西,并且他们会变成已经有的菜单项的属性. - -##实例方法 - -`menu` 对象有如下实例方法 - -### `menu.popup([browserWindow, x, y, positioningItem])` - -* `browserWindow` BrowserWindow (可选) - 默认为 `null`. -* `x` Number (可选) - 默认为 -1. -* `y` Number (**必须** 如果x设置了) - 默认为 -1. -* `positioningItem` Number (可选) _macOS_ - 在指定坐标鼠标位置下面的菜单项的索引. 默认为 - -1. - -在 `browserWindow` 中弹出 context menu .你可以选择性地提供指定的 `x, y` 来设置菜单应该放在哪里,否则它将默认地放在当前鼠标的位置. - -### `menu.append(menuItem)` - -* `menuItem` MenuItem - -添加菜单项. - -### `menu.insert(pos, menuItem)` - -* `pos` Integer -* `menuItem` MenuItem - -在制定位置添加菜单项. - -### `menu.items()` - -获取一个菜单项数组. - -## macOS Application 上的菜单的注意事项 - -相对于windows 和 linux, macOS 上的应用菜单是完全不同的style,这里是一些注意事项,来让你的菜单项更原生化. - -### 标准菜单 - -在 macOS 上,有很多系统定义的标准菜单,例如 `Services` and -`Windows` 菜单.为了让你的应用更标准化,你可以为你的菜单的 `role` 设置值,然后 electron 将会识别他们并且让你的菜单更标准: - -* `window` -* `help` -* `services` - -### 标准菜单项行为 - -macOS 为一些菜单项提供了标准的行为方法,例如 `About xxx`, -`Hide xxx`, and `Hide Others`. 为了让你的菜单项的行为更标准化,你应该为菜单项设置 `role` 属性. - -### 主菜单名 - -在 macOS ,无论你设置的什么标签,应用菜单的第一个菜单项的标签始终未你的应用名字.想要改变它的话,你必须通过修改应用绑定的 `Info.plist` 文件来修改应用名字.更多信息参考[About Information -Property List Files][AboutInformationPropertyListFiles] . - -## 为制定浏览器窗口设置菜单 (*Linux* *Windows*) - -浏览器窗口的[`setMenu` 方法][setMenu] 能够设置菜单为特定浏览器窗口的类型. - -## 菜单项位置 - -当通过 `Menu.buildFromTemplate` 创建菜单的时候,你可以使用 `position` and `id` 来放置菜单项. - -`MenuItem` 的属性 `position` 格式为 `[placement]=[id]`,`placement` 取值为 `before`, `after`, 或 `endof` 和 `id`, `id` 是菜单已经存在的菜单项的唯一 ID: - -* `before` - 在对应引用id菜单项之前插入. 如果引用的菜单项不存在,则将其插在菜单末尾. -* `after` - 在对应引用id菜单项之后插入. 如果引用的菜单项不存在,则将其插在菜单末尾. -* `endof` - 在逻辑上包含对应引用id菜单项的集合末尾插入. 如果引用的菜单项不存在, 则将使用给定的id创建一个新的集合,并且这个菜单项将插入. - -当一个菜档项插入成功了,所有的没有插入的菜单项将一个接一个地在后面插入.所以如果你想在同一个位置插入一组菜单项,只需要为这组菜单项的第一个指定位置. - -### 例子 - -模板: - -```javascript -[ - {label: '4', id: '4'}, - {label: '5', id: '5'}, - {label: '1', id: '1', position: 'before=4'}, - {label: '2', id: '2'}, - {label: '3', id: '3'} -] -``` - -菜单: - -``` -- 1 -- 2 -- 3 -- 4 -- 5 -``` - -模板: - -```javascript -[ - {label: 'a', position: 'endof=letters'}, - {label: '1', position: 'endof=numbers'}, - {label: 'b', position: 'endof=letters'}, - {label: '2', position: 'endof=numbers'}, - {label: 'c', position: 'endof=letters'}, - {label: '3', position: 'endof=numbers'} -] -``` - -菜单: - -``` -- --- -- a -- b -- c -- --- -- 1 -- 2 -- 3 -``` - -[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 \ No newline at end of file diff --git a/docs-translations/zh-CN/api/native-image.md b/docs-translations/zh-CN/api/native-image.md deleted file mode 100644 index fc5955cd21acc..0000000000000 --- a/docs-translations/zh-CN/api/native-image.md +++ /dev/null @@ -1,148 +0,0 @@ -# nativeImage - -在 Electron 中, 对所有创建 images 的 api 来说, 你可以使用文件路径或 `nativeImage` 实例. 如果使用 `null` ,将创建一个空的image 对象. - -例如, 当创建一个 tray 或设置窗口的图标时候,你可以使用一个字符串的图片路径 : - -```javascript -var appIcon = new Tray('/Users/somebody/images/icon.png'); -var window = new BrowserWindow({icon: '/Users/somebody/images/window.png'}); -``` - -或者从剪切板中读取图片,它返回的是 `nativeImage`: - -```javascript -var image = clipboard.readImage(); -var appIcon = new Tray(image); -``` - -## 支持的格式 - -当前支持 `PNG` 和 `JPEG` 图片格式. 推荐 `PNG` ,因为它支持透明和无损压缩. - -在 Windows, 你也可以使用 `ICO` 图标的格式. - -## 高分辨率图片 - -如果平台支持 high-DPI,你可以在图片基础路径后面添加 `@2x` ,可以标识它为高分辨率的图片. - -例如,如果 `icon.png` 是一个普通图片并且拥有标准分辨率,然后 `icon@2x.png`将被当作高分辨率的图片处理,它将拥有双倍 DPI 密度. - -如果想同时支持展示不同分辨率的图片,你可以将拥有不同size 的图片放在同一个文件夹下,不用 DPI 后缀.例如 : - -```text -images/ -├── icon.png -├── icon@2x.png -└── icon@3x.png -``` - - -```javascript -var appIcon = new Tray('/Users/somebody/images/icon.png'); -``` - -也支持下面这些 DPI 后缀: - -* `@1x` -* `@1.25x` -* `@1.33x` -* `@1.4x` -* `@1.5x` -* `@1.8x` -* `@2x` -* `@2.5x` -* `@3x` -* `@4x` -* `@5x` - -## 模板图片 - -模板图片由黑色和清色(和一个 alpha 通道)组成. -模板图片不是单独使用的,而是通常和其它内容混合起来创建期望的最终效果. - -最常见的用力是将模板图片用到菜单栏图片上,所以它可以同时适应亮、黑不同的菜单栏. - -**注意:** 模板图片只在 macOS 上可用. - -为了将图片标识为一个模板图片,它的文件名应当以 `Template` 结尾. 例如: - -* `xxxTemplate.png` -* `xxxTemplate@2x.png` - -## 方法 - -`nativeImage` 类有如下方法: - -### `nativeImage.createEmpty()` - -创建一个空的 `nativeImage` 实例. - -### `nativeImage.createFromPath(path)` - -* `path` String - -从指定 `path` 创建一个新的 `nativeImage` 实例 . - -### `nativeImage.createFromBuffer(buffer[, scaleFactor])` - -* `buffer` [Buffer][buffer] -* `scaleFactor` Double (可选) - -从 `buffer` 创建一个新的 `nativeImage` 实例 .默认 `scaleFactor` 是 1.0. - -### `nativeImage.createFromDataURL(dataURL)` - -* `dataURL` String - -从 `dataURL` 创建一个新的 `nativeImage` 实例 . - -## 实例方法 - -`nativeImage` 有如下方法: - -```javascript -const nativeImage = require('electron').nativeImage; - -var image = nativeImage.createFromPath('/Users/somebody/images/icon.png'); -``` - -### `image.toPNG()` - -返回一个 [Buffer][buffer] ,它包含了图片的 `PNG` 编码数据. - -### `image.toJPEG(quality)` - -* `quality` Integer (**必须**) - 在 0 - 100 之间. - -返回一个 [Buffer][buffer] ,它包含了图片的 `JPEG` 编码数据. - -### `image.toDataURL()` - -返回图片数据的 URL. - -### `image.getNativeHandle()` _macOS_ - -返回一个保存了 c 指针的 [Buffer][buffer] 来潜在处理原始图像.在macOS, 将会返回一个 `NSImage` 指针实例. - -注意那返回的指针是潜在原始图像的弱指针,而不是一个复制,你_必须_ 确保与 `nativeImage` 的关联不间断 . - -### `image.isEmpty()` - -返回一个 boolean ,标识图片是否为空. - -### `image.getSize()` - -返回图片的 size. - -[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer - -### `image.setTemplateImage(option)` - -* `option` Boolean - -将图片标识为模板图片. - -### `image.isTemplateImage()` - -返回一个 boolean ,标识图片是否是模板图片. \ No newline at end of file diff --git a/docs-translations/zh-CN/api/power-monitor.md b/docs-translations/zh-CN/api/power-monitor.md deleted file mode 100644 index 3394b4a284e23..0000000000000 --- a/docs-translations/zh-CN/api/power-monitor.md +++ /dev/null @@ -1,36 +0,0 @@ -# powerMonitor - -`power-monitor`模块是用来监听能源区改变的.只能在主进程中使用.在 `app` 模块的 `ready` 事件触发之后就不能使用这个模块了. - -例如: - -```javascript -app.on('ready', function() { - require('electron').powerMonitor.on('suspend', function() { - console.log('The system is going to sleep'); - }); -}); -``` - -## 事件 - -`power-monitor` 模块可以触发下列事件: - -### Event: 'suspend' - -在系统挂起的时候触发. - -### Event: 'resume' - -在系统恢复继续工作的时候触发. -Emitted when system is resuming. - -### Event: 'on-ac' - -在系统使用交流电的时候触发. -Emitted when the system changes to AC power. - -### Event: 'on-battery' - -在系统使用电池电源的时候触发. -Emitted when system changes to battery power. \ No newline at end of file diff --git a/docs-translations/zh-CN/api/power-save-blocker.md b/docs-translations/zh-CN/api/power-save-blocker.md deleted file mode 100644 index 3a045eaea7798..0000000000000 --- a/docs-translations/zh-CN/api/power-save-blocker.md +++ /dev/null @@ -1,48 +0,0 @@ -# powerSaveBlocker - -`powerSaveBlocker` 模块是用来阻止应用系统进入睡眠模式的,因此这允许应用保持系统和屏幕继续工作. - -例如: - -```javascript -const powerSaveBlocker = require('electron').powerSaveBlocker; - -var id = powerSaveBlocker.start('prevent-display-sleep'); -console.log(powerSaveBlocker.isStarted(id)); - -powerSaveBlocker.stop(id); -``` - -## 方法 - -`powerSaveBlocker` 模块有如下方法: - -### `powerSaveBlocker.start(type)` - -* `type` String - 强行保存阻塞类型. - * `prevent-app-suspension` - 阻止应用挂起. - 保持系统活跃,但是允许屏幕不亮. 用例: - 下载文件或者播放音频. - * `prevent-display-sleep`- 阻止应用进入休眠. 保持系统和屏幕活跃,屏幕一直亮. 用例: 播放音频. - -开始阻止系统进入睡眠模式.返回一个整数,这个整数标识了保持活跃的blocker. - -**注意:** `prevent-display-sleep` 有更高的优先级 -`prevent-app-suspension`. 只有最高优先级生效. 换句话说, `prevent-display-sleep` 优先级永远高于 -`prevent-app-suspension`. - -例如, A 请求调用了 `prevent-app-suspension`, B请求调用了 `prevent-display-sleep`. `prevent-display-sleep` -将一直工作,直到B停止调用. 在那之后, `prevent-app-suspension` -才起效. - -### `powerSaveBlocker.stop(id)` - -* `id` Integer - 通过 `powerSaveBlocker.start` 返回的保持活跃的 blocker id. - -让指定blocker 停止活跃. - -### `powerSaveBlocker.isStarted(id)` - -* `id` Integer - 通过 `powerSaveBlocker.start` 返回的保持活跃的 blocker id. - -返回 boolean, 是否对应的 `powerSaveBlocker` 已经启动. \ No newline at end of file diff --git a/docs-translations/zh-CN/api/process.md b/docs-translations/zh-CN/api/process.md deleted file mode 100644 index c52591c54293e..0000000000000 --- a/docs-translations/zh-CN/api/process.md +++ /dev/null @@ -1,48 +0,0 @@ -# 进程 - -Electron 中的 `process` 对象 与 upstream node 中的有以下的不同点: - -* `process.type` String - 进程类型, 可以是 `browser` (i.e. main process) - 或 `renderer`. -* `process.versions.electron` String - Electron的版本. -* `process.versions.chrome` String - Chromium的版本. -* `process.resourcesPath` String - JavaScript源代码路径. -* `process.mas` Boolean - 在Mac App Store 创建, 它的值为 `true`, 在其它的地方值为 `undefined`. - -## 事件 - -### 事件: 'loaded' - -在Electron已经加载了其内部预置脚本和它准备加载主进程或渲染进程的时候触发. - -当node被完全关闭的时候,它可以被预加载脚本使用来添加(原文: removed)与node无关的全局符号来回退到全局范围: - -```js -// preload.js -var _setImmediate = setImmediate; -var _clearImmediate = clearImmediate; -process.once('loaded', function() { - global.setImmediate = _setImmediate; - global.clearImmediate = _clearImmediate; -}); -``` - -## 属性 - -### `process.noAsar` - -设置它为 `true` 可以使 `asar` 文件在node的内置模块中失效. - -## 方法 - -`process` 对象有如下方法: - -### `process.hang()` - -使当前进程的主线程挂起. - -### `process.setFdLimit(maxDescriptors)` _macOS_ _Linux_ - -* `maxDescriptors` Integer - -设置文件描述符软限制于 `maxDescriptors` 或硬限制与os, 无论它是否低于当前进程. diff --git a/docs-translations/zh-CN/api/protocol.md b/docs-translations/zh-CN/api/protocol.md deleted file mode 100644 index a7dab97c5d566..0000000000000 --- a/docs-translations/zh-CN/api/protocol.md +++ /dev/null @@ -1,183 +0,0 @@ -# 协议 - -`protocol` 模块可以注册一个自定义协议,或者使用一个已经存在的协议. - -例子,使用一个与 `file://` 功能相似的协议 : - -```javascript -const electron = require('electron'); -const app = electron.app; -const path = require('path'); - -app.on('ready', function() { - var protocol = electron.protocol; - protocol.registerFileProtocol('atom', function(request, callback) { - var url = request.url.substr(7); - callback({path: path.normalize(__dirname + '/' + url)}); - }, function (error) { - if (error) - console.error('Failed to register protocol') - }); -}); -``` - -**注意:** 这个模块只有在 `app` 模块的 `ready` 事件触发之后才可使用. - -## 方法 - -`protocol` 模块有如下方法: - -### `protocol.registerStandardSchemes(schemes)` - -* `schemes` Array - 将一个自定义的方案注册为标准的方案. - -一个标准的 `scheme` 遵循 RFC 3986 的 -[generic URI syntax](https://tools.ietf.org/html/rfc3986#section-3) 标准. 这包含了 `file:` 和 `filesystem:`. - -### `protocol.registerServiceWorkerSchemes(schemes)` - -* `schemes` Array - 将一个自定义的方案注册为处理 service workers. - -### `protocol.registerFileProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (可选) - -注册一个协议,用来发送响应文件.当通过这个协议来发起一个请求的时候,将使用 `handler(request, callback)` 来调用 -`handler` .当 `scheme` 被成功注册或者完成(错误)时失败,将使用 `completion(null)` 调用 `completion`. - -* `request` Object - * `url` String - * `referrer` String - * `method` String - * `uploadData` Array (可选) -* `callback` Function - -`uploadData` 是一个 `data` 对象数组: - -* `data` Object - * `bytes` Buffer - 被发送的内容. - * `file` String - 上传的文件路径. - -为了处理请求,调用 `callback` 时需要使用文件路径或者一个带 `path` 参数的对象, 例如 `callback(filePath)` 或 -`callback({path: filePath})`. - -当不使用任何参数调用 `callback` 时,你可以指定一个数字或一个带有 `error` 参数的对象,来标识 `request` 失败.你可以使用的 error number 可以参考 -[net error list][net-error]. - -默认 `scheme` 会被注册为一个 `http:` 协议,它与遵循 "generic URI syntax" 规则的协议解析不同,例如 `file:` ,所以你或许应该调用 `protocol.registerStandardSchemes` 来创建一个标准的 scheme. - -### `protocol.registerBufferProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (可选) - -注册一个 `scheme` 协议,用来发送响应 `Buffer` . - -这个方法的用法类似 `registerFileProtocol`,除非使用一个 `Buffer` 对象,或一个有 `data`, -`mimeType`, 和 `charset` 属性的对象来调用 `callback` . - -例子: - -```javascript -protocol.registerBufferProtocol('atom', function(request, callback) { - callback({mimeType: 'text/html', data: new Buffer('
Response
')}); -}, function (error) { - if (error) - console.error('Failed to register protocol') -}); -``` - -### `protocol.registerStringProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (可选) - -注册一个 `scheme` 协议,用来发送响应 `String` . - -这个方法的用法类似 `registerFileProtocol`,除非使用一个 `String` 对象,或一个有 `data`, -`mimeType`, 和 `charset` 属性的对象来调用 `callback` . - -### `protocol.registerHttpProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (可选) - -注册一个 `scheme` 协议,用来发送 HTTP 请求作为响应. - -这个方法的用法类似 `registerFileProtocol`,除非使用一个 `redirectRequest` 对象,或一个有 `url`, `method`, -`referrer`, `uploadData` 和 `session` 属性的对象来调用 `callback` . - -* `redirectRequest` Object - * `url` String - * `method` String - * `session` Object (可选) - * `uploadData` Object (可选) - -默认这个 HTTP 请求会使用当前 session .如果你想使用不同的session值,你应该设置 `session` 为 `null`. - -POST 请求应当包含 `uploadData` 对象. - -* `uploadData` object - * `contentType` String - 内容的 MIME type. - * `data` String - 被发送的内容. - -### `protocol.unregisterProtocol(scheme[, completion])` - -* `scheme` String -* `completion` Function (可选) - -注销自定义协议 `scheme`. - -### `protocol.isProtocolHandled(scheme, callback)` - -* `scheme` String -* `callback` Function - -将使用一个布尔值来调用 `callback` ,这个布尔值标识了是否已经存在 `scheme` 的句柄了. - -### `protocol.interceptFileProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (可选) - -拦截 `scheme` 协议并且使用 `handler` 作为协议的新的句柄来发送响应文件. - -### `protocol.interceptStringProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (可选) - -拦截 `scheme` 协议并且使用 `handler` 作为协议的新的句柄来发送响应 `String`. - -### `protocol.interceptBufferProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (可选) - -拦截 `scheme` 协议并且使用 `handler` 作为协议的新的句柄来发送响应 `Buffer`. - -### `protocol.interceptHttpProtocol(scheme, handler[, completion])` - -* `scheme` String -* `handler` Function -* `completion` Function (optional) - -拦截 `scheme` 协议并且使用 `handler` 作为协议的新的句柄来发送新的响应 HTTP 请求. -Intercepts `scheme` protocol and uses `handler` as the protocol's new handler -which sends a new HTTP request as a response. - -### `protocol.uninterceptProtocol(scheme[, completion])` - -* `scheme` String -* `completion` Function -取消对 `scheme` 的拦截,使用它的原始句柄进行处理. - -[net-error]: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h \ No newline at end of file diff --git a/docs-translations/zh-CN/api/remote.md b/docs-translations/zh-CN/api/remote.md deleted file mode 100644 index a686abf2f6184..0000000000000 --- a/docs-translations/zh-CN/api/remote.md +++ /dev/null @@ -1,137 +0,0 @@ -# remote - -`remote` 模块提供了一种在渲染进程(网页)和主进程之间进行进程间通讯(IPC)的简便途径。 - -Electron中, 与GUI相关的模块(如 `dialog`, `menu` 等)只存在于主进程,而不在渲染进程中 -。为了能从渲染进程中使用它们,需要用`ipc`模块来给主进程发送进程间消息。使用 `remote` -模块,可以调用主进程对象的方法,而无需显式地发送进程间消息,这类似于 Java 的 [RMI][rmi]。 -下面是从渲染进程创建一个浏览器窗口的例子: - -```javascript -const remote = require('electron').remote; -const BrowserWindow = remote.BrowserWindow; - -var win = new BrowserWindow({ width: 800, height: 600 }); -win.loadURL('https://github.com'); -``` - -**注意:** 反向操作(从主进程访问渲染进程),可以使用[webContents.executeJavascript](web-contents.md#webcontentsexecutejavascriptcode-usergesture). - -## 远程对象 - -`remote`模块返回的每个对象(包括函数)都代表了主进程中的一个对象(我们称之为远程对象或者远程函数)。 -当调用远程对象的方法、执行远程函数或者使用远程构造器(函数)创建新对象时,其实就是在发送同步的进程间消息。 - -在上面的例子中, `BrowserWindow` 和 `win` 都是远程对象,然而 -`new BrowserWindow` 并没有在渲染进程中创建 `BrowserWindow` 对象。 -而是在主进程中创建了 `BrowserWindow` 对象,并在渲染进程中返回了对应的远程对象,即 -`win` 对象。 - -请注意只有 [可枚举属性](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties) 才能通过 remote 进行访问. - -## 远程对象的生命周期 - -Electron 确保在渲染进程中的远程对象存在(换句话说,没有被垃圾收集),那主进程中的对应对象也不会被释放。 -当远程对象被垃圾收集之后,主进程中的对应对象才会被取消关联。 - -如果远程对象在渲染进程泄露了(即,存在某个表中但永远不会释放),那么主进程中的对应对象也一样会泄露, -所以你必须小心不要泄露了远程对象。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. - -不过,主要的值类型如字符串和数字,是传递的副本。 - -## 给主进程传递回调函数 - -在主进程中的代码可以从渲染进程——`remote`模块——中接受回调函数,但是使用这个功能的时候必须非常非常小心。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. - -比如,你不能主进程中给`Array.map`传递来自渲染进程的函数。 - -```javascript -// 主进程 mapNumbers.js -exports.withRendererCallback = function(mapper) { - return [1,2,3].map(mapper); -} - -exports.withLocalCallback = function() { - return exports.mapNumbers(function(x) { - return x + 1; - }); -} -``` - -```javascript -// 渲染进程 -var mapNumbers = require("remote").require("./mapNumbers"); - -var withRendererCb = mapNumbers.withRendererCallback(function(x) { - return x + 1; -}) - -var withLocalCb = mapNumbers.withLocalCallback() - -console.log(withRendererCb, withLocalCb) // [true, true, true], [2, 3, 4] -``` - -如你所见,渲染器回调函数的同步返回值没有按预期产生,与主进程中的一模一样的回调函数的返回值不同。 - -其次,传递给主进程的函数会持续到主进程对他们进行垃圾回收。 - -例如,下面的代码第一眼看上去毫无问题。给远程对象的`close`事件绑定了一个回调函数: - -```javascript -remote.getCurrentWindow().on('close', function() { - // blabla... -}); -``` - -但记住主进程会一直保持对这个回调函数的引用,除非明确的卸载它。如果不卸载,每次重新载入窗口都会再次绑定,这样每次重启就会泄露一个回调函数。 - -更严重的是,由于前面安装了回调函数的上下文已经被释放,所以当主进程的 `close` 事件触发的时候,会抛出异常。 - -为了避免这个问题,要确保对传递给主进程的渲染器的回调函数进行清理。可以清理事件处理器,或者明确告诉主进行取消来自已经退出的渲染器进程中的回调函数。 - -## 访问主进程中的内置模块 - -在主进程中的内置模块已经被添加为`remote`模块中的属性,所以可以直接像使用`electron`模块一样直接使用它们。 - -```javascript -const app = remote.app; -``` - -## 方法 - -`remote` 模块有以下方法: - -### `remote.require(module)` - -* `module` String - -返回在主进程中执行 `require(module)` 所返回的对象。 - -### `remote.getCurrentWindow()` - -返回该网页所属的 [`BrowserWindow`](browser-window.md) 对象。 - -### `remote.getCurrentWebContents()` - -返回该网页的 [`WebContents`](web-contents.md) 对象 - -### `remote.getGlobal(name)` - -* `name` String - -返回在主进程中名为 `name` 的全局变量(即 `global[name]`) 。 - -### `remote.process` - -返回主进程中的 `process` 对象。等同于 -`remote.getGlobal('process')` 但是有缓存。 - -[rmi]: http://en.wikipedia.org/wiki/Java_remote_method_invocation diff --git a/docs-translations/zh-CN/api/screen.md b/docs-translations/zh-CN/api/screen.md deleted file mode 100644 index 6c44acfeb196e..0000000000000 --- a/docs-translations/zh-CN/api/screen.md +++ /dev/null @@ -1,135 +0,0 @@ -# screen - -`screen` 模块检索屏幕的 size,显示,鼠标位置等的信息.在 `app` 模块的`ready` 事件触发之前不可使用这个模块. - -`screen` 是一个 [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter). - -**注意:** 在渲染进程 / 开发者工具栏, `window.screen` 是一个预设值的 DOM -属性, 所以这样写 `var screen = require('electron').screen` 将不会工作. -在我们下面的例子, 我们取代使用可变名字的 `electronScreen`. -一个例子,创建一个充满整个屏幕的窗口 : - -```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; - -var mainWindow; - -app.on('ready', function() { - var electronScreen = electron.screen; - var size = electronScreen.getPrimaryDisplay().workAreaSize; - mainWindow = new BrowserWindow({ width: size.width, height: size.height }); -}); -``` - -另一个例子,在此页外创建一个窗口: - -```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; - -var mainWindow; - -app.on('ready', function() { - var electronScreen = electron.screen; - var displays = electronScreen.getAllDisplays(); - var externalDisplay = null; - for (var i in displays) { - if (displays[i].bounds.x != 0 || displays[i].bounds.y != 0) { - externalDisplay = displays[i]; - break; - } - } - - if (externalDisplay) { - mainWindow = new BrowserWindow({ - x: externalDisplay.bounds.x + 50, - y: externalDisplay.bounds.y + 50 - }); - } -}); -``` - -## `Display` 对象 - -`Display` 对象表示一个连接到系统的物理显示. 一个虚设的 `Display` 或许存在于一个无头系统(headless system)中,或者一个 `Display` 对应一个远程的、虚拟的display. - -* `display` object - * `id` Integer - 与display 相关的唯一性标志. - * `rotation` Integer - 可以是 0, 1, 2, 3, 每个代表了屏幕旋转的度数 0, 90, 180, 270. - * `scaleFactor` Number - Output device's pixel scale factor. - * `touchSupport` String - 可以是 `available`, `unavailable`, `unknown`. - * `bounds` Object - * `size` Object - * `workArea` Object - * `workAreaSize` Object - -## 事件 - -`screen` 模块有如下事件: - -### Event: 'display-added' - -返回: - -* `event` Event -* `newDisplay` Object - -当添加了 `newDisplay` 时发出事件 - -### Event: 'display-removed' - -返回: - -* `event` Event -* `oldDisplay` Object - -当移出了 `oldDisplay` 时发出事件 - -### Event: 'display-metrics-changed' - -返回: - -* `event` Event -* `display` Object -* `changedMetrics` Array - -当一个 `display` 中的一个或更多的 metrics 改变时发出事件. -`changedMetrics` 是一个用来描述这个改变的数组.可能的变化为 `bounds`, -`workArea`, `scaleFactor` 和 `rotation`. - -## 方法 - -`screen` 模块有如下方法: - -### `screen.getCursorScreenPoint()` - -返回当前鼠标的绝对路径 . - -### `screen.getPrimaryDisplay()` - -返回最主要的 display. - -### `screen.getAllDisplays()` - -返回一个当前可用的 display 数组. - -### `screen.getDisplayNearestPoint(point)` - -* `point` Object - * `x` Integer - * `y` Integer - -返回离指定点最近的 display. - -### `screen.getDisplayMatching(rect)` - -* `rect` Object - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -返回与提供的边界范围最密切相关的 display. diff --git a/docs-translations/zh-CN/api/session.md b/docs-translations/zh-CN/api/session.md deleted file mode 100644 index b9664c08e6529..0000000000000 --- a/docs-translations/zh-CN/api/session.md +++ /dev/null @@ -1,481 +0,0 @@ -# session - -`session` 模块可以用来创建一个新的 `Session` 对象. - -你也可以通过使用 [`webContents`](web-contents.md) 的属性 `session` 来使用一个已有页面的 `session` ,`webContents` 是[`BrowserWindow`](browser-window.md) 的属性. - -```javascript -const BrowserWindow = require('electron').BrowserWindow; - -var win = new BrowserWindow({ width: 800, height: 600 }); -win.loadURL("http://github.com"); - -var ses = win.webContents.session; -``` - -## 方法 - -`session` 模块有如下方法: - -### session.fromPartition(partition) - -* `partition` String - -从字符串 `partition` 返回一个新的 `Session` 实例. - -如果 `partition` 以 `persist:` 开头,那么这个page将使用一个持久的 session,这个 session 将对应用的所有 page 可用.如果没前缀,这个 page 将使用一个历史 session.如果 `partition` 为空,那么将返回应用的默认 session . - -## 属性 - -`session` 模块有如下属性: - -### session.defaultSession - -返回应用的默认 session 对象. - -## Class: Session - -可以在 `session` 模块中创建一个 `Session` 对象 : - -```javascript -const session = require('electron').session; - -var ses = session.fromPartition('persist:name'); -``` - -### 实例事件 - -实例 `Session` 有以下事件: - -#### Event: 'will-download' - -* `event` Event -* `item` [DownloadItem](download-item.md) -* `webContents` [WebContents](web-contents.md) - -当 Electron 将要从 `webContents` 下载 `item` 时触发. - -调用 `event.preventDefault()` 可以取消下载,并且在进程的下个 tick中,这个 `item` 也不可用. - -```javascript -session.defaultSession.on('will-download', function(event, item, webContents) { - event.preventDefault(); - require('request')(item.getURL(), function(data) { - require('fs').writeFileSync('/somewhere', data); - }); -}); -``` - -### 实例方法 - -实例 `Session` 有以下方法: - -#### `ses.cookies` - -`cookies` 赋予你全力来查询和修改 cookies. 例如: - -```javascript -// 查询所有 cookies. -session.defaultSession.cookies.get({}, function(error, cookies) { - console.log(cookies); -}); - -// 查询与指定 url 相关的所有 cookies. -session.defaultSession.cookies.get({ url : "http://www.github.com" }, function(error, cookies) { - console.log(cookies); -}); - -// 设置 cookie; -// may overwrite equivalent cookies if they exist. -var cookie = { url : "http://www.github.com", name : "dummy_name", value : "dummy" }; -session.defaultSession.cookies.set(cookie, function(error) { - if (error) - console.error(error); -}); -``` - -#### `ses.cookies.get(filter, callback)` - -* `filter` Object - * `url` String (可选) - 与获取 cookies 相关的 - `url`.不设置的话就是从所有 url 获取 cookies . - * `name` String (可选) - 通过 name 过滤 cookies. - * `domain` String (可选) - 获取对应域名或子域名的 cookies . - * `path` String (可选) - 获取对应路径的 cookies . - * `secure` Boolean (可选) - 通过安全性过滤 cookies. - * `session` Boolean (可选) - 过滤掉 session 或 持久的 cookies. -* `callback` Function - -发送一个请求,希望获得所有匹配 `details` 的 cookies, -在完成的时候,将通过 `callback(error, cookies)` 调用 `callback`. - -`cookies`是一个 `cookie` 对象. - -* `cookie` Object - * `name` String - cookie 名. - * `value` String - cookie值. - * `domain` String - cookie域名. - * `hostOnly` String - 是否 cookie 是一个 host-only cookie. - * `path` String - cookie路径. - * `secure` Boolean - 是否是安全 cookie. - * `httpOnly` Boolean - 是否只是 HTTP cookie. - * `session` Boolean - cookie 是否是一个 session cookie 或一个带截至日期的持久 - cookie . - * `expirationDate` Double (可选) - cookie的截至日期,数值为UNIX纪元以来的秒数. 对session cookies 不提供. - -#### `ses.cookies.set(details, callback)` - -* `details` Object - * `url` String - 与获取 cookies 相关的 - `url`. - * `name` String - cookie 名. 忽略默认为空. - * `value` String - cookie 值. 忽略默认为空. - * `domain` String - cookie的域名. 忽略默认为空. - * `path` String - cookie 的路径. 忽略默认为空. - * `secure` Boolean - 是否已经进行了安全性标识. 默认为 - false. - * `session` Boolean - 是否已经 HttpOnly 标识. 默认为 false. - * `expirationDate` Double - cookie的截至日期,数值为UNIX纪元以来的秒数. 如果忽略, cookie 变为 session cookie. -* `callback` Function - -使用 `details` 设置 cookie, 完成时使用 `callback(error)` 掉哟个 `callback` . - -#### `ses.cookies.remove(url, name, callback)` - -* `url` String - 与 cookies 相关的 - `url`. -* `name` String - 需要删除的 cookie 名. -* `callback` Function - -删除匹配 `url` 和 `name` 的 cookie, 完成时使用 `callback()`调用`callback`. - -#### `ses.getCacheSize(callback)` - -* `callback` Function - * `size` Integer - 单位 bytes 的缓存 size. - -返回 session 的当前缓存 size . - -#### `ses.clearCache(callback)` - -* `callback` Function - 操作完成时调用 - -清空 session 的 HTTP 缓存. - -#### `ses.clearStorageData([options, ]callback)` - -* `options` Object (可选) - * `origin` String - 应当遵循 `window.location.origin` 的格式 - `scheme://host:port`. - * `storages` Array - 需要清理的 storages 类型, 可以包含 : - `appcache`, `cookies`, `filesystem`, `indexdb`, `local storage`, - `shadercache`, `websql`, `serviceworkers` - * `quotas` Array - 需要清理的类型指标, 可以包含: - `temporary`, `persistent`, `syncable`. -* `callback` Function - 操作完成时调用. - -清除 web storages 的数据. - -#### `ses.flushStorageData()` - -将没有写入的 DOMStorage 写入磁盘. - -#### `ses.setProxy(config, callback)` - -* `config` Object - * `pacScript` String - 与 PAC 文件相关的 URL. - * `proxyRules` String - 代理使用规则. -* `callback` Function - 操作完成时调用. - -设置 proxy settings. - -当 `pacScript` 和 `proxyRules` 一同提供时,将忽略 `proxyRules`,并且使用 `pacScript` 配置 . - -`proxyRules` 需要遵循下面的规则: - -``` -proxyRules = schemeProxies[";"] -schemeProxies = ["="] -urlScheme = "http" | "https" | "ftp" | "socks" -proxyURIList = [","] -proxyURL = ["://"][":"] -``` - -例子: - -* `http=foopy:80;ftp=foopy2` - 为 `http://` URL 使用 HTTP 代理 `foopy:80` , 和为 `ftp://` URL - HTTP 代理 `foopy2:80` . -* `foopy:80` - 为所有 URL 使用 HTTP 代理 `foopy:80` . -* `foopy:80,bar,direct://` - 为所有 URL 使用 HTTP 代理 `foopy:80` , 如果 `foopy:80` 不可用,则切换使用 `bar`, 再往后就不使用代理了. -* `socks4://foopy` - 为所有 URL 使用 SOCKS v4 代理 `foopy:1080`. -* `http=foopy,socks5://bar.com` - 为所有 URL 使用 HTTP 代理 `foopy`, 如果 `foopy`不可用,则切换到 SOCKS5 代理 `bar.com`. -* `http=foopy,direct://` - 为所有http url 使用 HTTP 代理,如果 `foopy`不可用,则不使用代理. -* `http=foopy;socks=foopy2` - 为所有http url 使用 `foopy` 代理,为所有其他 url 使用 `socks4://foopy2` 代理. - -### `ses.resolveProxy(url, callback)` - -* `url` URL -* `callback` Function - -解析 `url` 的代理信息.当请求完成的时候使用 `callback(proxy)` 调用 `callback`. - -#### `ses.setDownloadPath(path)` - -* `path` String - 下载地址 - -设置下载保存地址,默认保存地址为各自 app 应用的 `Downloads`目录. - -#### `ses.enableNetworkEmulation(options)` - -* `options` Object - * `offline` Boolean - 是否模拟网络故障. - * `latency` Double - 每毫秒的 RTT - * `downloadThroughput` Double - 每 Bps 的下载速率. - * `uploadThroughput` Double - 每 Bps 的上载速率. - -通过给定配置的 `session` 来模拟网络. - -```javascript -// 模拟 GPRS 连接,使用的 50kbps 流量,500 毫秒的 rtt. -window.webContents.session.enableNetworkEmulation({ - latency: 500, - downloadThroughput: 6400, - uploadThroughput: 6400 -}); - -// 模拟网络故障. -window.webContents.session.enableNetworkEmulation({offline: true}); -``` - -#### `ses.disableNetworkEmulation()` - -停止所有已经使用 `session` 的活跃模拟网络. -重置为原始网络类型. - -#### `ses.setCertificateVerifyProc(proc)` - -* `proc` Function - -为 `session` 设置证书验证过程,当请求一个服务器的证书验证时,使用 `proc(hostname, certificate, callback)` 调用 `proc`.调用 `callback(true)` 来接收证书,调用 `callback(false)` 来拒绝验证证书. - -调用了 `setCertificateVerifyProc(null)` ,则将会回复到默认证书验证过程. - -```javascript -myWindow.webContents.session.setCertificateVerifyProc(function(hostname, cert, callback) { - if (hostname == 'github.com') - callback(true); - else - callback(false); -}); -``` - -#### `ses.setPermissionRequestHandler(handler)` - -* `handler` Function - * `webContents` Object - [WebContents](web-contents.md) 请求许可. - * `permission` String - 枚举了 'media', 'geolocation', 'notifications', 'midiSysex', 'pointerLock', 'fullscreen'. - * `callback` Function - 允许或禁止许可. - -为对应 `session` 许可请求设置响应句柄.调用 `callback(true)` 接收许可,调用 `callback(false)` 禁止许可. - -```javascript -session.fromPartition(partition).setPermissionRequestHandler(function(webContents, permission, callback) { - if (webContents.getURL() === host) { - if (permission == "notifications") { - callback(false); // denied. - return; - } - } - - callback(true); -}); -``` - -#### `ses.clearHostResolverCache([callback])` - -* `callback` Function (可选) - 操作结束调用. - -清除主机解析缓存. - -#### `ses.webRequest` - -在其生命周期的不同阶段,`webRequest` API 设置允许拦截并修改请求内容. - -每个 API 接收一可选的 `filter` 和 `listener`,当 API 事件发生的时候使用 `listener(details)` 调用 `listener`,`details` 是一个用来描述请求的对象.为 `listener` 使用 `null` 则会退定事件. - -`filter` 是一个拥有 `urls` 属性的对象,这是一个 url 模式数组,这用来过滤掉不匹配指定 url 模式的请求.如果忽略 `filter` ,那么所有请求都将可以成功匹配. - -所有事件的 `listener` 都有一个回调事件,当 `listener` 完成它的工作的时候,它将使用一个 `response` 对象来调用. - -```javascript -// 将所有请求的代理都修改为下列 url. -var filter = { - urls: ["https://*.github.com/*", "*://electron.github.io"] -}; - -session.defaultSession.webRequest.onBeforeSendHeaders(filter, function(details, callback) { - details.requestHeaders['User-Agent'] = "MyAgent"; - callback({cancel: false, requestHeaders: details.requestHeaders}); -}); -``` - -#### `ses.webRequest.onBeforeRequest([filter, ]listener)` - -* `filter` Object -* `listener` Function - -当一个请求即将开始的时候,使用 `listener(details, callback)` 调用 `listener`. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `uploadData` Array (可选) -* `callback` Function - -`uploadData` 是一个 `data` 数组对象: - -* `data` Object - * `bytes` Buffer - 被发送的内容. - * `file` String - 上载文件路径. - -`callback` 必须使用一个 `response` 对象来调用: - -* `response` Object - * `cancel` Boolean (可选) - * `redirectURL` String (可选) - 原始请求阻止发送或完成,而不是重定向. - -#### `ses.webRequest.onBeforeSendHeaders([filter, ]listener)` - -* `filter` Object -* `listener` Function - -一旦请求报文头可用了,在发送 HTTP 请求的之前,使用 `listener(details, callback)` 调用 `listener`.这也许会在服务器发起一个tcp 连接,但是在发送任何 http 数据之前发生. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `requestHeaders` Object -* `callback` Function - -必须使用一个 `response` 对象来调用 `callback` : - -* `response` Object - * `cancel` Boolean (可选) - * `requestHeaders` Object (可选) - 如果提供了,将使用这些 headers 来创建请求. - -#### `ses.webRequest.onSendHeaders([filter, ]listener)` - -* `filter` Object -* `listener` Function - -在一个请求正在发送到服务器的时候,使用 `listener(details)` 来调用 `listener` ,之前 `onBeforeSendHeaders` 修改部分响应可用,同时取消监听. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `requestHeaders` Object - -#### `ses.webRequest.onHeadersReceived([filter,] listener)` - -* `filter` Object -* `listener` Function - -当 HTTP 请求报文头已经到达的时候,使用 `listener(details, callback)` 调用 `listener` . - -* `details` Object - * `id` String - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `statusLine` String - * `statusCode` Integer - * `responseHeaders` Object -* `callback` Function - -必须使用一个 `response` 对象来调用 `callback` : - -* `response` Object - * `cancel` Boolean - * `responseHeaders` Object (可选) - 如果提供, 服务器将假定使用这些头来响应. - -#### `ses.webRequest.onResponseStarted([filter, ]listener)` - -* `filter` Object -* `listener` Function - -当响应body的首字节到达的时候,使用 `listener(details)` 调用 `listener`.对 http 请求来说,这意味着状态线和响应头可用了. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `responseHeaders` Object - * `fromCache` Boolean - 标识响应是否来自磁盘 - cache. - * `statusCode` Integer - * `statusLine` String - -#### `ses.webRequest.onBeforeRedirect([filter, ]listener)` - -* `filter` Object -* `listener` Function - -当服务器的重定向初始化正要启动时,使用 `listener(details)` 调用 `listener`. - -* `details` Object - * `id` String - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `redirectURL` String - * `statusCode` Integer - * `ip` String (可选) - 请求的真实服务器ip 地址 - * `fromCache` Boolean - * `responseHeaders` Object - -#### `ses.webRequest.onCompleted([filter, ]listener)` - -* `filter` Object -* `listener` Function - -当请求完成的时候,使用 `listener(details)` 调用 `listener`. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `responseHeaders` Object - * `fromCache` Boolean - * `statusCode` Integer - * `statusLine` String - -#### `ses.webRequest.onErrorOccurred([filter, ]listener)` - -* `filter` Object -* `listener` Function - -当一个错误发生的时候,使用 `listener(details)` 调用 `listener`. - -* `details` Object - * `id` Integer - * `url` String - * `method` String - * `resourceType` String - * `timestamp` Double - * `fromCache` Boolean - * `error` String - 错误描述. \ No newline at end of file diff --git a/docs-translations/zh-CN/api/shell.md b/docs-translations/zh-CN/api/shell.md deleted file mode 100644 index 17ebe5511a375..0000000000000 --- a/docs-translations/zh-CN/api/shell.md +++ /dev/null @@ -1,45 +0,0 @@ -# shell - -`shell` 模块提供了集成其他桌面客户端的关联功能. - - -在用户默认浏览器中打开URL的示例: - -```javascript -const {shell} = require('electron'); - -shell.openExternal('https://github.com'); -``` - -## Methods - -`shell` 模块包含以下函数: - -### `shell.showItemInFolder(fullPath)` - -* `fullPath` String - -打开文件所在文件夹,一般情况下还会选中它. - -### `shell.openItem(fullPath)` - -* `fullPath` String - -以默认打开方式打开文件. - -### `shell.openExternal(url)` - -* `url` String - -以系统默认设置打开外部协议.(例如,mailto: somebody@somewhere.io会打开用户默认的邮件客户端) - - -### `shell.moveItemToTrash(fullPath)` - -* `fullPath` String - -删除指定路径文件,并返回此操作的状态值(boolean类型). - -### `shell.beep()` - -播放 beep 声音. diff --git a/docs-translations/zh-CN/api/synopsis.md b/docs-translations/zh-CN/api/synopsis.md deleted file mode 100644 index 014d5893c73a8..0000000000000 --- a/docs-translations/zh-CN/api/synopsis.md +++ /dev/null @@ -1,71 +0,0 @@ -# 简介 - -所有的[Node.js's built-in modules][1]在Electron中都可用,并且所有的node的第三方组件也可以放心使用(包括[自身的模块][2])。 - -Electron也提供了一些额外的内置组件来开发传统桌面应用。一些组件只可以在主进程中使用,一些只可以在渲染进程中使用,但是也有部分可以在这2种进程中都可使用。 - -基本规则:GUI模块或者系统底层的模块只可以在主进程中使用。要使用这些模块,你应当很熟悉[主进程vs渲染进程][3]脚本的概念。 - -主进程脚本看起来像个普通的nodejs脚本 - -```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; - -var window = null; - -app.on('ready', function() { - window = new BrowserWindow({width: 800, height: 600}); - window.loadURL('https://github.com'); -}); -``` - -渲染进程和传统的web界面一样,除了它具有使用node模块的能力: - -```html - - - - - - -``` - -如果想运行应用,参考 `Run your app` 。 - -## 解构任务 - -如果你使用的是CoffeeScript或Babel,你可以使用[destructuring assignment][4]来让使用内置模块更简单: - -```javascript -const {app, BrowserWindow} = require('electron'); -``` - -然而如果你使用的是普通的JavaScript,你就需要等到Chrome支持ES6了。 - -##使用内置模块时禁用旧样式 - -在版本v0.35.0之前,所有的内置模块都需要按造 `require('module-name')` 形式来使用,虽然它有很多[弊端][5],我们仍然在老的应用中友好的支持它。 - -为了完整的禁用旧样式,你可以设置环境变量 `ELECTRON_HIDE_INTERNAL_MODULES ` : - -```javascript -process.env.ELECTRON_HIDE_INTERNAL_MODULES = 'true' -``` - -或者调用 `hideInternalModules` API: - -```javascript -require('electron').hideInternalModules() -``` - - - [1]:http://nodejs.org/api/ - [2]:https://github.com/heyunjiang/electron/blob/master/docs/tutorial/using-native-node-modules.md - [3]:https://github.com/heyunjiang/electron/blob/master/docs/tutorial/quick-start.md#the-main-process - [4]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment - [5]:https://github.com/electron/electron/issues/387 \ No newline at end of file diff --git a/docs-translations/zh-CN/api/tray.md b/docs-translations/zh-CN/api/tray.md deleted file mode 100644 index 2d23857e59515..0000000000000 --- a/docs-translations/zh-CN/api/tray.md +++ /dev/null @@ -1,205 +0,0 @@ -# Tray - -用一个 `Tray` 来表示一个图标,这个图标处于正在运行的系统的通知区 ,通常被添加到一个 context menu 上. - -```javascript -const electron = require('electron'); -const app = electron.app; -const Menu = electron.Menu; -const Tray = electron.Tray; - -var appIcon = null; -app.on('ready', function(){ - appIcon = new Tray('/path/to/my/icon'); - var contextMenu = Menu.buildFromTemplate([ - { label: 'Item1', type: 'radio' }, - { label: 'Item2', type: 'radio' }, - { label: 'Item3', type: 'radio', checked: true }, - { label: 'Item4', type: 'radio' } - ]); - appIcon.setToolTip('This is my application.'); - appIcon.setContextMenu(contextMenu); -}); - -``` - -__平台限制:__ - -* 在 Linux, 如果支持应用指示器则使用它,否则使用 `GtkStatusIcon` 代替. -* 在 Linux ,配置了只有有了应用指示器的支持, 你必须安装 `libappindicator1` 来让 tray icon 执行. -* 应用指示器只有在它拥有 context menu 时才会显示. -* 当在linux 上使用了应用指示器,将忽略点击事件. -* 在 Linux,为了让单独的 `MenuItem` 起效,需要再次调用 `setContextMenu` .例如: - -```javascript -contextMenu.items[2].checked = false; -appIcon.setContextMenu(contextMenu); -``` -如果想在所有平台保持完全相同的行为,不应该依赖点击事件,而是一直将一个 context menu 添加到 tray icon. - -## Class: Tray - -`Tray` 是一个 [事件发出者][event-emitter]. - -### `new Tray(image)` - -* `image` [NativeImage](native-image.md) - -创建一个与 `image` 相关的 icon. - -## 事件 - -`Tray` 模块可发出下列事件: - -**注意:** 一些事件只能在特定的os中运行,已经标明. - -### Event: 'click' - -* `event` Event - * `altKey` Boolean - * `shiftKey` Boolean - * `ctrlKey` Boolean - * `metaKey` Boolean -* `bounds` Object - tray icon 的 bounds. - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -当tray icon被点击的时候发出事件. - -__注意:__ `bounds` 只在 macOS 和 Windows 上起效. - -### Event: 'right-click' _macOS_ _Windows_ - -* `event` Event - * `altKey` Boolean - * `shiftKey` Boolean - * `ctrlKey` Boolean - * `metaKey` Boolean -* `bounds` Object - tray icon 的 bounds. - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -当tray icon被鼠标右键点击的时候发出事件. - -### Event: 'double-click' _macOS_ _Windows_ - -* `event` Event - * `altKey` Boolean - * `shiftKey` Boolean - * `ctrlKey` Boolean - * `metaKey` Boolean -* `bounds` Object - tray icon 的 bounds. - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer - -当tray icon被双击的时候发出事件. - -### Event: 'balloon-show' _Windows_ - -当tray 气泡显示的时候发出事件. - -### Event: 'balloon-click' _Windows_ - -当tray 气泡被点击的时候发出事件. - -### Event: 'balloon-closed' _Windows_ - -当tray 气泡关闭的时候发出事件,因为超时或人为关闭. - -### Event: 'drop' _macOS_ - -当tray icon上的任何可拖动项被删除的时候发出事件. - -### Event: 'drop-files' _macOS_ - -* `event` -* `files` Array - 已删除文件的路径. - -当tray icon上的可拖动文件被删除的时候发出事件. - -### Event: 'drag-enter' _macOS_ - -当一个拖动操作进入tray icon的时候发出事件. - -### Event: 'drag-leave' _macOS_ - -当一个拖动操作离开tray icon的时候发出事件. -Emitted when a drag operation exits the tray icon. - -### Event: 'drag-end' _macOS_ - -当一个拖动操作在tray icon上或其它地方停止拖动的时候发出事件. - -## 方法 - -`Tray` 模块有以下方法: - -**Note:** 一些方法只能在特定的os中运行,已经标明. - -### `Tray.destroy()` - -立刻删除 tray icon. - -### `Tray.setImage(image)` - -* `image` [NativeImage](native-image.md) - -让 `image` 与 tray icon 关联起来. - -### `Tray.setPressedImage(image)` _macOS_ - -* `image` [NativeImage](native-image.md) - -当在 macOS 上按压 tray icon 的时候, 让 `image` 与 tray icon 关联起来. - -### `Tray.setToolTip(toolTip)` - -* `toolTip` String - -为 tray icon 设置 hover text. - -### `Tray.setTitle(title)` _macOS_ - -* `title` String - -在状态栏沿着 tray icon 设置标题. - -### `Tray.setHighlightMode(highlight)` _macOS_ - -* `highlight` Boolean - -当 tray icon 被点击的时候,是否设置它的背景色变为高亮(blue).默认为 true. - -### `Tray.displayBalloon(options)` _Windows_ - -* `options` Object - * `icon` [NativeImage](native-image.md) - * `title` String - * `content` String - -展示一个 tray balloon. - -### `Tray.popUpContextMenu([menu, position])` _macOS_ _Windows_ - -* `menu` Menu (optional) -* `position` Object (可选) - 上托位置. - * `x` Integer - * `y` Integer - -从 tray icon 上托出 context menu . 当划过 `menu` 的时候, `menu` 显示,代替 tray 的 context menu . - -`position` 只在 windows 上可用,默认为 (0, 0) . - -### `Tray.setContextMenu(menu)` - -* `menu` Menu - -为这个 icon 设置 context menu . - -[event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter \ No newline at end of file diff --git a/docs-translations/zh-CN/api/web-contents.md b/docs-translations/zh-CN/api/web-contents.md deleted file mode 100644 index c05b6d2593c72..0000000000000 --- a/docs-translations/zh-CN/api/web-contents.md +++ /dev/null @@ -1,864 +0,0 @@ -# webContents - -`webContents` 是一个 -[事件发出者](http://nodejs.org/api/events.html#events_class_events_eventemitter). - -它负责渲染并控制网页,也是 [`BrowserWindow`](browser-window.md) 对象的属性.一个使用 `webContents` 的例子: - -```javascript -const BrowserWindow = require('electron').BrowserWindow; - -var win = new BrowserWindow({width: 800, height: 1500}); -win.loadURL("http://github.com"); - -var webContents = win.webContents; -``` - -## 事件 - -`webContents` 对象可发出下列事件: - -### Event: 'did-finish-load' - -当导航完成时发出事件,`onload` 事件也完成. - -### Event: 'did-fail-load' - -返回: - -* `event` Event -* `errorCode` Integer -* `errorDescription` String -* `validatedURL` String -* `isMainFrame` Boolean - -这个事件类似 `did-finish-load` ,但是是在加载失败或取消加载时发出, 例如, `window.stop()` 请求结束.错误代码的完整列表和它们的含义都可以在 [here](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h) 找到. - -### Event: 'did-frame-finish-load' - -返回: - -* `event` Event -* `isMainFrame` Boolean - -当一个 frame 导航完成的时候发出事件. - -### Event: 'did-start-loading' - -当 tab 的spinner 开始 spinning的时候. - -### Event: 'did-stop-loading' - -当 tab 的spinner 结束 spinning的时候. - -### Event: 'did-get-response-details' - -返回: - -* `event` Event -* `status` Boolean -* `newURL` String -* `originalURL` String -* `httpResponseCode` Integer -* `requestMethod` String -* `referrer` String -* `headers` Object -* `resourceType` String - -当有关请求资源的详细信息可用的时候发出事件. -`status` 标识了 socket链接来下载资源. - -### Event: 'did-get-redirect-request' - -返回: - -* `event` Event -* `oldURL` String -* `newURL` String -* `isMainFrame` Boolean -* `httpResponseCode` Integer -* `requestMethod` String -* `referrer` String -* `headers` Object - -当在请求资源时收到重定向的时候发出事件. - -### Event: 'dom-ready' - -返回: - -* `event` Event - -当指定 frame 中的 文档加载完成的时候发出事件. - -### Event: 'page-favicon-updated' - -返回: - -* `event` Event -* `favicons` Array - Array of URLs - -当 page 收到图标 url 的时候发出事件. - -### Event: 'new-window' - -返回: - -* `event` Event -* `url` String -* `frameName` String -* `disposition` String - 可为 `default`, `foreground-tab`, `background-tab`, - `new-window` 和 `other`. -* `options` Object - 创建新的 `BrowserWindow`时使用的参数. - -当 page 请求打开指定 url 窗口的时候发出事件.这可以是通过 `window.open` 或一个外部连接如 `` 发出的请求. - -默认指定 `url` 的 `BrowserWindow` 会被创建. - -调用 `event.preventDefault()` 可以用来阻止打开窗口. - -### Event: 'will-navigate' - -返回: - -* `event` Event -* `url` String - -当用户或 page 想要开始导航的时候发出事件.它可在当 `window.location` 对象改变或用户点击 page 中的链接的时候发生. - -当使用 api(如 `webContents.loadURL` 和 `webContents.back`) 以编程方式来启动导航的时候,这个事件将不会发出. - -它也不会在页内跳转发生, 例如点击锚链接或更新 `window.location.hash`.使用 `did-navigate-in-page` 事件可以达到目的. - -调用 `event.preventDefault()` 可以阻止导航. - -### Event: 'did-navigate' - -返回: - -* `event` Event -* `url` String - -当一个导航结束时候发出事件. - -页内跳转时不会发出这个事件,例如点击锚链接或更新 `window.location.hash`.使用 `did-navigate-in-page` 事件可以达到目的. - -### Event: 'did-navigate-in-page' - -返回: - -* `event` Event -* `url` String - -当页内导航发生的时候发出事件. - -当页内导航发生的时候,page 的url 改变,但是不会跳出界面.例如当点击锚链接时或者 DOM 的 `hashchange` 事件发生. - -### Event: 'crashed' - -当渲染进程崩溃的时候发出事件. - -### Event: 'plugin-crashed' - -返回: - -* `event` Event -* `name` String -* `version` String - -当插件进程崩溃时候发出事件. - -### Event: 'destroyed' - -当 `webContents` 被删除的时候发出事件. - -### Event: 'devtools-opened' - -当开发者工具栏打开的时候发出事件. - -### Event: 'devtools-closed' - -当开发者工具栏关闭时候发出事件. - -### Event: 'devtools-focused' - -当开发者工具栏获得焦点或打开的时候发出事件. - -### Event: 'certificate-error' - -返回: - -* `event` Event -* `url` URL -* `error` String - The error code -* `certificate` Object - * `data` Buffer - PEM encoded data - * `issuerName` String -* `callback` Function - -当验证证书或 `url` 失败的时候发出事件. - -使用方法类似 [`app` 的 `certificate-error` 事件](app.md#event-certificate-error). - -### Event: 'select-client-certificate' - -返回: - -* `event` Event -* `url` URL -* `certificateList` [Objects] - * `data` Buffer - PEM encoded data - * `issuerName` String - Issuer's Common Name -* `callback` Function - -当请求客户端证书的时候发出事件. - -使用方法类似 [`app` 的 `select-client-certificate` 事件](app.md#event-select-client-certificate). - -### Event: 'login' - -返回: - -* `event` Event -* `request` Object - * `method` String - * `url` URL - * `referrer` URL -* `authInfo` Object - * `isProxy` Boolean - * `scheme` String - * `host` String - * `port` Integer - * `realm` String -* `callback` Function - -当 `webContents` 想做基本验证的时候发出事件. - -使用方法类似 [the `login` event of `app`](app.md#event-login). - -### Event: 'found-in-page' - -返回: - -* `event` Event -* `result` Object - * `requestId` Integer - * `finalUpdate` Boolean - 标识是否还有更多的值可以查看. - * `activeMatchOrdinal` Integer (可选) - 活动匹配位置 - * `matches` Integer (可选) - 匹配数量. - * `selectionArea` Object (可选) - 协调首个匹配位置. - -当使用 [`webContents.findInPage`](web-contents.md#webcontentsfindinpage) 进行页内查找并且找到可用值得时候发出事件. - -### Event: 'media-started-playing' - -当媒体开始播放的时候发出事件. - -### Event: 'media-paused' - -当媒体停止播放的时候发出事件. - -### Event: 'did-change-theme-color' - -当page 的主题色时候发出事件.这通常由于引入了一个 meta 标签 : - -```html - -``` - -### Event: 'cursor-changed' - -返回: - -* `event` Event -* `type` String -* `image` NativeImage (可选) -* `scale` Float (可选) - -当鼠标的类型发生改变的时候发出事件. `type` 的参数可以是 `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`, `custom`. - -如果 `type` 参数值为 `custom`, `image` 参数会在一个`NativeImage` 中控制自定义鼠标图片, 并且 `scale` 会控制图片的缩放比例. - -## 实例方法 - -`webContents` 对象有如下的实例方法: - -### `webContents.loadURL(url[, options])` - -* `url` URL -* `options` Object (可选) - * `httpReferrer` String - A HTTP Referrer url. - * `userAgent` String - 产生请求的用户代理 - * `extraHeaders` String - 以 "\n" 分隔的额外头 - -在窗口中加载 `url` , `url` 必须包含协议前缀, -比如 `http://` 或 `file://`. 如果加载想要忽略 http 缓存,可以使用 `pragma` 头来达到目的. - -```javascript -const options = {"extraHeaders" : "pragma: no-cache\n"} -webContents.loadURL(url, options) -``` - -### `webContents.downloadURL(url)` - -* `url` URL - -初始化一个指定 `url` 的资源下载,不导航跳转. `session` 的 `will-download` 事件会触发. - -### `webContents.getURL()` - -返回当前page 的 url. - -```javascript -var win = new BrowserWindow({width: 800, height: 600}); -win.loadURL("http://github.com"); - -var currentURL = win.webContents.getURL(); -``` - -### `webContents.getTitle()` - -返回当前page 的 标题. - -### `webContents.isLoading()` - -返回一个布尔值,标识当前页是否正在加载. - -### `webContents.isWaitingForResponse()` - -返回一个布尔值,标识当前页是否正在等待主要资源的第一次响应. - -### `webContents.stop()` - -停止还为开始的导航. - -### `webContents.reload()` - -重载当前页. - -### `webContents.reloadIgnoringCache()` - -重载当前页,忽略缓存. - -### `webContents.canGoBack()` - -返回一个布尔值,标识浏览器是否能回到前一个page. - -### `webContents.canGoForward()` - -返回一个布尔值,标识浏览器是否能前往下一个page. - -### `webContents.canGoToOffset(offset)` - -* `offset` Integer - -返回一个布尔值,标识浏览器是否能前往指定 `offset` 的page. - -### `webContents.clearHistory()` - -清除导航历史. - -### `webContents.goBack()` - -让浏览器回退到前一个page. - -### `webContents.goForward()` - -让浏览器回前往下一个page. - -### `webContents.goToIndex(index)` - -* `index` Integer - -让浏览器回前往指定 `index` 的page. - -### `webContents.goToOffset(offset)` - -* `offset` Integer - -导航到相对于当前页的偏移位置页. - -### `webContents.isCrashed()` - -渲染进程是否崩溃. - -### `webContents.setUserAgent(userAgent)` - -* `userAgent` String - -重写本页用户代理. - -### `webContents.getUserAgent()` - -返回一个 `String` ,标识本页用户代理信息. - -### `webContents.insertCSS(css)` - -* `css` String - -为当前页插入css. - -### `webContents.executeJavaScript(code[, userGesture, callback])` - -* `code` String -* `userGesture` Boolean (可选) -* `callback` Function (可选) - 脚本执行完成后调用的回调函数. - * `result` - -评估 page `代码`. - -浏览器窗口中的一些 HTML API ,例如 `requestFullScreen`,只能被用户手势请求.设置 `userGesture` 为 `true` 可以取消这个限制. - -### `webContents.setAudioMuted(muted)` - -* `muted` Boolean - -减缓当前也的 audio 的播放速度. - -### `webContents.isAudioMuted()` - -返回一个布尔值,标识当前页是否减缓了 audio 的播放速度. - -### `webContents.undo()` - -执行网页的编辑命令 `undo` . - -### `webContents.redo()` - -执行网页的编辑命令 `redo` . - -### `webContents.cut()` - -执行网页的编辑命令 `cut` . - -### `webContents.copy()` - -执行网页的编辑命令 `copy` . - -### `webContents.paste()` - -执行网页的编辑命令 `paste` . - -### `webContents.pasteAndMatchStyle()` - -执行网页的编辑命令 `pasteAndMatchStyle` . - -### `webContents.delete()` - -执行网页的编辑命令 `delete` . - -### `webContents.selectAll()` - -执行网页的编辑命令 `selectAll` . - -### `webContents.unselect()` - -执行网页的编辑命令 `unselect` . - -### `webContents.replace(text)` - -* `text` String - -执行网页的编辑命令 `replace` . - -### `webContents.replaceMisspelling(text)` - -* `text` String - -执行网页的编辑命令 `replaceMisspelling` . - -### `webContents.insertText(text)` - -* `text` String - -插入 `text` 到获得了焦点的元素. - -### `webContents.findInPage(text[, options])` - -* `text` String - 查找内容, 不能为空. -* `options` Object (可选) - * `forward` Boolean - 是否向前或向后查找, 默认为 `true`. - * `findNext` Boolean - 当前操作是否是第一次查找或下一次查找, - 默认为 `false`. - * `matchCase` Boolean - 查找是否区分大小写, - 默认为 `false`. - * `wordStart` Boolean -是否仅以首字母查找. - 默认为 `false`. - * `medialCapitalAsWordStart` Boolean - 是否结合 `wordStart`,如果匹配是大写字母开头,后面接小写字母或无字母,那么就接受这个词中匹配.接受几个其它的合成词匹配, 默认为 `false`. - -发起请求,在网页中查找所有与 `text` 相匹配的项,并且返回一个 `Integer` 来表示这个请求用的请求Id.这个请求结果可以通过订阅 - [`found-in-page`](web-contents.md#event-found-in-page) 事件来取得. - -### `webContents.stopFindInPage(action)` - -* `action` String - 指定一个行为来接替停止 - [`webContents.findInPage`](web-contents.md#webcontentfindinpage) 请求. - * `clearSelection` - 转变为一个普通的 selection. - * `keepSelection` - 清除 selection. - * `activateSelection` - 获取焦点并点击 selection node. - -使用给定的 `action` 来为 `webContents` 停止任何 `findInPage` 请求. - -```javascript -webContents.on('found-in-page', function(event, result) { - if (result.finalUpdate) - webContents.stopFindInPage("clearSelection"); -}); - -const requestId = webContents.findInPage("api"); -``` - -### `webContents.hasServiceWorker(callback)` - -* `callback` Function - -检查是否有任何 ServiceWorker 注册了,并且返回一个布尔值,来作为 `callback`响应的标识. - -### `webContents.unregisterServiceWorker(callback)` - -* `callback` Function - -如果存在任何 ServiceWorker ,则全部注销,并且当JS承诺执行行或JS拒绝执行而失败的时候,返回一个布尔值,它标识了相应的 `callback`. - -### `webContents.print([options])` - -* `options` Object (可选) - * `silent` Boolean - 不需要请求用户的打印设置. 默认为 `false`. - * `printBackground` Boolean - 打印背景和网页图片. 默认为 `false`. - -打印窗口的网页. 当设置 `silent` 为 `false` 的时候,Electron 将使用系统默认的打印机和打印方式来打印. - -在网页中调用 `window.print()` 和 调用 `webContents.print({silent: false, printBackground: false})`具有相同的作用. - -**注意:** 在 Windows, 打印 API 依赖于 `pdf.dll`. 如果你的应用不使用任何的打印, 你可以安全删除 `pdf.dll` 来减少二进制文件的size. - -### `webContents.printToPDF(options, callback)` - -* `options` Object - * `marginsType` Integer - 指定使用的 margin type. 默认 margin 使用 0, 无 margin 使用 1, 最小化 margin 使用 2. - * `pageSize` String - 指定生成的PDF文件的page size. 可以是 `A3`, - `A4`, `A5`, `Legal`, `Letter` 和 `Tabloid`. - * `printBackground` Boolean - 是否打印 css 背景. - * `printSelectionOnly` Boolean - 是否只打印选中的部分. - * `landscape` Boolean - landscape 为 `true`, portrait 为 `false`. -* `callback` Function - -打印窗口的网页为 pdf ,使用 Chromium 预览打印的自定义设置. - -完成时使用 `callback(error, data)` 调用 `callback` . `data` 是一个 `Buffer` ,包含了生成的 pdf 数据. - -默认,空的 `options` 被视为 : - -```javascript -{ - marginsType: 0, - printBackground: false, - printSelectionOnly: false, - landscape: false -} -``` - -```javascript -const BrowserWindow = require('electron').BrowserWindow; -const fs = require('fs'); - -var win = new BrowserWindow({width: 800, height: 600}); -win.loadURL("http://github.com"); - -win.webContents.on("did-finish-load", function() { - // Use default printing options - win.webContents.printToPDF({}, function(error, data) { - if (error) throw error; - fs.writeFile("/tmp/print.pdf", data, function(error) { - if (error) - throw error; - console.log("Write PDF successfully."); - }) - }) -}); -``` - -### `webContents.addWorkSpace(path)` - -* `path` String - -添加指定的路径给开发者工具栏的 workspace.必须在 DevTools 创建之后使用它 : - -```javascript -mainWindow.webContents.on('devtools-opened', function() { - mainWindow.webContents.addWorkSpace(__dirname); -}); -``` - -### `webContents.removeWorkSpace(path)` - -* `path` String - -从开发者工具栏的 workspace 删除指定的路径. - -### `webContents.openDevTools([options])` - -* `options` Object (可选) - * `detach` Boolean - 在一个新窗口打开开发者工具栏 - -打开开发者工具栏. - -### `webContents.closeDevTools()` - -关闭开发者工具栏. - -### `webContents.isDevToolsOpened()` - -返回布尔值,开发者工具栏是否打开. - -### `webContents.isDevToolsFocused()` - -返回布尔值,开发者工具栏视图是否获得焦点. - -### `webContents.toggleDevTools()` - -Toggles 开发者工具. - -### `webContents.inspectElement(x, y)` - -* `x` Integer -* `y` Integer - -在 (`x`, `y`) 开始检测元素. - -### `webContents.inspectServiceWorker()` - -为 service worker 上下文打开开发者工具栏. - -### `webContents.send(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (可选) - -通过 `channel` 发送异步消息给渲染进程,你也可发送任意的参数.参数应该在 JSON 内部序列化,并且此后没有函数或原形链被包括了. - -渲染进程可以通过使用 `ipcRenderer` 监听 `channel` 来处理消息. - -例子,从主进程向渲染进程发送消息 : - -```javascript -// 主进程. -var window = null; -app.on('ready', function() { - window = new BrowserWindow({width: 800, height: 600}); - window.loadURL('file://' + __dirname + '/index.html'); - window.webContents.on('did-finish-load', function() { - window.webContents.send('ping', 'whoooooooh!'); - }); -}); -``` - -```html - - - - - - -``` - -### `webContents.enableDeviceEmulation(parameters)` - -`parameters` Object, properties: - -* `screenPosition` String - 指定需要模拟的屏幕 - (默认 : `desktop`) - * `desktop` - * `mobile` -* `screenSize` Object - 设置模拟屏幕 size (screenPosition == mobile) - * `width` Integer - 设置模拟屏幕 width - * `height` Integer - 设置模拟屏幕 height -* `viewPosition` Object - 在屏幕放置 view - (screenPosition == mobile) (默认: `{x: 0, y: 0}`) - * `x` Integer - 设置偏移左上角的x轴 - * `y` Integer - 设置偏移左上角的y轴 -* `deviceScaleFactor` Integer - 设置设备比例因子 (如果为0,默认为原始屏幕比例) (默认: `0`) -* `viewSize` Object - 设置模拟视图 size (空表示不覆盖) - * `width` Integer - 设置模拟视图 width - * `height` Integer - 设置模拟视图 height -* `fitToView` Boolean - 如果有必要的话,是否把模拟视图按比例缩放来适应可用空间 (默认: `false`) -* `offset` Object - 可用空间内的模拟视图偏移 (不在适应模式) (默认: `{x: 0, y: 0}`) - * `x` Float - 设置相对左上角的x轴偏移值 - * `y` Float - 设置相对左上角的y轴偏移值 -* `scale` Float - 可用空间内的模拟视图偏移 (不在适应视图模式) (默认: `1`) - -使用给定的参数来开启设备模拟. - -### `webContents.disableDeviceEmulation()` - -使用 `webContents.enableDeviceEmulation` 关闭设备模拟. - -### `webContents.sendInputEvent(event)` - -* `event` Object - * `type` String (**必需**) - 事件类型,可以是 `mouseDown`, - `mouseUp`, `mouseEnter`, `mouseLeave`, `contextMenu`, `mouseWheel`, - `mouseMove`, `keyDown`, `keyUp`, `char`. - * `modifiers` Array - 事件的 modifiers 数组, 可以是 - include `shift`, `control`, `alt`, `meta`, `isKeypad`, `isAutoRepeat`, - `leftButtonDown`, `middleButtonDown`, `rightButtonDown`, `capsLock`, - `numLock`, `left`, `right`. - -向 page 发送一个输入 `event` . - -对键盘事件来说,`event` 对象还有如下属性 : - -* `keyCode` String (**必需**) - 特点是将作为键盘事件发送. 可用的 key codes [Accelerator](accelerator.md). - - -对鼠标事件来说,`event` 对象还有如下属性 : - -* `x` Integer (**required**) -* `y` Integer (**required**) -* `button` String - button 按下, 可以是 `left`, `middle`, `right` -* `globalX` Integer -* `globalY` Integer -* `movementX` Integer -* `movementY` Integer -* `clickCount` Integer - -对鼠标滚轮事件来说,`event` 对象还有如下属性 : - -* `deltaX` Integer -* `deltaY` Integer -* `wheelTicksX` Integer -* `wheelTicksY` Integer -* `accelerationRatioX` Integer -* `accelerationRatioY` Integer -* `hasPreciseScrollingDeltas` Boolean -* `canScroll` Boolean - -### `webContents.beginFrameSubscription(callback)` - -* `callback` Function - -开始订阅 提交 事件和捕获数据帧,当有 提交 事件时,使用 `callback(frameBuffer)` 调用 `callback`. - -`frameBuffer` 是一个包含原始像素数据的 `Buffer`,像素数据是按照 32bit BGRA 格式有效存储的,但是实际情况是取决于处理器的字节顺序的(大多数的处理器是存放小端序的,如果是在大端序的处理器上,数据是 32bit ARGB 格式). - -### `webContents.endFrameSubscription()` - -停止订阅帧提交事件. - -### `webContents.savePage(fullPath, saveType, callback)` - -* `fullPath` String - 文件的完整路径. -* `saveType` String - 指定保存类型. - * `HTMLOnly` - 只保存html. - * `HTMLComplete` - 保存整个 page 内容. - * `MHTML` - 保存完整的 html 为 MHTML. -* `callback` Function - `function(error) {}`. - * `error` Error - -如果保存界面过程初始化成功,返回 true. - -```javascript -win.loadURL('https://github.com'); - -win.webContents.on('did-finish-load', function() { - win.webContents.savePage('/tmp/test.html', 'HTMLComplete', function(error) { - if (!error) - console.log("Save page successfully"); - }); -}); -``` - -## 实例属性 - -`WebContents` 对象也有下列属性: - -### `webContents.session` - -返回这个 `webContents` 使用的 [session](session.md) 对象. - -### `webContents.hostWebContents` - -返回这个 `webContents` 的父 `webContents` . - -### `webContents.devToolsWebContents` - -获取这个 `WebContents` 的开发者工具栏的 `WebContents` . - -**注意:** 用户不可保存这个对象,因为当开发者工具栏关闭的时候它的值为 `null` . - -### `webContents.debugger` - -调试 API 为 [remote debugging protocol][rdp] 提供交替传送. - -```javascript -try { - win.webContents.debugger.attach("1.1"); -} catch(err) { - console.log("Debugger attach failed : ", err); -}; - -win.webContents.debugger.on('detach', function(event, reason) { - console.log("Debugger detached due to : ", reason); -}); - -win.webContents.debugger.on('message', function(event, method, params) { - if (method == "Network.requestWillBeSent") { - if (params.request.url == "https://www.github.com") - win.webContents.debugger.detach(); - } -}) - -win.webContents.debugger.sendCommand("Network.enable"); -``` - -#### `webContents.debugger.attach([protocolVersion])` - -* `protocolVersion` String (可选) - 请求调试协议版本. - -添加 `webContents` 调试. - -#### `webContents.debugger.isAttached()` - -返回一个布尔值,标识是否已经给 `webContents` 添加了调试. - -#### `webContents.debugger.detach()` - -删除 `webContents` 调试. - -#### `webContents.debugger.sendCommand(method[, commandParams, callback])` - -* `method` String - 方法名, 应该是由远程调试协议定义的方法. -* `commandParams` Object (可选) - 请求参数为 JSON 对象. -* `callback` Function (可选) - Response - * `error` Object - 错误消息,标识命令失败. - * `result` Object - 回复在远程调试协议中由 'returns'属性定义的命令描述. - -发送给定命令给调试目标. - -### Event: 'detach' - -* `event` Event -* `reason` String - 拆分调试器原因. - -在调试 session 结束时发出事件.这在 `webContents` 关闭时或 `webContents` 请求开发者工具栏时发生. - -### Event: 'message' - -* `event` Event -* `method` String - 方法名. -* `params` Object - 在远程调试协议中由 'parameters' 属性定义的事件参数. - -每当调试目标发出事件时发出. - -[rdp]: https://developer.chrome.com/devtools/docs/debugger-protocol \ No newline at end of file diff --git a/docs-translations/zh-CN/api/web-frame.md b/docs-translations/zh-CN/api/web-frame.md deleted file mode 100644 index d278e94271312..0000000000000 --- a/docs-translations/zh-CN/api/web-frame.md +++ /dev/null @@ -1,101 +0,0 @@ -# webFrame - -`web-frame` 模块允许你自定义如何渲染当前网页 . - -例子,放大当前页到 200%. - -```javascript -var webFrame = require('electron').webFrame; - -webFrame.setZoomFactor(2); -``` - -## 方法 - -`web-frame` 模块有如下方法: - -### `webFrame.setZoomFactor(factor)` - -* `factor` Number - 缩放参数. - -将缩放参数修改为指定的参数值.缩放参数是百分制的,所以 300% = 3.0. - -### `webFrame.getZoomFactor()` - -返回当前缩放参数值. - -### `webFrame.setZoomLevel(level)` - -* `level` Number - 缩放水平 - -将缩放水平修改为指定的水平值. 原始 size 为 0 ,并且每次增长都表示放大 20% 或缩小 20%,默认限制为原始 size 的 300% 到 50% 之间 . - -### `webFrame.getZoomLevel()` - -返回当前缩放水平值. - -### `webFrame.setZoomLevelLimits(minimumLevel, maximumLevel)` - -* `minimumLevel` Number -* `maximumLevel` Number - -设置缩放水平的最大值和最小值. - -### `webFrame.setSpellCheckProvider(language, autoCorrectWord, provider)` - -* `language` String -* `autoCorrectWord` Boolean -* `provider` Object - -为输入框或文本域设置一个拼写检查 provider . - -`provider` 必须是一个对象,它有一个 `spellCheck` 方法,这个方法返回扫过的单词是否拼写正确 . - -例子,使用 [node-spellchecker][spellchecker] 作为一个 provider: - -```javascript -webFrame.setSpellCheckProvider("en-US", true, { - spellCheck: function(text) { - return !(require('spellchecker').isMisspelled(text)); - } -}); -``` - -### `webFrame.registerURLSchemeAsSecure(scheme)` - -* `scheme` String - -注册 `scheme` 为一个安全的 scheme. - - -安全的 schemes 不会引发混合内容 warnings.例如, `https` 和 -`data` 是安全的 schemes ,因为它们不能被活跃网络攻击而失效. - -### `webFrame.registerURLSchemeAsBypassingCSP(scheme)` - -* `scheme` String - -忽略当前网页内容的安全策略,直接从 `scheme` 加载. - -### `webFrame.registerURLSchemeAsPrivileged(scheme)` - -* `scheme` String - -通过资源的内容安全策略,注册 `scheme` 为安全的 scheme,允许注册 ServiceWorker并且支持 fetch API. - -### `webFrame.insertText(text)` - -* `text` String - -向获得焦点的原色插入内容 . - -### `webFrame.executeJavaScript(code[, userGesture])` - -* `code` String -* `userGesture` Boolean (可选) - 默认为 `false`. - -评估页面代码 . - -在浏览器窗口中,一些 HTML APIs ,例如 `requestFullScreen`,只可以通过用户手势来使用.设置`userGesture` 为 `true` 可以突破这个限制 . - -[spellchecker]: https://github.com/atom/node-spellchecker \ No newline at end of file diff --git a/docs-translations/zh-CN/api/web-view-tag.md b/docs-translations/zh-CN/api/web-view-tag.md deleted file mode 100644 index a1348c4d5882a..0000000000000 --- a/docs-translations/zh-CN/api/web-view-tag.md +++ /dev/null @@ -1,692 +0,0 @@ -# `` 标签 - -使用 `webview` 标签来把 'guest' 内容(例如 web pages )嵌入到你的 Electron app 中. guest内容包含在 `webview` 容器中.一个嵌入你应用的page控制着guest内容如何布局摆放和表达含义. - -与 `iframe` 不同, `webview` 和你的应用运行的是不同的进程. 它不拥有渲染进程的权限,并且应用和嵌入内容之间的交互全部都是异步的.因为这能保证应用的安全性不受嵌入内容的影响. - -## 例子 - -把一个 web page 嵌入到你的app,首先添加 `webview` 标签到你的app待嵌入page(展示 guest content). 在一个最简单的 `webview` 中,它包含了 web page 的文件路径和一个控制 `webview` 容器展示效果的css样式: - -```html - -``` - -如果想随时控制 guest 内容,可以添加 JavaScript 脚本来监听 `webview` 事件使用 `webview` 方法来做出响应. 这里是2个事件监听的例子:一个监听 web page 准备加载,另一个监听 web page 停止加载,并且在加载的时候显示一条 "loading..." 信息: - -```html - -``` - -## 标签属性 - -`webview` 标签有下面一些属性 : - -### `src` - -```html - -``` - -将一个可用的url做为这个属性的初始值添加到顶部导航. - -如果把当前页的src添加进去将加载当前page. - - `src`同样可以填 data urls,例如 -`data:text/plain,Hello, world!`. - -### `autosize` - -```html - -``` - -如果这个属性的值为 "on" , `webview` 容器将会根据属性`minwidth`, `minheight`, `maxwidth`, 和 -`maxheight` 的值在它们之间自适应. 只有在 `autosize` 开启的时候这个约束才会有效. 当 `autosize` 开启的时候, `webview` 容器的 size 只能在上面那四个属性值之间. - -### `nodeintegration` - -```html - -``` - -如果设置了这个属性, `webview` 中的 guest page 将整合node,并且拥有可以使用系统底层的资源,例如 `require` 和 `process` . - -### `plugins` - -```html - -``` - -如果这个属性的值为 "on" , `webview` 中的 guest page 就可以使用浏览器插件。 - -### `preload` - -```html - -``` - -在 guest page 中的其他脚本执行之前预加载一个指定的脚本。规定预加载脚本的url须如 `file:` 或者 `asar:`,因为它在是 guest page 中通过通过 `require` 命令加载的。 - -如果 guest page 没有整合 node ,这个脚本将试图使用真个 Node APIs ,但是在这个脚本执行完毕时,之前由node插入的全局对象会被删除。 - - -### `httpreferrer` - -```html - -``` - -为 guest page 设置 referrer URL。 - -### `useragent` - -```html - -``` - -在 guest page 加载之前为其设置用户代理。如果页面已经加载了,可以使用 `setUserAgent` 方法来改变用户代理。 - -### `disablewebsecurity` - -```html - -``` - -如果这个属性的值为 "on" , guest page会禁用web安全控制. - -### partition - -```html - - -``` - -为page设置session。如果初始值为 `partition` ,这个 page 将会为app中的所有 page 应用同一个持续有效的 session。如果没有 `persist:` 前缀, 这个 page 将会使用一个历史 session 。通过分配使用相同的 `partition`, 所有的page都可以分享相同的session。如果 `partition` 没有设置,那app将使用默认的session. - -这个值只能在在第一个渲染进程之前设置修改,之后修改的话会无效并且抛出一个DOM异常. - -### `allowpopups` - -```html - -``` - -如果这个属性的值为 "on" ,将允许 guest page 打开一个新窗口。 - -### `blinkfeatures` - -```html - -``` - -这个属性的值为一个用逗号分隔的列表,它的值指定特性被启用。你可以从[setFeatureEnabledFromString][blink-feature-string]函数找到完整的支持特性。 - -## 方法 - - `webview` 的方法集合: - -**注意:** webview 元素必须在使用这些方法之前加载完毕。 - -**例如** - -```javascript -webview.addEventListener("dom-ready", function() { - webview.openDevTools(); -}); -``` - -### `.loadURL(url[, options])` - -* `url` URL -* `options` Object (可选) - * `httpReferrer` String - 一个http类型的url. - * `userAgent` String -用于发起请求的用户代理. - * `extraHeaders` String - 额外的headers,用 "\n"分隔. - -加载 webview 中的 `url`,`url` 必须包含协议前缀,例如 `http://` 或 `file://`. - -### `.getURL()` - -从 guest page 中返回 url. - -### `.getTitle()` - -从 guest page 中返回 title. - -### `.isLoading()` - -返回一个 guest page 是否仍在加载资源的布尔值. - -### `.isWaitingForResponse()` - -返回一个 guest page 是否正在等待page的主要资源做出回应的布尔值. - - -### `.stop()` - -停止渲染. - -### `.reload()` - -重新加载 guest page. - -### `.reloadIgnoringCache()` - -忽视缓存,重新加载 guest page. - -### `.canGoBack()` - -返回一个 guest page 是否能够回退的布尔值. - -### `.canGoForward()` - -返回一个 guest page 是否能够前进的布尔值. - -### `.canGoToOffset(offset)` - -* `offset` Integer - -返回一个 guest page 是否能够前进到 `offset` 的布尔值. - -### `.clearHistory()` - -清除导航历史. - -### `.goBack()` - -guest page 回退. - -### `.goForward()` - -guest page 前进. - -### `.goToIndex(index)` - -* `index` Integer - -guest page 导航到指定的绝对位置. - -### `.goToOffset(offset)` - -* `offset` Integer - -guest page 导航到指定的相对位置. - -### `.isCrashed()` - -返回一个 渲染进程是否崩溃 的布尔值. - -### `.setUserAgent(userAgent)` - -* `userAgent` String - -重新设置用户代理. - -### `.getUserAgent()` - -返回用户代理名字,返回类型:`String`. - -### `.insertCSS(css)` - -* `css` String - -插入css. - -### `.executeJavaScript(code, userGesture, callback)` - -* `code` String -* `userGesture` Boolean - 默认 `false`. -* `callback` Function (可选) - 回调函数. - * `result` - -评估 `code` ,如果 `userGesture` 值为 true ,它将在这个page里面创建用户手势. HTML APIs ,如 `requestFullScreen`,它需要用户响应,那么将自动通过这个参数优化. - -### `.openDevTools()` - -为 guest page 打开开发工具调试窗口. - -### `.closeDevTools()` - -为 guest page 关闭开发工具调试窗口. - -### `.isDevToolsOpened()` - -返回一个 guest page 是否打开了开发工具调试窗口的布尔值. - -### `.isDevToolsFocused()` - -返回一个 guest page 是否聚焦了开发工具调试窗口的布尔值. - -### `.inspectElement(x, y)` - -* `x` Integer -* `y` Integer - -开始检查 guest page 在 (`x`, `y`) 位置的元素. - -### `.inspectServiceWorker()` - -在 guest page 中为服务人员打开开发工具. - -### `.setAudioMuted(muted)` - -* `muted` Boolean -设置 guest page 流畅(muted). - -### `.isAudioMuted()` - -返回一个 guest page 是否流畅的布尔值. - -### `.undo()` - -在page中编辑执行 `undo` 命令. - -### `.redo()` - -在page中编辑执行 `redo` 命令. - -### `.cut()` - -在page中编辑执行 `cut` 命令. - -### `.copy()` - -在page中编辑执行 `copy` 命令. - -### `.paste()` - -在page中编辑执行 `paste` 命令. - -### `.pasteAndMatchStyle()` - -在page中编辑执行 `pasteAndMatchStyle` 命令. - -### `.delete()` - -在page中编辑执行 `delete` 命令. - -### `.selectAll()` - -在page中编辑执行 `selectAll` 命令. - -### `.unselect()` - -在page中编辑执行 `unselect` 命令. - -### `.replace(text)` - -* `text` String - -在page中编辑执行 `replace` 命令. - -### `.replaceMisspelling(text)` - -* `text` String - -在page中编辑执行 `replaceMisspelling` 命令. - -### `.insertText(text)` - -* `text` String - -插入文本. - -### `.findInPage(text[, options])` - -* `text` String - 搜索内容,不能为空. -* `options` Object (可选) - * `forward` Boolean - 向前或向后, 默认为 `true`. - * `findNext` Boolean - 是否查找的第一个结果, - 默认为 `false`. - * `matchCase` Boolean - 是否区分大小写, - 默认为 `false`. - * `wordStart` Boolean - 是否只查找首字母. - 默认为 `false`. - * `medialCapitalAsWordStart` Boolean - 当配合 `wordStart`的时候,接受一个文字中的匹配项,要求匹配项是以大写字母开头后面跟小写字母或者没有字母。可以接受一些其他单词内部匹配, 默认为 `false`. - -发起一个请求来寻找页面中的所有匹配 `text` 的地方并且返回一个 `Integer`来表示这个请求用的请求Id. 这个请求结果可以通过订阅[`found-in-page`](web-view-tag.md#event-found-in-page) 事件来取得. - -### `.stopFindInPage(action)` - -* `action` String - 指定一个行为来接替停止 - [`.findInPage`](web-view-tag.md#webviewtagfindinpage) 请求. - * `clearSelection` - 转变为一个普通的 selection. - * `keepSelection` - 清除 selection. - * `activateSelection` - 聚焦并点击 selection node. - -使用 `action` 停止 `findInPage` 请求. - -### `.print([options])` - -打印输出 `webview` 的 web page. 类似 `webContents.print([options])`. - -### `.printToPDF(options, callback)` - -以pdf格式打印输出 `webview` 的 web page. 类似 `webContents.printToPDF(options, callback)`. - -### `.send(channel[, arg1][, arg2][, ...])` - -* `channel` String -* `arg` (可选) - -通过 `channel` 向渲染进程发出异步消息,你也可以发送任意的参数。 -渲染进程通过`ipcRenderer` 模块监听 `channel` 事件来控制消息. - -例子 -[webContents.send](web-contents.md#webcontentssendchannel-args). - -### `.sendInputEvent(event)` - -* `event` Object - -向 page 发送输入事件. - -查看 [webContents.sendInputEvent](web-contents.md##webcontentssendinputeventevent) -关于 `event` 对象的相信介绍. - -### `.getWebContents()` - -返回和这个 `webview` 相关的 [WebContents](web-contents.md). - -## DOM 事件 - -`webview` 可用下面的 DOM 事件: - -### Event: 'load-commit' - -返回: - -* `url` String -* `isMainFrame` Boolean - -加载完成触发. 这个包含当前文档的导航和副框架的文档加载,但是不包含异步资源加载. - -### Event: 'did-finish-load' - -在导航加载完成时触发,也就是tab 的 spinner停止spinning,并且加载事件处理. - -### Event: 'did-fail-load' - -Returns: - -* `errorCode` Integer -* `errorDescription` String -* `validatedURL` String - -类似 `did-finish-load` ,在加载失败或取消是触发,例如提出 `window.stop()`. - -### Event: 'did-frame-finish-load' - -返回: - -* `isMainFrame` Boolean - -当一个 frame 完成 加载时触发. - -### Event: 'did-start-loading' - -开始加载时触发. - -### Event: 'did-stop-loading' - -停止家在时触发. - -### Event: 'did-get-response-details' - -返回: - -* `status` Boolean -* `newURL` String -* `originalURL` String -* `httpResponseCode` Integer -* `requestMethod` String -* `referrer` String -* `headers` Object -* `resourceType` String - -当获得返回详情的时候触发. - -`status` 指示 socket 连接来下载资源. - -### Event: 'did-get-redirect-request' - -返回: - -* `oldURL` String -* `newURL` String -* `isMainFrame` Boolean - -当重定向请求资源被接收的时候触发. - -### Event: 'dom-ready' - -当指定的frame文档加载完毕时触发. - -### Event: 'page-title-updated' - -返回: - -* `title` String -* `explicitSet` Boolean - -当导航中的页面title被设置时触发. -在title通过文档路径异步加载时`explicitSet`为false. - -### Event: 'page-favicon-updated' - -返回: - -* `favicons` Array - Array of URLs. - -当page收到了图标url时触发. - -### Event: 'enter-html-full-screen' - -当通过HTML API使界面进入全屏时触发. - -### Event: 'leave-html-full-screen' - -当通过HTML API使界面退出全屏时触发. - -### Event: 'console-message' - -返回: - -* `level` Integer -* `message` String -* `line` Integer -* `sourceId` String - -当客户端输出控制台信息的时候触发. - -下面示例代码将所有信息输出到内置控制台,没有考虑到输出等级和其他属性。 - -```javascript -webview.addEventListener('console-message', function(e) { - console.log('Guest page logged a message:', e.message); -}); -``` - -### Event: 'found-in-page' - -返回: - -* `result` Object - * `requestId` Integer - * `finalUpdate` Boolean - 指明下面是否还有更多的回应. - * `activeMatchOrdinal` Integer (可选) - 活动匹配位置 - * `matches` Integer (optional) - 匹配数量. - * `selectionArea` Object (optional) - 整合第一个匹配域. - -在请求[`webview.findInPage`](web-view-tag.md#webviewtagfindinpage)结果有效时触发. - -```javascript -webview.addEventListener('found-in-page', function(e) { - if (e.result.finalUpdate) - webview.stopFindInPage("keepSelection"); -}); - -const rquestId = webview.findInPage("test"); -``` - -### Event: 'new-window' - -返回: - -* `url` String -* `frameName` String -* `disposition` String - 可以为 `default`, `foreground-tab`, `background-tab`, - `new-window` 和 `other`. -* `options` Object - 参数应该被用作创建新的 - `BrowserWindow`. - -在 guest page 试图打开一个新的浏览器窗口时触发. - -下面示例代码在系统默认浏览器中打开了一个新的url. - -```javascript -webview.addEventListener('new-window', function(e) { - require('electron').shell.openExternal(e.url); -}); -``` - -### Event: 'will-navigate' - -返回: - -* `url` String - -当用户或page尝试开始导航时触发. -它能在 `window.location` 变化或者用户点击连接的时候触发. - -这个事件在以 APIS 编程方式开始导航时不会触发,例如 `.loadURL` 和 `.back`. - -在页面内部导航跳转也将不回触发这个事件,例如点击锚链接或更新 `window.location.hash`.使用 `did-navigate-in-page` 来实现页内跳转事件. - -使用 `event.preventDefault()` 并不会起什么用. - -### Event: 'did-navigate' - -返回: - -* `url` String - -当导航结束时触发. - -在页面内部导航跳转也将不回触发这个事件,例如点击锚链接或更新 `window.location.hash`.使用 `did-navigate-in-page` 来实现页内跳转事件. - -### Event: 'did-navigate-in-page' - -返回: - -* `url` String - -当页内导航发生时触发. -当业内导航发生时,page url改变了,但是不会跳出 page . 例如在锚链接被电击或DOM `hashchange` 事件发生时触发. - -### Event: 'close' - -在 guest page试图关闭自己的时候触发. - -下面的示例代码指示了在客户端试图关闭自己的时候将改变导航连接为`about:blank`. - -```javascript -webview.addEventListener('close', function() { - webview.src = 'about:blank'; -}); -``` - -### Event: 'ipc-message' - -返回: - -* `channel` String -* `args` Array - -在 guest page 向嵌入页发送一个异步消息的时候触发. - -你可以很简单的使用 `sendToHost` 方法和 `ipc-message` 事件在 guest page 和 嵌入页(embedder page)之间通信: - -```javascript -// In embedder page. -webview.addEventListener('ipc-message', function(event) { - console.log(event.channel); - // Prints "pong" -}); -webview.send('ping'); -``` - -```javascript -// In guest page. -var ipcRenderer = require('electron').ipcRenderer; -ipcRenderer.on('ping', function() { - ipcRenderer.sendToHost('pong'); -}); -``` - -### Event: 'crashed' - -在渲染进程崩溃的时候触发. - -### Event: 'gpu-crashed' - -在GPU进程崩溃的时候触发. - -### Event: 'plugin-crashed' - -返回: - -* `name` String -* `version` String - -在插件进程崩溃的时候触发. - -### Event: 'destroyed' - -在界面内容销毁的时候触发. - -### Event: 'media-started-playing' - -在媒体准备播放的时候触发. - -### Event: 'media-paused' - -在媒体暂停播放或播放放毕的时候触发. - -### Event: 'did-change-theme-color' - -在页面的主体色改变的时候触发. -在使用 meta 标签的时候这就很常见了: - -```html - -``` - -### Event: 'devtools-opened' - -在开发者工具打开的时候触发. - -### Event: 'devtools-closed' - -在开发者工具关闭的时候触发. - -### Event: 'devtools-focused' - -在开发者工具获取焦点的时候触发. - -[blink-feature-string]: https://code.google.com/p/chromium/codesearch#chromium/src/out/Debug/gen/blink/platform/RuntimeEnabledFeatures.cpp&sq=package:chromium&type=cs&l=527 \ No newline at end of file diff --git a/docs-translations/zh-CN/api/window-open.md b/docs-translations/zh-CN/api/window-open.md deleted file mode 100644 index 069e2c3522639..0000000000000 --- a/docs-translations/zh-CN/api/window-open.md +++ /dev/null @@ -1,60 +0,0 @@ -# `window.open` 函数 - -当在界面中使用 `window.open` 来创建一个新的窗口时候,将会创建一个 `BrowserWindow` 的实例,并且将返回一个标识,这个界面通过标识来对这个新的窗口进行有限的控制. - -这个标识对传统的web界面来说,通过它能对子窗口进行有限的功能性兼容控制. -想要完全的控制这个窗口,可以直接创建一个 `BrowserWindow` . - -新创建的 `BrowserWindow` 默认为继承父窗口的属性参数,想重写属性的话可以在 `features` 中设置他们. - -### `window.open(url[, frameName][, features])` - -* `url` String -* `frameName` String (可选) -* `features` String (可选) - -创建一个新的window并且返回一个 `BrowserWindowProxy` 类的实例. - - `features` 遵循标准浏览器的格式,但是每个feature 应该作为 `BrowserWindow` 参数的一个字段. - -### `window.opener.postMessage(message, targetOrigin)` - -* `message` String -* `targetOrigin` String - -通过指定位置或用 `*` 来代替没有明确位置来向父窗口发送信息. - -## Class: BrowserWindowProxy - -`BrowserWindowProxy` 由`window.open` 创建返回,并且提供了对子窗口的有限功能性控制. - -### `BrowserWindowProxy.blur()` - -子窗口的失去焦点. -### `BrowserWindowProxy.close()` - -强行关闭子窗口,忽略卸载事件. - -### `BrowserWindowProxy.closed` - -在子窗口关闭之后恢复正常. - -### `BrowserWindowProxy.eval(code)` - -* `code` String - -评估子窗口的代码. - -### `BrowserWindowProxy.focus()` - -子窗口获得焦点(让其显示在最前). - -### `BrowserWindowProxy.postMessage(message, targetOrigin)` - -* `message` String -* `targetOrigin` String - - -通过指定位置或用 `*` 来代替没有明确位置来向子窗口发送信息. - -除了这些方法,子窗口还可以无特性和使用单一方法来实现 `window.opener` 对象. \ No newline at end of file diff --git a/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md b/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md deleted file mode 100644 index 68fddb11d237b..0000000000000 --- a/docs-translations/zh-CN/development/atom-shell-vs-node-webkit.md +++ /dev/null @@ -1,31 +0,0 @@ -# Electron 和 NW.js (原名 node-webkit) 在技术上的差异 - -__备注:Electron 的原名是 Atom Shell。__ - -与 NW.js 相似,Electron 提供了一个能通过 JavaScript 和 HTML 创建桌面应用的平台,同时集成 Node 来授予网页访问底层系统的权限。 - -但是这两个项目也有本质上的区别,使得 Electron 和 NW.js 成为两个相互独立的产品。 - -__1. 应用的入口__ - -在 NW.js 中,一个应用的主入口是一个页面。你在 `package.json` 中指定一个主页面,它会作为应用的主窗口被打开。 - -在 Electron 中,入口是一个 JavaScript 脚本。不同于直接提供一个URL,你需要手动创建一个浏览器窗口,然后通过 API 加载 HTML 文件。你还可以监听窗口事件,决定何时让应用退出。 - -Electron 的工作方式更像 Node.js 运行时。 Electron 的 APIs 更加底层,因此你可以用它替代 [PhantomJS](http://phantomjs.org/) 做浏览器测试。 - -__2. 构建系统__ - -为了避免构建整个 Chromium 带来的复杂度,Electron 通过 [`libchromiumcontent`](https://github.com/brightray/libchromiumcontent) 来访问 Chromium 的 Content API。`libchromiumcontent` 是一个独立的、引入了 Chromium Content 模块及其所有依赖的共享库。用户不需要一个强劲的机器来构建 Electron。 - -__3. Node 集成__ - -在 NW.js,网页中的 Node 集成需要通过给 Chromium 打补丁来实现。但在 Electron 中,我们选择了另一种方式:通过各个平台的消息循环与 libuv 的循环集成,避免了直接在 Chromium 上做改动。你可以看 [`node_bindings`][node-bindings] 来了解这是如何完成的。 - -__4. 多上下文__ - -如果你是有经验的 NW.js 用户,你应该会熟悉 Node 上下文和 web 上下文的概念。这些概念的产生源于 NW.js 的实现方式。 - -通过使用 Node 的[多上下文](http://strongloop.com/strongblog/whats-new-node-js-v0-12-multiple-context-execution/)特性,Electron不需要在网页中引入新的 JavaScript 上下文。 - -[node-bindings]: https://github.com/electron/electron/tree/master/atom/common diff --git a/docs-translations/zh-CN/development/build-instructions-linux.md b/docs-translations/zh-CN/development/build-instructions-linux.md deleted file mode 100644 index 9815aeb03e5fe..0000000000000 --- a/docs-translations/zh-CN/development/build-instructions-linux.md +++ /dev/null @@ -1,123 +0,0 @@ -# Build Instructions (Linux) - -遵循下面的引导,在 Linux 上构建 Electron . - -## Prerequisites - -* Python 2.7.x. 一些发行版如 CentOS 仍然使用 Python 2.6.x ,所以或许需要 check 你的 Python 版本,使用 `python -V`. -* Node.js v0.12.x. 有很多方法来安装 Node. 可以从 [Node.js](http://nodejs.org)下载原文件并且编译它 .也可以作为一个标准的用户在 home 目录下安装 node .或者尝试使用仓库 [NodeSource](https://nodesource.com/blog/nodejs-v012-iojs-and-the-nodesource-linux-repositories). -* Clang 3.4 或更新的版本. -* GTK+开发头文件和libnotify. - -在 Ubuntu, 安装下面的库 : - -```bash -$ sudo apt-get install build-essential clang libdbus-1-dev libgtk2.0-dev \ - libnotify-dev libgnome-keyring-dev libgconf2-dev \ - libasound2-dev libcap-dev libcups2-dev libxtst-dev \ - libxss1 libnss3-dev gcc-multilib g++-multilib -``` - -在 Fedora, 安装下面的库 : - -```bash -$ sudo yum install clang dbus-devel gtk2-devel libnotify-devel libgnome-keyring-devel \ - xorg-x11-server-utils libcap-devel cups-devel libXtst-devel \ - alsa-lib-devel libXrandr-devel GConf2-devel nss-devel -``` - -其它版本的也许提供了相似的包来安装,通过包管理器,例如 pacman. -或一个可以编译源文件的. - -## 使用虚拟机 - -如果在虚拟机上构建 Electron,你需要一个固定大小的设备,至少需要 25 gigabytes . - -## 获取代码 - -```bash -$ git clone https://github.com/electron/electron.git -``` - -## Bootstrapping - -bootstrap 脚本也是必要下载的构建依赖,来创建项目文件.需要使用 Python 2.7.x 来让脚本成功执行.正确下载文件会花费较长的时间. -注意我们使用的是 `ninja` 来构建 Electron,所以没有生成 `Makefile` 项目. - -```bash -$ cd electron -$ ./script/bootstrap.py -v -``` - -### 交叉编译 - -如果想创建一个 `arm` target ,应当还要下载下面的依赖 : - -```bash -$ sudo apt-get install libc6-dev-armhf-cross linux-libc-dev-armhf-cross \ - g++-arm-linux-gnueabihf -``` - -为了编译 `arm` 或 `ia32` targets, 你应当为 `bootstrap.py` 脚本使用 -`--target_arch` 参数: - -```bash -$ ./script/bootstrap.py -v --target_arch=arm -``` - -## 构建 - -创建 `Release` 、 `Debug` target: - -```bash -$ ./script/build.py -``` - -这个脚本也许会在目录 `out/R` 下创建一个巨大的可执行的 Electron . 文件大小或许会超过 1.3 gigabytes. 原因是 Release target 二进制文件包含了 调试符号 .运行 `create-dist.py` 脚本来减小文件的 size : - -```bash -$ ./script/create-dist.py -``` -这会在 `dist` 目录下创建一个有大量小文件的工作空间. 运行 create-dist.py 脚本之后, 或许你想删除仍然在 `out/R` 下的 1.3+ gigabyte 二进制文件. - -可以只创建 `Debug` target: - -```bash -$ ./script/build.py -c D -``` - -创建完毕, 可以在 `out/D`下面找到 `electron`. - -## Cleaning - -删除构建文件 : - -```bash -$ ./script/clean.py -``` - -## 解决问题 - -确保你已经安装了所有的依赖 . - -### Error While Loading Shared Libraries: libtinfo.so.5 - -预构建的 `clang` 会尝试链接到 `libtinfo.so.5`. 取决于 host 架构, 适当的使用 `libncurses`: - -```bash -$ sudo ln -s /usr/lib/libncurses.so.5 /usr/lib/libtinfo.so.5 -``` - -## Tests - -测试你的修改是否符合项目代码风格,使用: - -```bash -$ ./script/cpplint.py -``` - -测试有效性使用: - -```bash -$ ./script/test.py -``` \ No newline at end of file diff --git a/docs-translations/zh-CN/development/build-instructions-osx.md b/docs-translations/zh-CN/development/build-instructions-osx.md deleted file mode 100644 index f9992c929958e..0000000000000 --- a/docs-translations/zh-CN/development/build-instructions-osx.md +++ /dev/null @@ -1,62 +0,0 @@ -# Build Instructions (macOS) - -遵循下面的引导,在 macOS 上构建 Electron . - -## 前提 - -* macOS >= 10.8 -* [Xcode](https://developer.apple.com/technologies/tools/) >= 5.1 -* [node.js](http://nodejs.org) (外部) - -如果你目前使用的Python是通过 Homebrew 安装的,则你还需要安装如下Python模块: - -* pyobjc - -## 获取代码 - -```bash -$ git clone https://github.com/electron/electron.git -``` - -## Bootstrapping - -bootstrap 脚本也是必要下载的构建依赖,来创建项目文件.注意我们使用的是 [ninja](https://ninja-build.org/) 来构建 Electron,所以没有生成 Xcode 项目. - -```bash -$ cd electron -$ ./script/bootstrap.py -v -``` - -## 构建 - -创建 `Release` 、 `Debug` target: - -```bash -$ ./script/build.py -``` - -可以只创建 `Debug` target: - -```bash -$ ./script/build.py -c D -``` - -创建完毕, 可以在 `out/D` 下面找到 `Electron.app`. - -## 32位支持 - -在 macOS 上,构建 Electron 只支持 64位的,不支持 32位的 . - -## 测试 - -测试你的修改是否符合项目代码风格,使用: - -```bash -$ ./script/cpplint.py -``` - -测试有效性使用: - -```bash -$ ./script/test.py -``` diff --git a/docs-translations/zh-CN/development/build-instructions-windows.md b/docs-translations/zh-CN/development/build-instructions-windows.md deleted file mode 100644 index 4333620a560b4..0000000000000 --- a/docs-translations/zh-CN/development/build-instructions-windows.md +++ /dev/null @@ -1,136 +0,0 @@ -# Build Instructions (Windows) - -遵循下面的引导,在 Windows 上构建 Electron . - -## 前提 - -* Windows 7 / Server 2008 R2 or higher -* Visual Studio 2015 - [download VS 2015 Community Edition for - free](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) -* [Python 2.7](http://www.python.org/download/releases/2.7/) -* [Node.js](http://nodejs.org/download/) -* [Git](http://git-scm.com) - -如果你现在还没有安装 Windows , [modern.ie](https://www.modern.ie/en-us/virtualization-tools#downloads) 有一个 timebombed 版本的 Windows ,你可以用它来构建 Electron. - -构建 Electron 完全的依赖于命令行,并且不可通过 Visual Studio. -可以使用任何的编辑器来开发 Electron ,未来会支持 Visual Studio. - -**注意:** 虽然 Visual Studio 不是用来构建的,但是它仍然 -**必须的** ,因为我们需要它提供的构建工具栏. - -**注意:** Visual Studio 2013 不可用. 请确定使用 MSVS -**2015**. - -## 获取代码 - -```powershell -$ git clone https://github.com/electron/electron.git -``` - -## Bootstrapping - -bootstrap 脚本也是必要下载的构建依赖,来创建项目文件.注意我们使用的是 `ninja` 来构建 Electron,所以没有生成 Visual Studio 项目. - -```powershell -$ cd electron -$ python script\bootstrap.py -v -``` - -## 构建 - -创建 `Release` 、 `Debug` target: - -```powershell -$ python script\build.py -``` - -可以只创建 `Debug` target: - -```powershell -$ python script\build.py -c D -``` - -创建完毕, 可以在 `out/D`(debug target) 或 `out\R` (release target) 下面找到 `electron.exe`. - -## 64bit Build - -为了构建64位的 target,在运行 bootstrap 脚本的时候需要使用 `--target_arch=x64` : - -```powershell -$ python script\bootstrap.py -v --target_arch=x64 -``` - -其他构建步骤完全相同. - -## Tests - -测试你的修改是否符合项目代码风格,使用: - -```powershell -$ python script\cpplint.py -``` - -测试有效性使用: - -```powershell -$ python script\test.py -``` -在构建 debug 时为 Tests包含原生模块 (例如 `runas`) 将不会执行(详情 [#2558](https://github.com/electron/electron/issues/2558)), 但是它们在构建 release 会起效. - -运行 release 构建使用 : - -```powershell -$ python script\test.py -R -``` - -## 解决问题 - -### Command xxxx not found - -如果你遇到了一个错误,类似 `Command xxxx not found`, 可以尝试使用 `VS2012 Command Prompt` 控制台来执行构建脚本 . - -### Fatal internal compiler error: C1001 - -确保你已经安装了 Visual Studio 的最新安装包 . - -### Assertion failed: ((handle))->activecnt >= 0 - -如果在 Cygwin 下构建的,你可能会看到 `bootstrap.py` 失败并且附带下面错误 : - -``` -Assertion failed: ((handle))->activecnt >= 0, file src\win\pipe.c, line 1430 - -Traceback (most recent call last): - File "script/bootstrap.py", line 87, in - sys.exit(main()) - File "script/bootstrap.py", line 22, in main - update_node_modules('.') - File "script/bootstrap.py", line 56, in update_node_modules - execute([NPM, 'install']) - File "/home/zcbenz/codes/raven/script/lib/util.py", line 118, in execute - raise e -subprocess.CalledProcessError: Command '['npm.cmd', 'install']' returned non-zero exit status 3 -``` - -这是由同时使用 Cygwin Python 和 Win32 Node 造成的 bug.解决办法就是使用 Win32 Python 执行 bootstrap 脚本 (假定你已经在目录 `C:\Python27` 下安装了 Python): - -```powershell -$ /cygdrive/c/Python27/python.exe script/bootstrap.py -``` - -### LNK1181: cannot open input file 'kernel32.lib' - -重新安装 32位的 Node.js. - -### Error: ENOENT, stat 'C:\Users\USERNAME\AppData\Roaming\npm' - -简单创建目录 [应该可以解决问题](http://stackoverflow.com/a/25095327/102704): - -```powershell -$ mkdir ~\AppData\Roaming\npm -``` - -### node-gyp is not recognized as an internal or external command - -如果你使用 Git Bash 来构建,或许会遇到这个错误,可以使用 PowerShell 或 VS2015 Command Prompt 来代替 . \ No newline at end of file diff --git a/docs-translations/zh-CN/development/build-system-overview.md b/docs-translations/zh-CN/development/build-system-overview.md deleted file mode 100644 index 6bd1452b81643..0000000000000 --- a/docs-translations/zh-CN/development/build-system-overview.md +++ /dev/null @@ -1,42 +0,0 @@ -# Build System Overview - -Electron 使用 [gyp](https://gyp.gsrc.io/) 来生成项目 ,使用 [ninja](https://ninja-build.org/) 来构建项目. 项目配置可以在 `.gyp` 和 `.gypi` 文件中找到. - -## Gyp 文件 - -下面的 `gyp` 文件包含了构建 Electron 的主要规则 : - -* `atom.gyp` 定义了 Electron 它自己是怎样被构建的. -* `common.gypi` 调整 node 的构建配置,来让它结合 Chromium 一起构建. -* `vendor/brightray/brightray.gyp` 定义了 `brightray` 是如何被构建的,并且包含了默认配置来连接到 Chromium. -* `vendor/brightray/brightray.gypi` 包含了常用的创建配置. - -## 创建组件 - -在 Chromium 还是一个相当大的项目的时候,最后链接阶段会花了好几分钟,这让开发变得很困难. 为了解决这个困难,Chromium 引入了 "component build" ,这让每个创建的组建都是分隔开的共享库,让链接更快,但是这浪费了文件大小和性能. - -在 Electron 中,我们采用了一个非常相似的方法 : 在创建 `Debug` , 二进制文件会被链接进入一个 Chromium 组件的共享版本库来达到快速链接; 在创建 `Release`, 二进制文件会被链接进入一个静态版本库, 所以我们可以有最小的二进制文件size和最佳的体验. - -## Minimal Bootstrapping - -在运行 bootstrap 脚本的时候,所有的 Chromium 预编译二进制文件会被下载.默认静态库和共享库会被下载,并且项目的最后大小会在 800MB 到 2GB 之间,这取决于平台类型. - -默认,`libchromiumcontent` 是从 Amazon Web Services 上下载下来的.如果设置了 `LIBCHROMIUMCONTENT_MIRROR` 环境变量,bootstrap脚本会从这里下载下来. [`libchromiumcontent-qiniu-mirror`](https://github.com/hokein/libchromiumcontent-qiniu-mirror) 是 `libchromiumcontent` 的映射.如果你不能连接 AWS,你可以切换下载路径:`export LIBCHROMIUMCONTENT_MIRROR=http://7xk3d2.dl1.z0.glb.clouddn.com/` -如果只是想快速搭建一个 Electron 的测试或开发环境,可以通过 `--dev` 参数只下载共享版本库: - -```bash -$ ./script/bootstrap.py --dev -$ ./script/build.py -c D -``` - -## Two-Phase Project Generation - -在 `Release` 和 `Debug` 构建的时候后,Electron 链接了不同配置的库 .然而 `gyp`不支持为不同的配置文件进行不同的链接设置. - -为了规避这个问题,Electron 在运行 `gyp` 的时候,使用了一个 `gyp` 的变量 `libchromiumcontent_component`来控制应该使用哪个链接设置,并且只生成一个目标. - -## Target Names - -与大多数的项目不同,它们使用 `Release` 和 `Debug` 作为目标名字,而 Electron 使用使用的是 `R` 和 `D`.这是因为如果只定义了一个 `Release` 或 `Debug` 构建配置,`gyp` 会随机崩溃,并且在同一时候,Electron 只生成一个目标,如上所述. - -这只对开发者可用,如果想重新构建 Electron ,将不会成功. \ No newline at end of file diff --git a/docs-translations/zh-CN/development/coding-style.md b/docs-translations/zh-CN/development/coding-style.md deleted file mode 100644 index f293ece40de71..0000000000000 --- a/docs-translations/zh-CN/development/coding-style.md +++ /dev/null @@ -1,23 +0,0 @@ -# 编码规范 - -以下是 Electron 项目的编码规范。 - -## C++ 和 Python - -对于 C++ 和 Python,我们遵循 Chromium 的[编码规范](http://www.chromium.org/developers/coding-style)。你可以使用 `script/cpplint.py` 来检验文件是否符合要求。 - -我们目前使用的 Python 版本是 Python 2.7。 - -C++ 代码中用到了许多 Chromium 中的接口和数据类型,所以希望你能熟悉它们。Chromium 中的[重要接口和数据结构](https://www.chromium.org/developers/coding-style/important-abstractions-and-data-structures)就是一篇不错的入门文档,里面提到了一些特殊类型、域内类型(退出作用域时自动释放内存)、日志机制,等等。 - -## CoffeeScript - -对于 CoffeeScript,我们遵循 GitHub 的[编码规范](https://github.com/styleguide/javascript) 及以下规则: - -* 文件**不要**以换行符结尾,我们要遵循 Google 的编码规范。 -* 文件名使用 `-` 而不是 `_` 来连接单词,比如 `file-name.coffee` 而不是 `file_name.coffee`,这是沿用 [github/atom](https://github.com/github/atom) 模块的命名方式(`module-name`)。这条规则仅适用于 `.coffee` 文件。 - -## API 命名 - -当新建一个 API 时,我们倾向于使用 getters 和 setters 而不是 jQuery 单函数的命名方式,比如 `.getText()` 和 `.setText(text)` - 而不是 `.text([text])`。这里有关于该规则的[讨论记录](https://github.com/electron/electron/issues/46)。 diff --git a/docs-translations/zh-CN/development/setting-up-symbol-server.md b/docs-translations/zh-CN/development/setting-up-symbol-server.md deleted file mode 100644 index f1104496de6a2..0000000000000 --- a/docs-translations/zh-CN/development/setting-up-symbol-server.md +++ /dev/null @@ -1,38 +0,0 @@ -# Setting Up Symbol Server in Debugger - -调试 symbols 让你有更好的调试 sessions. 它们有可执行的动态库的函数信息,并且提供信息来获得洁净的呼叫栈. 一个 Symbol 服务器允许调试器自动加载正确的 symbols, 二进制文件 和 资源文件,不用再去强制用户下载巨大的调试文件. 服务器函数类似 -[Microsoft's symbol server](http://support.microsoft.com/kb/311503) ,所以这里的记录可用. - -注意,因为公众版本的 Electron 构建是最优化的,调试不一定一直简单.调试器将不会给显示出所有变量内容,并且因为内联,尾调用,和其它编译器优化,执行路径会看起来很怪异 . 唯一的解决办法是搭建一个不优化的本地构建. - -Electron 使用的官方 symbol 服务器地址为 -`http://54.249.141.255:8086/atom-shell/symbols` . -你不能直接访问这个路径,必须将其添加到你的调试工具的 symbol 路径上.在下面的例子中,使用了一个本地缓存目录来避免重复从服务器获取 PDB. 在你的电脑上使用一个恰当的缓存目录来代替 `c:\code\symbols` . - -## Using the Symbol Server in Windbg - -Windbg symbol 路径被配制为一个限制带星号字符的字符串. 要只使用 Electron 的 symbol 服务器, 将下列记录添加到你的 symbol 路径 (__注意:__ 如果你愿意使用一个不同的地点来下载 symbols,你可以在你的电脑中使用任何可写的目录来代替 `c:\code\symbols`): - -``` -SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols -``` - -使用 Windbg 菜单或通过输入 `.sympath` 命令,在环境中设置一个 `_NT_SYMBOL_PATH` 字符串.如果你也想从微软的 symbol 服务器获得 symbols ,你应当首先将它们先列出来 : - -``` -SRV*c:\code\symbols\*http://msdl.microsoft.com/download/symbols;SRV*c:\code\symbols\*http://54.249.141.255:8086/atom-shell/symbols -``` - -## 在 Visual Studio 中使用 symbol 服务器 - - - - -## Troubleshooting: Symbols will not load - -在 Windbg 中输入下列命令,打印出为什么 symbols 没有加载 : - -``` -> !sym noisy -> .reload /f chromiumcontent.dll -``` diff --git a/docs-translations/zh-CN/development/source-code-directory-structure.md b/docs-translations/zh-CN/development/source-code-directory-structure.md deleted file mode 100644 index fd3676c2e988d..0000000000000 --- a/docs-translations/zh-CN/development/source-code-directory-structure.md +++ /dev/null @@ -1,53 +0,0 @@ -# 源码目录结构 - -Electron 的源代码主要依据 Chromium 的拆分约定被拆成了许多部分。 - -为了更好地理解源代码,您可能需要了解一下 -[Chromium 的多进程架构](http://dev.chromium.org/developers/design-documents/multi-process-architecture)。 - -## 源代码的结构 - -``` -Electron -├──atom - Electron 的源代码 -| ├── app - 系统入口代码 -| ├── browser - 包含了主窗口、UI 和其他所有与主进程有关的东西,它会告诉渲染进程如何管理页面 -| |   ├── lib - 主进程初始化代码中 JavaScript 部分的代码 -| | ├── ui - 不同平台上 UI 部分的实现 -| | | ├── cocoa - Cocoa 部分的源代码 -| | | ├── gtk - GTK+ 部分的源代码 -| | | └── win - Windows GUI 部分的源代码 -| | ├── default_app - 在没有指定 app 的情况下 Electron 启动时默认显示的页面 -| | ├── api - 主进程 API 的实现 -| | | └── lib - API 实现中 Javascript 部分的代码 -| | ├── net - 网络相关的代码 -| | ├── mac - 与 Mac 有关的 Objective-C 代码 -| | └── resources - 图标,平台相关的文件等 -| ├── renderer - 运行在渲染进程中的代码 -| | ├── lib - 渲染进程初始化代码中 JavaScript 部分的代码 -| | └── api - 渲染进程 API 的实现 -| | └── lib - API 实现中 Javascript 部分的代码 -| └── common - 同时被主进程和渲染进程用到的代码,包括了一些用来将 node 的事件循环 -| | 整合到 Chromium 的事件循环中时用到的工具函数和代码 -| ├── lib - 同时被主进程和渲染进程使用到的 Javascript 初始化代码 -| └── api - 同时被主进程和渲染进程使用到的 API 的实现以及 Electron 内置模块的基础设施 -| └── lib - API 实现中 Javascript 部分的代码 -├── chromium_src - 从 Chromium 项目中拷贝来的代码 -├── docs - 英语版本的文档 -├── docs-translations - 各种语言版本的文档翻译 -├── spec - 自动化测试 -├── atom.gyp - Electron 的构建规则 -└── common.gypi - 为诸如 `node` 和 `breakpad` 等其他组件准备的编译设置和构建规则 -``` - -## 其他目录的结构 - -* **script** - 用于诸如构建、打包、测试等开发用途的脚本 -* **tools** - 在 gyp 文件中用到的工具脚本,但与 `script` 目录不同, - 该目录中的脚本不应该被用户直接调用 -* **vendor** - 第三方依赖项的源代码,为了防止人们将它与 Chromium 源码中的同名目录相混淆, - 在这里我们不使用 `third_party` 作为目录名 -* **node_modules** - 在构建中用到的第三方 node 模块 -* **out** - `ninja` 的临时输出目录 -* **dist** - 由脚本 `script/create-dist.py` 创建的临时发布目录 -* **external_binaries** - 下载的不支持通过 `gyp` 构建的预编译第三方框架 diff --git a/docs-translations/zh-CN/faq/electron-faq.md b/docs-translations/zh-CN/faq/electron-faq.md deleted file mode 100644 index 6c13dcdf5094f..0000000000000 --- a/docs-translations/zh-CN/faq/electron-faq.md +++ /dev/null @@ -1,139 +0,0 @@ -# Electron 常见问题 - -## Electron 会在什么时候升级到最新版本的 Chrome? - -通常来说,在稳定版的 Chrome 发布后两周内,我们会更新 Electron 内的 Chrome 版本。 - -我们只会使用 stable 版本的 Chrome。但如果在 beta 或 dev 版本中有一个重要的更新,我们会把补丁应用到现版本的 Chrome 上。 - -## Electron 会在什么时候升级到最新版本的 Node.js? - -我们通常会在最新版的 Node.js 发布后一个月左右将 Electron 更新到这个版本的 Node.js。我们通过这种方式来避免新版本的 Node.js -带来的 bug(这种 bug 太常见了)。 - -Node.js 的新特性通常是由新版本的 V8 带来的。由于 Electron 使用的是 Chrome 浏览器中附带的 V8 引擎,所以 Electron 内往往已经 -有了部分新版本 Node.js 才有的崭新特性。 - -## 如何在两个网页间共享数据? - -在两个网页(渲染进程)间共享数据最简单的方法是使用浏览器中已经实现的 HTML5 API,比较好的方案是用 [Storage API][storage], -[`localStorage`][local-storage],[`sessionStorage`][session-storage] 或者 [IndexedDB][indexed-db]。 - -你还可以用 Electron 内的 IPC 机制实现。将数据存在主进程的某个全局变量中,然后在多个渲染进程中使用 `remote` 模块来访问它。 - -```javascript -// 在主进程中 -global.sharedObject = { - someProperty: 'default value' -}; -``` - -```javascript -// 在第一个页面中 -require('remote').getGlobal('sharedObject').someProperty = 'new value'; -``` - -```javascript -// 在第二个页面中 -console.log(require('remote').getGlobal('sharedObject').someProperty); -``` - -## 为什么应用的窗口、托盘在一段时间后不见了? - -这通常是因为用来存放窗口、托盘的变量被垃圾收集了。 - -你可以参考以下两篇文章来了解为什么会遇到这个问题。 - -* [内存管理][memory-management] -* [变量作用域][variable-scope] - -如果你只是要一个快速的修复方案,你可以用下面的方式改变变量的作用域,防止这个变量被垃圾收集。 - -从 - -```javascript -app.on('ready', function() { - var tray = new Tray('/path/to/icon.png'); -}) -``` - -改为 - -```javascript -var tray = null; -app.on('ready', function() { - tray = new Tray('/path/to/icon.png'); -}) -``` - -## 在 Electron 中,我为什么不能用 jQuery、RequireJS、Meteor、AngularJS? - -因为 Electron 在运行环境中引入了 Node.js,所以在 DOM 中有一些额外的变量,比如 `module`、`exports` 和 `require`。这导致 -了许多库不能正常运行,因为它们也需要将同名的变量加入运行环境中。 - -我们可以通过禁用 Node.js 来解决这个问题,用如下的方式: - -```javascript -// 在主进程中 -var mainWindow = new BrowserWindow({ - webPreferences: { - nodeIntegration: false - } -}); -``` - -假如你依然需要使用 Node.js 和 Electron 提供的 API,你需要在引入那些库之前将这些变量重命名,比如: - -```html - - - - -``` - -## 为什么 `require('electron').xxx` 的结果是 undefined? - -在使用 Electron 的提供的模块时,你可能会遇到和以下类似的错误: - -``` -> require('electron').webFrame.setZoomFactor(1.0); -Uncaught TypeError: Cannot read property 'setZoomLevel' of undefined -``` - -这是因为你在项目中或者在全局中安装了[npm 上获取的 `electron` 模块][electron-module],它把 Electron 的内置模块覆写了。 - -你可以通过以下方式输出 `electron` 模块的路径来确认你是否使用了正确的模块。 - -```javascript -console.log(require.resolve('electron')); -``` - -确认一下它是不是像下面这样的: - -``` -"/path/to/Electron.app/Contents/Resources/atom.asar/renderer/api/lib/exports/electron.js" -``` - -假如输出的路径类似于 `node_modules/electron/index.js`,那么你需要移除或者重命名 npm 上的 `electron` 模块。 - -```bash -npm uninstall electron -npm uninstall -g electron -``` - -如果你依然遇到了这个问题,你可能需要检查一下拼写或者是否在错误的进程中调用了这个模块。比如, -`require('electron').app` 只能在主进程中使用, 然而 `require('electron').webFrame` 只能在渲染进程中使用。 - -[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 -[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 diff --git a/docs-translations/zh-CN/tutorial/application-distribution.md b/docs-translations/zh-CN/tutorial/application-distribution.md deleted file mode 100644 index 07c9c0d8748ee..0000000000000 --- a/docs-translations/zh-CN/tutorial/application-distribution.md +++ /dev/null @@ -1,110 +0,0 @@ -# 应用部署 - -为了使用 Electron 部署你的应用程序,你存放应用程序的文件夹需要叫做 `app` 并且需要放在 Electron 的 -资源文件夹下(在 macOS 中是指 `Electron.app/Contents/Resources/`,在 Linux 和 Windows 中是指 `resources/`) -就像这样: - -在 macOS 中: - -```text -electron/Electron.app/Contents/Resources/app/ -├── package.json -├── main.js -└── index.html -``` - -在 Windows 和 Linux 中: - -```text -electron/resources/app -├── package.json -├── main.js -└── index.html -``` - -然后运行 `Electron.app` (或者 Linux 中的 `electron`,Windows 中的 `electron.exe`), -接着 Electron 就会以你的应用程序的方式启动。`electron` 文件夹将被部署并可以分发给最终的使用者。 - -## 将你的应用程序打包成一个文件 - -除了通过拷贝所有的资源文件来分发你的应用程序之外,你可以通过打包你的应用程序为一个 [asar](https://github.com/atom/asar) 库文件以避免暴露你的源代码。 - -为了使用一个 `asar` 库文件代替 `app` 文件夹,你需要修改这个库文件的名字为 `app.asar` , -然后将其放到 Electron 的资源文件夹下,然后 Electron 就会试图读取这个库文件并从中启动。 -如下所示: - -在 macOS 中: - -```text -electron/Electron.app/Contents/Resources/ -└── app.asar -``` - -在 Windows 和 Linux 中: - -```text -electron/resources/ -└── app.asar -``` - -更多的细节请见 [Application packaging](application-packaging.md). - -## 更换名称与下载二进制文件 - -在使用 Electron 打包你的应用程序之后,你可能需要在分发给用户之前修改打包的名字。 - -### Windows - -你可以将 `electron.exe` 改成任意你喜欢的名字,然后可以使用像 -[rcedit](https://github.com/atom/rcedit) -编辑它的 icon 和其他信息。 - -### macOS - -你可以将 `Electron.app` 改成任意你喜欢的名字,然后你也需要修改这些文件中的 -`CFBundleDisplayName`, `CFBundleIdentifier` 以及 `CFBundleName` 字段。 -这些文件如下: - -* `Electron.app/Contents/Info.plist` -* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` - -你也可以重命名帮助应用程序以避免在应用程序监视器中显示 `Electron Helper`, -但是请确保你已经修改了帮助应用的可执行文件的名字。 - -一个改过名字的应用程序的构造可能是这样的: - -``` -MyApp.app/Contents -├── Info.plist -├── MacOS/ -│   └── MyApp -└── Frameworks/ - ├── MyApp Helper EH.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper EH - ├── MyApp Helper NP.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper NP - └── MyApp Helper.app - ├── Info.plist - └── MacOS/ -    └── MyApp Helper -``` - -### Linux - -你可以将 `electron` 改成任意你喜欢的名字。 - -## 通过重编译源代码来更换名称 - -通过修改产品名称并重编译源代码来更换 Electron 的名称也是可行的。 -你需要修改 `atom.gyp` 文件并彻底重编译一次。 - -### grunt打包脚本 - -手动检查 Electron 代码并重编译是很复杂晦涩的,因此有一个Grunt任务可以自动的处理 -这些内容 [grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell). - -这个任务会自动的处理编辑 `.gyp` 文件,从源代码进行编译,然后重编译你的应用程序的本地 Node 模块以匹配这个新的可执行文件的名称。 diff --git a/docs-translations/zh-CN/tutorial/application-packaging.md b/docs-translations/zh-CN/tutorial/application-packaging.md deleted file mode 100644 index 13a24d2d1c339..0000000000000 --- a/docs-translations/zh-CN/tutorial/application-packaging.md +++ /dev/null @@ -1,155 +0,0 @@ -# 应用打包 - -为舒缓 Windows 下路径名过长的问题[issues](https://github.com/joyent/node/issues/6960), -也略对 `require` 加速以及简单隐匿你的源代码,你可以通过极小的源代码改动将你的应用打包成 [asar][asar]。 - -## 生成 `asar` 包 - -[asar][asar] 是一种将多个文件合并成一个文件的类 tar 风格的归档格式。 -Electron 可以无需解压,即从其中读取任意文件内容。 - -参照如下步骤将你的应用打包成 `asar`: - -### 1. 安装 asar - -```bash -$ npm install -g asar -``` - -### 2. 用 `asar pack` 打包 - -```bash -$ asar pack your-app app.asar -``` - -## 使用 `asar` 包 - -在 Electron 中有两类 APIs:Node.js 提供的 Node API 和 Chromium 提供的 Web API。 -这两种 API 都支持从 `asar` 包中读取文件。 - -### Node API - -由于 Electron 中打了特别补丁, Node API 中如 `fs.readFile` 或者 `require` 之类 -的方法可以将 `asar` 视之为虚拟文件夹,读取 `asar` 里面的文件就和从真实的文件系统中读取一样。 - -例如,假设我们在 `/path/to` 文件夹下有个 `example.asar` 包: - -```bash -$ asar list /path/to/example.asar -/app.js -/file.txt -/dir/module.js -/static/index.html -/static/main.css -/static/jquery.min.js -``` - -从 `asar` 包读取一个文件: - -```javascript -const fs = require('fs'); -fs.readFileSync('/path/to/example.asar/file.txt'); -``` - -列出 `asar` 包中根目录下的所有文件: - -```javascript -const fs = require('fs'); -fs.readdirSync('/path/to/example.asar'); -``` - -使用 `asar` 包中的一个模块: - -```javascript -require('/path/to/example.asar/dir/module.js'); -``` - -你也可以使用 `BrowserWindow` 来显示一个 `asar` 包里的 web 页面: - -```javascript -const BrowserWindow = require('electron').BrowserWindow; -var win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('file:///path/to/example.asar/static/index.html'); -``` - -### Web API - -在 Web 页面里,用 `file:` 协议可以获取 `asar` 包中文件。和 Node API 一样,视 `asar` 包如虚拟文件夹。 - -例如,用 `$.get` 获取文件: - -```html - -``` - -### 像“文件”那样处理 `asar` 包 - -有些场景,如:核查 `asar` 包的校验和,我们需要像读取“文件”那样读取 `asar` 包的内容(而不是当成虚拟文件夹)。 -你可以使用内置的 `original-fs` (提供和 `fs` 一样的 API)模块来读取 `asar` 包的真实信息。 - -```javascript -var originalFs = require('original-fs'); -originalFs.readFileSync('/path/to/example.asar'); -``` - -## Node API 缺陷 - -尽管我们已经尽了最大努力使得 `asar` 包在 Node API 下的应用尽可能的趋向于真实的目录结构,但仍有一些底层 Node API 我们无法保证其正常工作。 - -### `asar` 包是只读的 - -`asar` 包中的内容不可更改,所以 Node APIs 里那些可以用来修改文件的方法在对待 `asar` 包时都无法正常工作。 - -### Working Directory 在 `asar` 包中无效 - -尽管 `asar` 包是虚拟文件夹,但其实并没有真实的目录架构对应在文件系统里,所以你不可能将 working Directory -设置成 `asar` 包里的一个文件夹。将 `asar` 中的文件夹以 `cwd` 形式作为参数传入一些 API 中也会报错。 - -### API 中的额外“开箱” - -大部分 `fs` API 可以无需解压即从 `asar` 包中读取文件或者文件的信息,但是在处理一些依赖真实文件路径的底层 -系统方法时,Electron 会将所需文件解压到临时目录下,然后将临时目录下的真实文件路径传给底层系统方法使其正 -常工作。 对于这类API,耗费会略多一些。 - -以下是一些需要额外解压的 API: - -* `child_process.execFile` -* `child_process.execFileSync` -* `fs.open` -* `fs.openSync` -* `process.dlopen` - `require`native模块时用到 - -### `fs.stat` 获取的 stat 信息不可靠 - -对 `asar` 包中的文件取 `fs.stat`,返回的 `Stats` 对象不是精确值,因为这些文件不是真实存在于文件系 -统里。所以除了文件大小和文件类型以外,你不应该依赖 `Stats` 对象的值。 - -### 执行 `asar` 包中的程序 - -Node 中有一些可以执行程序的 API,如 `child_process.exec`,`child_process.spawn` 和 `child_process.execFile` 等, -但只有 `execFile` 可以执行 `asar` 包中的程序。 - -因为 `exec` 和 `spawn` 允许 `command` 替代 `file` 作为输入,而 `command` 是需要在 shell 下执行的,目前没有 -可靠的方法来判断 `command` 中是否在操作一个 `asar` 包中的文件,而且即便可以判断,我们依旧无法保证可以在无任何 -副作用的情况下替换 `command` 中的文件路径。 - -## 打包时排除文件 - -如上所述,一些 Node API 会在调用时将文件解压到文件系统中,除了效率问题外,也有可能引起杀毒软件的注意! - -为解决这个问题,你可以在生成 `asar` 包时使用 `--unpack` 选项来排除一些文件,使其不打包到 `asar` 包中, -下面是如何排除一些用作共享用途的 native 模块的方法: - -```bash -$ asar pack app app.asar --unpack *.node -``` - -经过上述命令后,除了生成的 `app.asar` 包以外,还有一个包含了排除文件的 `app.asar.unpacked` 文件夹, -你需要将这个文件夹一起拷贝,提供给用户。 - -[asar]: https://github.com/atom/asar diff --git a/docs-translations/zh-CN/tutorial/debugging-main-process.md b/docs-translations/zh-CN/tutorial/debugging-main-process.md deleted file mode 100644 index 361d7c2d57e0b..0000000000000 --- a/docs-translations/zh-CN/tutorial/debugging-main-process.md +++ /dev/null @@ -1,71 +0,0 @@ -# 主进程调试 - -浏览器窗口的开发工具仅能调试渲染器的进程脚本(比如 web 页面)。为了提供一个可以调试主进程 -的方法,Electron 提供了 `--debug` 和 `--debug-brk` 开关。 - -## 命令行开关 - -使用如下的命令行开关来调试 Electron 的主进程: - -### `--debug=[port]` - -当这个开关用于 Electron 时,它将会监听 V8 引擎中有关 `port` 的调试器协议信息。 -默认的 `port` 是 `5858`。 - -### `--debug-brk=[port]` - -就像 `--debug` 一样,但是会在第一行暂停脚本运行。 - -## 使用 node-inspector 来调试 - -__备注:__ Electron 目前对 node-inspector 支持的不是特别好, -如果你通过 node-inspector 的 console 来检查 `process` 对象,主进程就会崩溃。 - -### 1. 确认你已经安装了 [node-gyp 所需工具](https://github.com/nodejs/node-gyp#installation) - -### 2. 安装 [node-inspector][node-inspector] - -```bash -$ npm install node-inspector -``` - -### 3. 安装 `node-pre-gyp` 的一个修订版 - -```bash -$ npm install git+https://git@github.com/enlight/node-pre-gyp.git#detect-electron-runtime-in-find -``` - -### 4. 为 Electron 重新编译 `node-inspector` `v8` 模块(将 target 参数修改为你的 Electron 的版本号) - -```bash -$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall -$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall -``` - -[How to install native modules][how-to-install-native-modules]. - -### 5. 打开 Electron 的调试模式 - -你也可以用调试参数来运行 Electron : - -```bash -$ electron --debug=5858 your/app -``` - -或者,在第一行暂停你的脚本: - -```bash -$ electron --debug-brk=5858 your/app -``` - -### 6. 使用 Electron 开启 [node-inspector][node-inspector] 服务 - -```bash -$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js -``` - -### 7. 加载调试器界面 - -在 Chrome 中打开 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858 - -[node-inspector]: https://github.com/node-inspector/node-inspector diff --git a/docs-translations/zh-CN/tutorial/desktop-environment-integration.md b/docs-translations/zh-CN/tutorial/desktop-environment-integration.md deleted file mode 100644 index ea92d8d44fe2c..0000000000000 --- a/docs-translations/zh-CN/tutorial/desktop-environment-integration.md +++ /dev/null @@ -1,222 +0,0 @@ -# 桌面环境集成 -不同的操作系统在各自的桌面应用上提供了不同的特性。例如,在 windows 上应用曾经打开的文件会出现在任务栏的跳转列表,在 Mac 上,应用可以把自定义菜单放在鱼眼菜单上。 - -本章将会说明怎样使用 Electron APIs 把你的应用和桌面环境集成到一块。 - -## Notifications (Windows, Linux, macOS) - -这三个操作系统都为用户提供了发送通知的方法。Electron让开发人员通过 -[HTML5 Notification API](https://notifications.spec.whatwg.org/) -便利的去发送通知,用操作系统自带的通知APIs去显示。 - -**Note:** 因为这是一个HTML5API,所以只在渲染进程中起作用 - -```javascript -var myNotification = new Notification('Title', { - body: 'Lorem Ipsum Dolor Sit Amet' -}); - -myNotification.onclick = function () { - console.log('Notification clicked') -} -``` - -尽管代码和用户体验在不同的操作系统中基本相同,但还是有一些差异。 - -### Windows - -* 在Windows 10上, 通知"可以工作". -* 在Windows 8.1和Windows 8系统下,你需要将你的应用通过一个[Application User -Model ID][app-user-model-id]安装到开始屏幕上。需要注意的是,这不是将你的应用固定到开始屏幕。 -* 在Windows 7以及更低的版本中,通知不被支持。不过你可以使用[Tray API][tray-balloon]发送一个"气泡通知"。 - -此外,通知支持的最大字符长队为250。Windows团队建议通知应该保持在200个字符以下。 - -### Linux - -通知使用`libnotify`发送,它能在任何支持[Desktop Notifications -Specification][notification-spec]的桌面环境中显示,包括 Cinnamon, Enlightenment, Unity, -GNOME, KDE。 - -### macOS - -在macOS系统中,通知是直接转发的,你应该了解[Apple's Human Interface guidelines regarding notifications](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html)。 - -注意通知被限制在256个字节以内,如果超出,则会被截断。 - -## 最近文档 (Windows & macOS) -Windows 和 macOS 提供获取最近文档列表的便捷方式,那就是打开跳转列表或者鱼眼菜单。 - -跳转列表: -![JumpList][1] - -鱼眼菜单: -![Dock Menu][2] - -为了增加一个文件到最近文件列表,你可以使用 [app.addRecentDocument][3] API: - -```javascript -var app = require('app'); -app.addRecentDocument('/Users/USERNAME/Desktop/work.type'); -``` -或者你也可以使用 [app.clearRecentDocuments][4] API 来清空最近文件列表。 -```javascript -app.clearRecentDocuments(); -``` -## Windows 需注意 -为了这个特性在 Windows 上表现正常,你的应用需要被注册成为一种文件类型的句柄,否则,在你注册之前,文件不会出现在跳转列表。你可以在 [Application Registration][5] 里找到任何关于注册事宜的说明。 - -## macOS 需注意 -当一个文件被最近文件列表请求时,`app` 模块里的 `open-file` 事件将会被发出。 - -## 自定义的鱼眼菜单(macOS) -macOS 可以让开发者定制自己的菜单,通常会包含一些常用特性的快捷方式。 -### 菜单中的终端 -![Dock menu of Terminal.app][6] - -使用 `app.dock.setMenu` API 来设置你的菜单,这仅在 macOS 上可行: -```javascript -var app = require('app'); -var Menu = require('menu'); -var dockMenu = Menu.buildFromTemplate([ - { label: 'New Window', click: function() { console.log('New Window'); } }, - { label: 'New Window with Settings', submenu: [ - { label: 'Basic' }, - { label: 'Pro'} - ]}, - { label: 'New Command...'} -]); -app.dock.setMenu(dockMenu); -``` - -## 用户任务(Windows) -在 Windows,你可以特别定义跳转列表的 `Tasks` 目录的行为,引用 MSDN 的文档: - -> Applications define tasks based on both the program's features and the key things a user is expected to do with them. Tasks should be context-free, in that the application does not need to be running for them to work. They should also be the statistically most common actions that a normal user would perform in an application, such as compose an email message or open the calendar in a mail program, create a new document in a word processor, launch an application in a certain mode, or launch one of its subcommands. An application should not clutter the menu with advanced features that standard users won't need or one-time actions such as registration. Do not use tasks for promotional items such as upgrades or special offers. - -> It is strongly recommended that the task list be static. It should remain the same regardless of the state or status of the application. While it is possible to vary the list dynamically, you should consider that this could confuse the user who does not expect that portion of the destination list to change. - -### IE 的任务 -![IE][7] -不同于 macOS 的鱼眼菜单,Windows 上的用户任务表现得更像一个快捷方式,比如当用户点击一个任务,一个程序将会被传入特定的参数并且运行。 - -你可以使用 [app.setUserTasks][8] API 来设置你的应用中的用户任务: -```javascript -var app = require('app'); -app.setUserTasks([ - { - program: process.execPath, - arguments: '--new-window', - iconPath: process.execPath, - iconIndex: 0, - title: 'New Window', - description: 'Create a new window' - } -]); -``` -调用 `app.setUserTasks` 并传入空数组就可以清除你的任务列表: -```javascript -app.setUserTasks([]); -``` -当你的应用关闭时,用户任务会仍然会出现,在你的应用被卸载前,任务指定的图标和程序的路径必须是存在的。 - -### 缩略图工具栏 -在 Windows,你可以在任务栏上添加一个按钮来当作应用的缩略图工具栏。它将提供用户一种用户访问常用窗口的方式,并且不需要恢复或者激活窗口。 - -在 MSDN,它被如是说: -> This toolbar is simply the familiar standard toolbar common control. It has a maximum of seven buttons. Each button's ID, image, tooltip, and state are defined in a structure, which is then passed to the taskbar. The application can show, enable, disable, or hide buttons from the thumbnail toolbar as required by its current state. - -> For example, Windows Media Player might offer standard media transport controls such as play, pause, mute, and stop. - -### Windows Media Player 的缩略图工具栏 -![Thumbnail toolbar of Windows Media Player][9] -你可以使用 [BrowserWindow.setThumbarButtons][10] 来设置你的应用的缩略图工具栏。 -```javascript -var BrowserWindow = require('browser-window'); -var path = require('path'); -var win = new BrowserWindow({ - width: 800, - height: 600 -}); -win.setThumbarButtons([ - { - tooltip: "button1", - icon: path.join(__dirname, 'button1.png'), - click: function() { console.log("button2 clicked"); } - }, - { - tooltip: "button2", - icon: path.join(__dirname, 'button2.png'), - flags:['enabled', 'dismissonclick'], - click: function() { console.log("button2 clicked."); } - } -]); -``` -调用 `BrowserWindow.setThumbarButtons` 并传入空数组即可清空缩略图工具栏: -```javascript -win.setThumbarButtons([]); -``` - -## Unity launcher 快捷方式(Linux) -在 Unity,你可以通过改变 `.desktop` 文件来增加自定义运行器的快捷方式,详情看 [Adding shortcuts to a launcher][11]。 -### Audacious 运行器的快捷方式: -![Launcher shortcuts of Audacious][12] - -## 任务栏的进度条(Windows & Unity) -在 Windows,进度条可以出现在一个任务栏按钮之上。这可以提供进度信息给用户而不需要用户切换应用窗口。 - -Unity DE 也具有同样的特性,在运行器上显示进度条。 -### 在任务栏上的进度条: -![Progress bar in taskbar button][13] - -### 在 Unity 运行器上的进度条 -![Progress bar in Unity launcher][14] - -给一个窗口设置进度条,你可以调用 [BrowserWindow.setProgressBar][15] API: -```javascript -var window = new BrowserWindow({...}); -window.setProgressBar(0.5); -``` -在 macOS,一个窗口可以设置它展示的文件,文件的图标可以出现在标题栏,当用户 Command-Click 或者 Control-Click 标题栏,文件路径弹窗将会出现。 -### 展示文件弹窗菜单: -![Represented file popup menu][16] - -你可以调用 [BrowserWindow.setRepresentedFilename][17] 和 [BrowserWindow.setDocumentEdited][18] APIs: -```javascript -var window = new BrowserWindow({...}); -window.setRepresentedFilename('/etc/passwd'); -window.setDocumentEdited(true); -``` - - [1]:https://camo.githubusercontent.com/3310597e01f138b1d687e07aa618c50908a88dec/687474703a2f2f692e6d73646e2e6d6963726f736f66742e636f6d2f64796e696d672f49433432303533382e706e67 - [2]: https://cloud.githubusercontent.com/assets/639601/5069610/2aa80758-6e97-11e4-8cfb-c1a414a10774.png - [3]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/app.md - [4]: https://github.com/electron/electron/blob/master/docs/tutorial/clearrecentdocuments - [5]: https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121%28v=vs.85%29.aspx - [6]: https://cloud.githubusercontent.com/assets/639601/5069962/6032658a-6e9c-11e4-9953-aa84006bdfff.png - [7]: https://camo.githubusercontent.com/30154e0cc36acfc968ac9ae076a8f0d6600dd736/687474703a2f2f692e6d73646e2e6d6963726f736f66742e636f6d2f64796e696d672f49433432303533392e706e67 - [8]: https://github.com/electron/electron/blob/master/docs/api/app.md#appsetusertaskstasks - [9]: https://camo.githubusercontent.com/098cb0f52f27084a80ec6429e51a195df3d8c333/68747470733a2f2f692d6d73646e2e7365632e732d6d7366742e636f6d2f64796e696d672f49433432303534302e706e67 - [10]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/browser-window.md - [11]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher - [12]: https://camo.githubusercontent.com/b6f54e2bc3206ebf8e08dd029529af9ec84d58ae/68747470733a2f2f68656c702e7562756e74752e636f6d2f636f6d6d756e6974792f556e6974794c61756e6368657273416e644465736b746f7046696c65733f616374696f6e3d41747461636846696c6526646f3d676574267461726765743d73686f7274637574732e706e67 - [13]: https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png - [14]: https://cloud.githubusercontent.com/assets/639601/5081747/4a0a589e-6f0f-11e4-803f-91594716a546.png - [15]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/browser-window.md - [16]: https://cloud.githubusercontent.com/assets/639601/5082061/670a949a-6f14-11e4-987a-9aaa04b23c1d.png - [17]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/browser-window.md - [18]: https://github.com/electron/electron/blob/master/docs-translations/zh-CN/api/browser-window.md - -[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows -[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments-os-x-windows -[setusertaskstasks]: ../api/app.md#appsetusertaskstasks-windows -[setprogressbar]: ../api/browser-window.md#winsetprogressbarprogress -[setoverlayicon]: ../api/browser-window.md#winsetoverlayiconoverlay-description-windows-7 -[setrepresentedfilename]: ../api/browser-window.md#winsetrepresentedfilenamefilename-os-x -[setdocumentedited]: ../api/browser-window.md#winsetdocumenteditededited-os-x -[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx -[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher -[setthumbarbuttons]: ../api/browser-window.md#winsetthumbarbuttonsbuttons-windows-7 -[tray-balloon]: ../api/tray.md#traydisplayballoonoptions-windows -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx -[notification-spec]: https://developer.gnome.org/notification-spec/ diff --git a/docs-translations/zh-CN/tutorial/devtools-extension.md b/docs-translations/zh-CN/tutorial/devtools-extension.md deleted file mode 100644 index e35a971e1c768..0000000000000 --- a/docs-translations/zh-CN/tutorial/devtools-extension.md +++ /dev/null @@ -1,45 +0,0 @@ -# DevTools扩展 - -为了使调试更容易,Electron 原生支持 [Chrome DevTools Extension][devtools-extension]。 - -对于大多数DevTools的扩展,你可以直接下载源码,然后通过 `BrowserWindow.addDevToolsExtension` API 加载它们。Electron会记住已经加载了哪些扩展,所以你不需要每次创建一个新window时都调用 `BrowserWindow.addDevToolsExtension` API。 - -** 注:React DevTools目前不能直接工作,详情留意 [https://github.com/electron/electron/issues/915](https://github.com/electron/electron/issues/915) ** - -例如,要用[React DevTools Extension](https://github.com/facebook/react-devtools),你得先下载他的源码: - -```bash -$ cd /some-directory -$ git clone --recursive https://github.com/facebook/react-devtools.git -``` - -参考 [`react-devtools/shells/chrome/Readme.md`](https://github.com/facebook/react-devtools/blob/master/shells/chrome/Readme.md) 来编译这个扩展源码。 - -然后你就可以在任意页面的 DevTools 里加载 React DevTools 了,通过控制台输入如下命令加载扩展: - -```javascript -const BrowserWindow = require('electron').remote.BrowserWindow; -BrowserWindow.addDevToolsExtension('/some-directory/react-devtools/shells/chrome'); -``` - -要卸载扩展,可以调用 `BrowserWindow.removeDevToolsExtension` API (扩展名作为参数传入),该扩展在下次打开DevTools时就不会加载了: - -```javascript -BrowserWindow.removeDevToolsExtension('React Developer Tools'); -``` - -## DevTools 扩展的格式 - -理论上,Electron 可以加载所有为 chrome 浏览器编写的 DevTools 扩展,但它们必须存放在文件夹里。那些以 `crx` 形式发布的扩展是不能被加载的,除非你把它们解压到一个文件夹里。 - -## 后台运行(background pages) - -Electron 目前并不支持 chrome 扩展里的后台运行(background pages)功能,所以那些依赖此特性的 DevTools 扩展在 Electron 里可能无法正常工作。 - -## `chrome.*` APIs - -有些 chrome 扩展使用了 `chrome.*`APIs,而且这些扩展在 Electron 中需要额外实现一些代码才能使用,所以并不是所有的这类扩展都已经在 Electron 中实现完毕了。 - -考虑到并非所有的 `chrome.*`APIs 都实现完毕,如果 DevTools 正在使用除了 `chrome.devtools.*` 之外的其它 APIs,这个扩展很可能无法正常工作。你可以通过报告这个扩展的异常信息,这样做方便我们对该扩展的支持。 - -[devtools-extension]: https://developer.chrome.com/extensions/devtools diff --git a/docs-translations/zh-CN/tutorial/mac-app-store-submission-guide.md b/docs-translations/zh-CN/tutorial/mac-app-store-submission-guide.md deleted file mode 100644 index 35dbb420c3124..0000000000000 --- a/docs-translations/zh-CN/tutorial/mac-app-store-submission-guide.md +++ /dev/null @@ -1,166 +0,0 @@ -# Mac App Store 应用提交向导 - -自从 v0.34.0,Electron 就允许提交应用包到 Mac App Store -(MAS)。这个向导提供的信息有: 如何提交应用和 MAS 构建的限制。 - -__注意:__ 提交应用到 Mac App Store 需要参加 [Apple Developer -Program][developer-program],这需要额外花费。 - -## 如何提交 - -下面步骤介绍了一个简单的提交应用到商店方法。然而,这些步骤不能保证你的应用被 Apple 接受;你仍然需要阅读 Apple 的 [Submitting Your App][submitting-your-app] 关于如何满足 Mac App Store 要求的向导。 - -### 获得证书 - -为了提交应用到商店,首先需要从 Apple 获得一个证书。可以遵循 [现有向导][nwjs-guide]。 - -### 软件签名 - -获得证书之后,你可以使用 [应用部署](application-distribution.md) 打包你的应用,之后进行提交。 - -首先,你需要在软件包内的 `Info.plist` 中增添一项 `ElectronTeamID`: - -```xml - - - ... - ElectronTeamID - TEAM_ID - - -``` - -之后,你需要准备2个授权文件。 - -`child.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.inherit - - - -``` - -`parent.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.application-groups - TEAM_ID.your.bundle.id - - -``` - -请注意上述 `TEAM_ID` 对应开发者账户的 Team ID,`your.bundle.id` 对应软件打包时使用的 Bundle ID。 - -然后使用下面的脚本签名你的应用: - -```bash -#!/bin/bash - -# 应用名称 -APP="YourApp" -# 应用路径 -APP_PATH="/path/to/YourApp.app" -# 生成安装包路径 -RESULT_PATH="~/Desktop/$APP.pkg" -# 开发者应用签名证书 -APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)" -INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)" -# 授权文件路径 -CHILD_PLIST="/path/to/child.plist" -PARENT_PLIST="/path/to/parent.plist" - -FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" - -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Electron Framework" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework/Versions/A/Libraries/libnode.dylib" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/Electron Framework.framework" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/Contents/MacOS/$APP Helper" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper.app/" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/Contents/MacOS/$APP Helper EH" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper EH.app/" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/Contents/MacOS/$APP Helper NP" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$FRAMEWORKS_PATH/$APP Helper NP.app/" -codesign -s "$APP_KEY" -f --entitlements "$CHILD_PLIST" "$APP_PATH/Contents/MacOS/$APP" -codesign -s "$APP_KEY" -f --entitlements "$PARENT_PLIST" "$APP_PATH" - -productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" -``` - -如果你是 macOS 下的应用沙箱使用新手,应当仔细阅读 Apple 的 [Enabling App Sandbox][enable-app-sandbox] 了解一些基础,然后在授权文件 (entitlements files) 内添加你的应用需要的许可。 - -### 上传你的应用并检查提交 - -在签名应用之后,你可以使用 Application Loader 上传软件到 iTunes Connect 进行处理。请确保在上传之前你已经 [创建应用记录][create-record],再 [提交进行审核][submit-for-review]。 - -## MAS 构建限制 - -为了让你的应用满足沙箱的所有条件,在 MAS 构建的时候,下面的模块已被禁用: - -* `crashReporter` -* `autoUpdater` - -并且下面的行为也改变了: - -* 一些视频采集功能无效。 -* 某些辅助功能无法访问。 -* 应用无法检测 DNS 变化。 - -也由于应用沙箱的使用方法,应用可以访问的资源被严格限制了;阅读更多信息 [App Sandboxing][app-sandboxing]。 - -## Electron 使用的加密算法 - -取决于你所在地方的国家和地区,Mac App Store 或许需要记录你应用的加密算法,甚至要求你提交一个 U.S. 加密注册 (ERN) 许可的复印件。 - -Electron 使用下列加密算法: - -* AES - [NIST SP 800-38A](http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf), [NIST SP 800-38D](http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf), [RFC 3394](http://www.ietf.org/rfc/rfc3394.txt) -* HMAC - [FIPS 198-1](http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf) -* ECDSA - ANS X9.62–2005 -* ECDH - ANS X9.63–2001 -* HKDF - [NIST SP 800-56C](http://csrc.nist.gov/publications/nistpubs/800-56C/SP-800-56C.pdf) -* PBKDF2 - [RFC 2898](https://tools.ietf.org/html/rfc2898) -* RSA - [RFC 3447](http://www.ietf.org/rfc/rfc3447) -* SHA - [FIPS 180-4](http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf) -* Blowfish - https://www.schneier.com/cryptography/blowfish/ -* CAST - [RFC 2144](https://tools.ietf.org/html/rfc2144), [RFC 2612](https://tools.ietf.org/html/rfc2612) -* DES - [FIPS 46-3](http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf) -* DH - [RFC 2631](https://tools.ietf.org/html/rfc2631) -* DSA - [ANSI X9.30](http://webstore.ansi.org/RecordDetail.aspx?sku=ANSI+X9.30-1%3A1997) -* EC - [SEC 1](http://www.secg.org/sec1-v2.pdf) -* IDEA - "On the Design and Security of Block Ciphers" book by X. Lai -* MD2 - [RFC 1319](http://tools.ietf.org/html/rfc1319) -* MD4 - [RFC 6150](https://tools.ietf.org/html/rfc6150) -* MD5 - [RFC 1321](https://tools.ietf.org/html/rfc1321) -* MDC2 - [ISO/IEC 10118-2](https://www.openssl.org/docs/manmaster/crypto/mdc2.html) -* RC2 - [RFC 2268](https://tools.ietf.org/html/rfc2268) -* RC4 - [RFC 4345](https://tools.ietf.org/html/rfc4345) -* RC5 - http://people.csail.mit.edu/rivest/Rivest-rc5rev.pdf -* RIPEMD - [ISO/IEC 10118-3](http://webstore.ansi.org/RecordDetail.aspx?sku=ISO%2FIEC%2010118-3:2004) - -如何获取 ERN 许可, 可看这篇文章:[How to legally -submit an app to Apple’s App Store when it uses encryption (or how to obtain an -ERN)][ern-tutorial]。 - -[developer-program]: https://developer.apple.com/support/compare-memberships/ -[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html -[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps -[enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html -[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html -[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html -[app-sandboxing]: https://developer.apple.com/app-sandboxing/ -[issue-3871]: https://github.com/electron/electron/issues/3871 -[ern-tutorial]: https://carouselapps.com/2015/12/15/legally-submit-app-apples-app-store-uses-encryption-obtain-ern/ diff --git a/docs-translations/zh-CN/tutorial/online-offline-events.md b/docs-translations/zh-CN/tutorial/online-offline-events.md deleted file mode 100644 index c13e44c688506..0000000000000 --- a/docs-translations/zh-CN/tutorial/online-offline-events.md +++ /dev/null @@ -1,74 +0,0 @@ -# 在线/离线事件探测 -使用标准 HTML5 APIs 可以实现在线和离线事件的探测,就像以下例子: - -*main.js* -```javascript -const electron = require('electron'); -const app = electron.app; -const BrowserWindow = electron.BrowserWindow; - -var onlineStatusWindow; -app.on('ready', function() { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); -}); -``` - -*online-status.html* -```html - - - - - - -``` - -也会有人想要在主进程也有回应这些事件的实例。然后主进程没有 `navigator` 对象因此不能直接探测在线还是离线。使用 Electron 的进程间通讯工具,事件就可以在主进程被使用,就像下面的例子: - -*main.js* -```javascript -const electron = require('electron'); -const app = electron.app; -const ipcMain = electron.ipcMain; -const BrowserWindow = electron.BrowserWindow; - -var onlineStatusWindow; -app.on('ready', function() { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); -}); - -ipcMain.on('online-status-changed', function(event, status) { - console.log(status); -}); -``` - -*online-status.html* -```html - - - - - - -``` diff --git a/docs-translations/zh-CN/tutorial/quick-start.md b/docs-translations/zh-CN/tutorial/quick-start.md deleted file mode 100644 index d41f736f4ee4c..0000000000000 --- a/docs-translations/zh-CN/tutorial/quick-start.md +++ /dev/null @@ -1,171 +0,0 @@ -# 快速入门 - -Electron 可以让你使用纯 JavaScript 调用丰富的原生 APIs 来创造桌面应用。你可以把它看作一个专注于桌面应用的 Node.js 的变体,而不是 Web 服务器。 - -这不意味着 Electron 是绑定了 GUI 库的 JavaScript。相反,Electron 使用 web 页面作为它的 GUI,所以你能把它看作成一个被 JavaScript 控制的,精简版的 Chromium 浏览器。 - -## 主进程 -在 Electron 里,运行 `package.json` 里 `main` 脚本的进程被称为**主进程**。在主进程运行的脚本可以以创建 web 页面的形式展示 GUI。 - -## 渲染进程 -由于 Electron 使用 Chromium 来展示页面,所以 Chromium 的多进程结构也被充分利用。每个 Electron 的页面都在运行着自己的进程,这样的进程我们称之为**渲染进程**。 - -在一般浏览器中,网页通常会在沙盒环境下运行,并且不允许访问原生资源。然而,Electron 用户拥有在网页中调用 Node.js 的 APIs 的能力,可以与底层操作系统直接交互。 - -## 主进程与渲染进程的区别 -主进程使用 `BrowserWindow` 实例创建页面。每个 `BrowserWindow` 实例都在自己的渲染进程里运行页面。当一个 `BrowserWindow` 实例被销毁后,相应的渲染进程也会被终止。 - -主进程管理所有页面和与之对应的渲染进程。每个渲染进程都是相互独立的,并且只关心他们自己的页面。 - -由于在页面里管理原生 GUI 资源是非常危险而且容易造成资源泄露,所以在页面调用 GUI 相关的 APIs 是不被允许的。如果你想在网页里使用 GUI 操作,其对应的渲染进程必须与主进程进行通讯,请求主进程进行相关的 GUI 操作。 - -在 Electron,我们提供几种方法用于主进程和渲染进程之间的通讯。像 [ipcRenderer][1] 和 [ipcMain][2] 模块用于发送消息, [remote][3] 模块用于 RPC 方式通讯。这些内容都可以在一个 FAQ 中查看 [how to share data between web pages][4]。 - -# 打造你第一个 Electron 应用 -大体上,一个 Electron 应用的目录结构如下: -```` -your-app/ -├── package.json -├── main.js -└── index.html -```` -`package.json `的格式和 Node 的完全一致,并且那个被 `main` 字段声明的脚本文件是你的应用的启动脚本,它运行在主进程上。你应用里的 `package.json` 看起来应该像: -```json -{ - "name" : "your-app", - "version" : "0.1.0", - "main" : "main.js" -} -``` -**注意**:如果 `main` 字段没有在 `package.json` 声明,Electron会优先加载 `index.js`。 - -`main.js` 应该用于创建窗口和处理系统事件,一个典型的例子如下: -```javascript -const electron = require('electron'); -// 控制应用生命周期的模块。 -const {app} = electron; -// 创建原生浏览器窗口的模块。 -const {BrowserWindow} = electron; - -// 保持一个对于 window 对象的全局引用,如果你不这样做, -// 当 JavaScript 对象被垃圾回收, window 会被自动地关闭 -let mainWindow; - -function createWindow() { - // 创建浏览器窗口。 - mainWindow = new BrowserWindow({width: 800, height: 600}); - - // 加载应用的 index.html。 - mainWindow.loadURL(`file://${__dirname}/index.html`); - - // 启用开发工具。 - mainWindow.webContents.openDevTools(); - - // 当 window 被关闭,这个事件会被触发。 - mainWindow.on('closed', () => { - // 取消引用 window 对象,如果你的应用支持多窗口的话, - // 通常会把多个 window 对象存放在一个数组里面, - // 与此同时,你应该删除相应的元素。 - mainWindow = null; - }); -} - -// Electron 会在初始化后并准备 -// 创建浏览器窗口时,调用这个函数。 -// 部分 API 在 ready 事件触发后才能使用。 -app.on('ready', createWindow); - -// 当全部窗口关闭时退出。 -app.on('window-all-closed', () => { - // 在 macOS 上,除非用户用 Cmd + Q 确定地退出, - // 否则绝大部分应用及其菜单栏会保持激活。 - if (process.platform !== 'darwin') { - app.quit(); - } -}); - -app.on('activate', () => { - // 在 macOS 上,当点击 dock 图标并且该应用没有打开的窗口时, - // 绝大部分应用会重新创建一个窗口。 - if (mainWindow === null) { - createWindow(); - } -}); - -// 在这文件,你可以续写应用剩下主进程代码。 -// 也可以拆分成几个文件,然后用 require 导入。 -``` -最后,你想展示的 `index.html` : -```html - - - - - Hello World! - - -

Hello World!

- We are using node , - Chrome , - and Electron . - - -``` - -# 运行你的应用 -一旦你创建了最初的 `main.js`, `index.html` 和 `package.json` 这几个文件,你可能会想尝试在本地运行并测试,看看是不是和期望的那样正常运行。 - -## electron-prebuilt -[electron-prebuilt][5] 是一个 `npm` 模块,包含所使用的 Electron 预编译版本。 -如果你已经用 `npm` 全局安装了它,你只需要按照如下方式直接运行你的应用: -```bash -electron . -``` -如果你是局部安装,那运行: -```bash -./node_modules/.bin/electron . -``` - -## 手工下载 Electron 二进制文件 -如果你手工下载了 Electron 的二进制文件,你也可以直接使用其中的二进制文件直接运行你的应用。 -### Windows -```bash -$ .\electron\electron.exe your-app\ -``` -### Linux -```bash -$ ./electron/electron your-app/ -``` -### macOS -```bash -$ ./Electron.app/Contents/MacOS/Electron your-app/ -``` -`Electron.app` 里面是 Electron 发布包,你可以在 [这里][6] 下载到。 - -# 以发行版本运行 -在你完成了你的应用后,你可以按照 [应用部署][7] 指导发布一个版本,并且以已经打包好的形式运行应用。 - -# 参照下面例子 -复制并且运行这个库 [electron/electron-quick-start][8]。 - -*注意:*运行时需要你的系统已经安装了 [Git][9] 和 [Node.js][10](包含 [npm][11])。 - -```bash -# 克隆这仓库 -$ git clone https://github.com/electron/electron-quick-start -# 进入仓库 -$ cd electron-quick-start -# 安装依赖库并运行应用 -$ npm install && npm start -``` - [1]: https://github.com/electron/electron/blob/v1.1.3/docs/api/ipc-renderer.md - [2]: https://github.com/electron/electron/blob/v1.1.3/docs/api/ipc-main.md - [3]: https://github.com/electron/electron/blob/v1.1.3/docs/api/remote.md - [4]: https://github.com/electron/electron/blob/v1.1.3/docs/faq/electron-faq.md#how-to-share-data-between-web-pages - [5]: https://github.com/electron-userland/electron-prebuilt - [6]: https://github.com/electron/electron/releases - [7]: https://github.com/electron/electron/blob/v1.1.3/docs/tutorial/application-distribution.md - [8]: https://github.com/electron/electron-quick-start - [9]: https://git-scm.com/ - [10]: https://nodejs.org/en/download/ - [11]: https://www.npmjs.com/ diff --git a/docs-translations/zh-CN/tutorial/supported-platforms.md b/docs-translations/zh-CN/tutorial/supported-platforms.md deleted file mode 100644 index dde3f130c575f..0000000000000 --- a/docs-translations/zh-CN/tutorial/supported-platforms.md +++ /dev/null @@ -1,27 +0,0 @@ -# 支持的平台 - -以下的平台是 Electron 目前支持的: - -### macOS - -对于 macOS 系统仅有64位的二进制文档,支持的最低版本是 macOS 10.8。 - -### Windows - -仅支持 Windows 7 及其以后的版本,之前的版本中是不能工作的。 - -对于 Windows 提供 `x86` 和 `amd64` (x64) 版本的二进制文件。需要注意的是 -`ARM` 版本的 Windows 目前尚不支持. - -### Linux - -预编译的 `ia32`(`i686`) 和 `x64`(`amd64`) 版本 Electron 二进制文件都是在 -Ubuntu 12.04 下编译的,`arm` 版的二进制文件是在 ARM v7(硬浮点 ABI 与 -Debian Wheezy 版本的 NEON)下完成的。 - -预编译二进制文件是否能够运行,取决于其中是否包括了编译平台链接的库,所以只有 Ubuntu 12.04 -可以保证正常工作,但是以下的平台也被证实可以运行 Electron 的预编译版本: - -* Ubuntu 12.04 及更新 -* Fedora 21 -* Debian 8 diff --git a/docs-translations/zh-CN/tutorial/testing-on-headless-ci.md b/docs-translations/zh-CN/tutorial/testing-on-headless-ci.md deleted file mode 100644 index b768467109f39..0000000000000 --- a/docs-translations/zh-CN/tutorial/testing-on-headless-ci.md +++ /dev/null @@ -1,51 +0,0 @@ -# Testing Electron with headless CI Systems (Travis CI, Jenkins) - -Electron基于Chromium,所以需要一个显示驱动使其运转。如果Chromium无法找到一个显示驱动, -ELectron 会启动失败,因此无论你如何去运行它,Electron不会执行你的任何测试。在Travis, Circle, -Jenkins 或者类似的系统上测试基于Electron的应用时,需要进行一些配置。本质上,我们需要使用一个 -虚拟的显示驱动。 - -## Configuring the Virtual Display Server - -首先安装[Xvfb](https://en.wikipedia.org/wiki/Xvfb)。 -这是一个虚拟的帧缓冲,实现了X11显示服务协议,所有的图形操作都在内存中表现,而不需要显示在 -任何屏幕输出设备上。这正是我们所需要的。 - -然后创建一个虚拟的xvfb屏幕并且导出一个指向他的名为`DISPLAY`的环境变量。Electron中的Chromium -会自动的去寻找`$DISPLAY`,所以你的应用不需要再去进行配置。这一步可以通过Paul Betts's的 -[xvfb-maybe](https://github.com/paulcbetts/xvfb-maybe)实现自动化:如果系统需要,在`xvfb-maybe`前加上你的测试命令 -然后这个小工具会自动的设置xvfb。在Windows或者macOS系统下,它不会执行任何东西。 - -``` -## On Windows or macOS, this just invokes electron-mocha -## On Linux, if we are in a headless environment, this will be equivalent -## to xvfb-run electron-mocha ./test/*.js -xvfb-maybe electron-mocha ./test/*.js -``` - -### Travis CI - -在 Travis 上, 你的 `.travis.yml` 应该和下面的代码相似: - -``` -addons: - apt: - packages: - - xvfb - -install: - - export DISPLAY=':99.0' - - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & -``` - -### Jenkins - -Jenkins下, 有一个可用的[Xvfb插件](https://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin). - -### Circle CI - -Circle CI 是非常棒的而且有xvfb,`$DISPLAY`也[已经搭建,所以不需要再进行设置](https://circleci.com/docs/environment#browsers)。 - -### AppVeyor - -AppVeyor运行于Windows上,支持 Selenium, Chromium, Electron 以及一些类似的工具,开箱即用,无需配置。 diff --git a/docs-translations/zh-CN/tutorial/using-native-node-modules.md b/docs-translations/zh-CN/tutorial/using-native-node-modules.md deleted file mode 100644 index ef85313e0c27c..0000000000000 --- a/docs-translations/zh-CN/tutorial/using-native-node-modules.md +++ /dev/null @@ -1,56 +0,0 @@ -# 使用原生模块 - -Electron 同样也支持原生模块,但由于和官方的 Node 相比使用了不同的 V8 引擎,如果你想编译原生模块,则需要手动设置 Electron 的 headers 的位置。 - -## 原生Node模块的兼容性 - -当 Node 开始换新的V8引擎版本时,原生模块可能“坏”掉。为确保一切工作正常,你需要检查你想要使用的原生模块是否被 Electron 内置的 Node 支持。你可以在[这里](https://github.com/electron/electron/releases)查看 Electron 内置的 Node 版本,或者使用 `process.version` (参考:[快速入门](https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md))查看。 - -考虑到 [NAN](https://github.com/nodejs/nan/) 可以使你的开发更容易对多版本 Node 的支持,建议使用它来开发你自己的模块。你也可以使用 [NAN](https://github.com/nodejs/nan/) 来移植旧的模块到新的 Nod e版本,以使它们可以在新的 Electron 下良好工作。 - -## 如何安装原生模块 - -如下三种方法教你安装原生模块: - -### 最简单方式 - -最简单的方式就是通过 [`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild) 包重新编译原生模块,它帮你自动完成了下载 headers、编译原生模块等步骤: - -```sh -npm install --save-dev electron-rebuild - -# 每次运行"npm install"时,也运行这条命令 -./node_modules/.bin/electron-rebuild - -# 在windows下如果上述命令遇到了问题,尝试这个: -.\node_modules\.bin\electron-rebuild.cmd -``` - -### 通过 npm 安装 - -你当然也可以通过 `npm` 安装原生模块。大部分步骤和安装普通模块时一样,除了以下一些系统环境变量你需要自己操作: - -```bash -export npm_config_disturl=https://atom.io/download/atom-shell -export npm_config_target=0.33.1 -export npm_config_arch=x64 -export npm_config_runtime=electron -HOME=~/.electron-gyp npm install module-name -``` - -### 通过 node-gyp 安装 - -你需要告诉 `node-gyp` 去哪下载 Electron 的 headers,以及下载什么版本: - -```bash -$ cd /path-to-module/ -$ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=https://atom.io/download/atom-shell -``` - -`HOME=~/.electron-gyp` 设置去哪找开发时的 headers。 - -`--target=0.29.1` 设置了 Electron 的版本 - -`--dist-url=...` 设置了 Electron 的 headers 的下载地址 - -`--arch=x64` 设置了该模块为适配64位操作系统而编译 diff --git a/docs-translations/zh-CN/tutorial/using-pepper-flash-plugin.md b/docs-translations/zh-CN/tutorial/using-pepper-flash-plugin.md deleted file mode 100644 index c030720f37c6b..0000000000000 --- a/docs-translations/zh-CN/tutorial/using-pepper-flash-plugin.md +++ /dev/null @@ -1,48 +0,0 @@ -# 使用 Pepper Flash 插件 - -Electron 现在支持 Pepper Flash 插件。要在 Electron 里面使用 Pepper Flash 插件,你需 -要手动设置 Pepper Flash 的路径和在你的应用里启用 Pepper Flash。 - -## 保留一份 Flash 插件的副本 - -在 macOS 和 Linux 上,你可以在 Chrome 浏览器的 `chrome://plugins` 页面上找到 Pepper -Flash 的插件信息。插件的路径和版本会对 Election 对其的支持有帮助。你也可以把插件 -复制到另一个路径以保留一份副本。 - -## 添加插件在 Electron 里的开关 - -你可以直接在命令行中用 `--ppapi-flash-path` 和 `ppapi-flash-version` 或者 -在 app 的准备事件前调用 `app.commandLine.appendSwitch` 这个 method。同时, -添加 `browser-window` 的插件开关。 -例如: - -```javascript -// Specify flash path. 设置 flash 路径 -// On Windows, it might be /path/to/pepflashplayer.dll -// On macOS, /path/to/PepperFlashPlayer.plugin -// On Linux, /path/to/libpepflashplayer.so -app.commandLine.appendSwitch('ppapi-flash-path', '/path/to/libpepflashplayer.so'); - -// Specify flash version, for example, v17.0.0.169 设置版本号 -app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169'); - -app.on('ready', function() { - mainWindow = new BrowserWindow({ - 'width': 800, - 'height': 600, - 'web-preferences': { - 'plugins': true - } - }); - mainWindow.loadURL('file://' + __dirname + '/index.html'); - // Something else -}); -``` - -## 使用 `` 标签启用插件 - -在 `` 标签里添加 `plugins` 属性。 - -```html - -``` diff --git a/docs-translations/zh-CN/tutorial/using-selenium-and-webdriver.md b/docs-translations/zh-CN/tutorial/using-selenium-and-webdriver.md deleted file mode 100644 index 4c1db714bde80..0000000000000 --- a/docs-translations/zh-CN/tutorial/using-selenium-and-webdriver.md +++ /dev/null @@ -1,119 +0,0 @@ -# 使用 Selenium 和 WebDriver - -引自[ChromeDriver - WebDriver for Chrome][chrome-driver]: - -> WebDriver 是一款开源的支持多浏览器的自动化测试工具。它提供了操作网页、用户输入、JavaScript 执行等能力。ChromeDriver 是一个实现了 WebDriver 与 Chromium 联接协议的独立服务。它也是由开发了 Chromium 和 WebDriver 的团队开发的。 - -为了能够使 `chromedriver` 和 Electron 一起正常工作,我们需要告诉它 Electron 在哪,并且让它相信 Electron 就是 Chrome 浏览器。 - -## 通过 WebDriverJs 配置 - -[WebDriverJs](https://code.google.com/p/selenium/wiki/WebDriverJs) 是一个可以配合 WebDriver 做测试的 node 模块,我们会用它来做个演示。 - -### 1. 启动 ChromeDriver - -首先,你要下载 `chromedriver`,然后运行以下命令: - -```bash -$ ./chromedriver -Starting ChromeDriver (v2.10.291558) on port 9515 -Only local connections are allowed. -``` - -记住 `9515` 这个端口号,我们后面会用到 - -### 2. 安装 WebDriverJS - -```bash -$ npm install selenium-webdriver -``` - -### 3. 联接到 ChromeDriver - -在 Electron 下使用 `selenium-webdriver` 和其平时的用法并没有大的差异,只是你需要手动设置连接 ChromeDriver,以及 Electron 的路径: - -```javascript -const webdriver = require('selenium-webdriver'); - -var driver = new webdriver.Builder() - // "9515" 是ChromeDriver使用的端口 - .usingServer('http://localhost:9515') - .withCapabilities({ - chromeOptions: { - // 这里设置Electron的路径 - binary: '/Path-to-Your-App.app/Contents/MacOS/Atom', - } - }) - .forBrowser('electron') - .build(); - -driver.get('http://www.google.com'); -driver.findElement(webdriver.By.name('q')).sendKeys('webdriver'); -driver.findElement(webdriver.By.name('btnG')).click(); -driver.wait(function() { - return driver.getTitle().then(function(title) { - return title === 'webdriver - Google Search'; - }); -}, 1000); - -driver.quit(); -``` - -## 通过 WebdriverIO 配置 - -[WebdriverIO](http://webdriver.io/) 也是一个配合 WebDriver 用来测试的 node 模块 - -### 1. 启动 ChromeDriver - -首先,下载 `chromedriver`,然后运行以下命令: - -```bash -$ chromedriver --url-base=wd/hub --port=9515 -Starting ChromeDriver (v2.10.291558) on port 9515 -Only local connections are allowed. -``` - -记住 `9515` 端口,后面会用到 - -### 2. 安装 WebdriverIO - -```bash -$ npm install webdriverio -``` - -### 3. 连接到 ChromeDriver - -```javascript -const webdriverio = require('webdriverio'); -var options = { - host: "localhost", // 使用localhost作为ChromeDriver服务器 - port: 9515, // "9515"是ChromeDriver使用的端口 - desiredCapabilities: { - browserName: 'chrome', - chromeOptions: { - binary: '/Path-to-Your-App/electron', // Electron的路径 - args: [/* cli arguments */] // 可选参数,类似:'app=' + /path/to/your/app/ - } - } -}; - -var client = webdriverio.remote(options); - -client - .init() - .url('http://google.com') - .setValue('#q', 'webdriverio') - .click('#btnG') - .getTitle().then(function(title) { - console.log('Title was: ' + title); - }) - .end(); -``` - -## 工作流程 - -无需重新编译 Electron,只要把 app 的源码放到 [Electron的资源目录](https://github.com/electron/electron/blob/master/docs/tutorial/application-distribution.md) 里就可直接开始测试了。 - -当然,你也可以在运行 Electron 时传入参数指定你 app 的所在文件夹。这步可以免去你拷贝-粘贴你的 app 到 Electron 的资源目录。 - -[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/ diff --git a/docs-translations/zh-CN/tutorial/using-widevine-cdm-plugin.md b/docs-translations/zh-CN/tutorial/using-widevine-cdm-plugin.md deleted file mode 100644 index 25ce3bd525e07..0000000000000 --- a/docs-translations/zh-CN/tutorial/using-widevine-cdm-plugin.md +++ /dev/null @@ -1,67 +0,0 @@ -# 使用 Widevine CDM 插件 - -在 Electron ,你可以使用 Widevine CDM 插件装载 Chrome 浏览器 . - -## 获取插件 - -Electron 没有为 Widevine CDM 插件 配制许可 reasons, 为了获得它,首先需要安装官方的 chrome 浏览器,这匹配了体系架构和 Electron 构建使用的 chrome 版本 . - -__注意:__ Chrome 浏览器的主要版本必须和 Electron 使用的版本一样,否则插件不会有效,虽然 `navigator.plugins` 会显示你已经安装了它 . - -### Windows & macOS - -在 Chrome 浏览器中打开 `chrome://components/` ,找到 `WidevineCdm` 并且确定它更新到最新版本,然后你可以从 `APP_DATA/Google/Chrome/WidevineCDM/VERSION/_platform_specific/PLATFORM_ARCH/` 路径找到所有的插件二进制文件 . - -`APP_DATA` 是系统存放数据的地方,在 Windows 上它是 -`%LOCALAPPDATA%`, 在 macOS 上它是 `~/Library/Application Support`. `VERSION` 是 -Widevine CDM 插件的版本字符串, 类似 `1.4.8.866`. `PLATFORM` 是 `mac` 或 -`win`. `ARCH` 是 `x86` 或 `x64`. - -在 Windows,必要的二进制文件是 `widevinecdm.dll` and -`widevinecdmadapter.dll`, 在 macOS ,它们是 `libwidevinecdm.dylib` 和 -`widevinecdmadapter.plugin`. 你可以将它们复制到任何你喜欢的地方,但是它们必须要放在一起. - -### Linux - -在 Linux ,Chrome 浏览器将插件的二进制文件装载在一起 , 你可以在 `/opt/google/chrome` 下找到,文件名是 `libwidevinecdm.so` 和 -`libwidevinecdmadapter.so`. - -## 使用插件 - -在获得了插件文件后,你可以使用 `--widevine-cdm-path` 命令行开关来将 `widevinecdmadapter` 的路径传递给 Electron , 插件版本使用 `--widevine-cdm-version` 开关. - -__注意:__ 虽然只有 `widevinecdmadapter` 的二进制文件传递给了 Electron, `widevinecdm` 二进制文件应当放在它的旁边. - -必须在 `app` 模块的 `ready` 事件触发之前使用命令行开关,并且 page 使用的插件必须激活. - -示例代码 : - -```javascript -// You have to pass the filename of `widevinecdmadapter` here, it is -// * `widevinecdmadapter.plugin` on macOS, -// * `libwidevinecdmadapter.so` on Linux, -// * `widevinecdmadapter.dll` on Windows. -app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevinecdmadapter.plugin'); -// The version of plugin can be got from `chrome://plugins` page in Chrome. -app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866'); - -var mainWindow = null; -app.on('ready', function() { - mainWindow = new BrowserWindow({ - webPreferences: { - // The `plugins` have to be enabled. - plugins: true - } - }) -}); -``` - -## 验证插件 - -为了验证插件是否工作,你可以使用下面的方法 : - -* 打开开发者工具查看是否 `navigator.plugins` 包含了 Widevine -CDM 插件. -* 打开 `https://shaka-player-demo.appspot.com/` 加载一个使用 -`Widevine` 的 manifest. -* 打开 http://www.dash-player.com/demo/drm-test-area/, 检查是否界面输出 `bitdash uses Widevine in your browser`, 然后播放 video. \ No newline at end of file diff --git a/docs-translations/zh-TW/README.md b/docs-translations/zh-TW/README.md deleted file mode 100644 index 3924e1fa83c12..0000000000000 --- a/docs-translations/zh-TW/README.md +++ /dev/null @@ -1,72 +0,0 @@ -## 導引 - -* [支援平台](tutorial/supported-platforms.md) -* [應用程式發布](tutorial/application-distribution.md) -* [應用程式打包](tutorial/application-packaging.md) -* [Mac App Store 上架指引](tutorial/mac-app-store-submission-guide.md) -* [使用原生 node 模組](tutorial/using-native-node-modules.md) -* [主行程 Debug](tutorial/debugging-main-process.md) -* [使用 Selenium 和 WebDriver](tutorial/using-selenium-and-webdriver.md) -* [DevTools 擴充](tutorial/devtools-extension.md) -* [使用 Pepper Flash 外掛](tutorial/using-pepper-flash-plugin.md) - -## 教學 - -* [快速入門](tutorial/quick-start.md) -* [桌面環境整合](tutorial/desktop-environment-integration.md) -* [在線/離線事件偵測](tutorial/online-offline-events.md) - -## API 參考 - -* [提要](api/synopsis.md) -* [行程物件](api/process.md) -* [支援的 Chrome 命令行開關](api/chrome-command-line-switches.md) - -客製的 DOM 元素: - -* [`File`物件](api/file-object.md) -* [``物件](api/web-view-tag.md) -* [`window.open`函數](api/window-open.md) - -主行程可用的模組: - -* [app](api/app.md) -* [auto-updater](api/auto-updater.md) -* [browser-window](api/browser-window.md) -* [content-tracing](api/content-tracing.md) -* [dialog](api/dialog.md) -* [global-shortcut](api/global-shortcut.md) -* [ipc (main process)](api/ipc-main-process.md) -* [menu](api/menu.md) -* [menu-item](api/menu-item.md) -* [power-monitor](api/power-monitor.md) -* [power-save-blocker](api/power-save-blocker.md) -* [protocol](api/protocol.md) -* [session](api/session.md) -* [webContents](api/web-contents.md) -* [tray](api/tray.md) - -渲染行程可用的模組 (網頁): - -* [ipc (renderer)](api/ipc-renderer.md) -* [remote](api/remote.md) -* [web-frame](api/web-frame.md) - -兩種行程都可用的模組: - -* [clipboard](api/clipboard.md) -* [crash-reporter](api/crash-reporter.md) -* [native-image](api/native-image.md) -* [screen](api/screen.md) -* [shell](api/shell.md) - -## 開發 - -* [Coding style](development/coding-style.md) -* [源碼目錄結構](development/source-code-directory-structure.md) -* [與 NW.js (原名node-webkit) 在技術上的差異](development/atom-shell-vs-node-webkit.md) -* [構建系統概況](development/build-system-overview.md) -* [構建步驟 (macOS)](development/build-instructions-osx.md) -* [構建步驟 (Windows)](development/build-instructions-windows.md) -* [構建步驟 (Linux)](development/build-instructions-linux.md) -* [在 debugger 中使用 symbol server](development/setting-up-symbol-server.md) diff --git a/docs-translations/zh-TW/api/file-object.md b/docs-translations/zh-TW/api/file-object.md deleted file mode 100644 index 4f523c4895166..0000000000000 --- a/docs-translations/zh-TW/api/file-object.md +++ /dev/null @@ -1,28 +0,0 @@ -# `File` object - -DOM's File 介面提供一個將本地文件抽象化,並可以讓使用者對本地文件直接使用 HTML5 檔案 API -Electron 可以添加一個 `path` 屬性至 `File` 接口進而顯示檔案在檔案系統內的真實路徑。 - -範例,獲得一個檔案之真實路徑,將檔案拖拉至應用程式 (dragged-onto-the-app): - -```html -
- Drag your file here -
- - -``` diff --git a/docs-translations/zh-TW/api/ipc-main-process.md b/docs-translations/zh-TW/api/ipc-main-process.md deleted file mode 100644 index 00e73efb4fc4b..0000000000000 --- a/docs-translations/zh-TW/api/ipc-main-process.md +++ /dev/null @@ -1,69 +0,0 @@ -# ipc (主行程) - -當在主行程裡使用 `ipc` 模組,這個模組負責處理來自渲染行程(網頁)的非同步與同步訊息。 -來自渲染器的訊息將會被注入到這個模組裡。 - -## 傳送訊息 - -同樣的也可以透過主行程來傳送訊息到渲染行程,更多資訊請參考 [WebContents.send](browser-window.md#webcontentssendchannel-args) - -- 當傳送一個訊息, 事件名稱為 `channel` -- 回覆同步訊息,你需要設定 `event.returnValue` -- 送出一個非同步訊息回給發送端,你可以使用 `event.sender.send(...)` - -這裏是一個傳送和處理訊息的範例,在渲染行程與主行程之間: - -```javascript -// 在主行程裡 -var ipc = require('ipc'); -ipc.on('asynchronous-message', function(event, arg) { - console.log(arg); // 輸出 "ping" - event.sender.send('asynchronous-reply', 'pong'); -}); - -ipc.on('synchronous-message', function(event, arg) { - console.log(arg); // 輸出 "ping" - event.returnValue = 'pong'; -}); -``` - -```javascript -// 在渲染行程裡 (網頁). -var ipc = require('ipc'); -console.log(ipc.sendSync('synchronous-message', 'ping')); // 輸出 "pong" - -ipc.on('asynchronous-reply', function(arg) { - console.log(arg); // 輸出 "pong" -}); -ipc.send('asynchronous-message', 'ping'); -``` - -## 聆聽訊息 - -`ipc` 模組擁有下列幾個方法去聆聽事件: - -### `ipc.on(channel, callback)` - -* `channel` String - 事件名稱 -* `callback` Function - -當一個事件發生 `callback` 會帶著 `event` 物件和一個訊息 `arg` - -## IPC 事件 - -`event` 物件被傳入 `callback` 具有以下幾個方法: - -### `Event.returnValue` - -設定這個值可以回傳一個同步訊息 - -### `Event.sender` - -回傳 `WebContents` 可以送出訊息 - -### `Event.sender.send(channel[, arg1][, arg2][, ...])` - -* `channel` String - 事件名稱 -* `arg` (選用) - -此傳送訊息是非同步的訊息,至渲染行程,可以是一個一系列的參數 `arg` 可以是任何型態。 diff --git a/docs-translations/zh-TW/api/power-monitor.md b/docs-translations/zh-TW/api/power-monitor.md deleted file mode 100644 index e38dee3212da3..0000000000000 --- a/docs-translations/zh-TW/api/power-monitor.md +++ /dev/null @@ -1,36 +0,0 @@ -# power-monitor - -`power-monitor` 模組用來監看電源狀態的改變。你只能在主行程 (main process) 裡面使用。 -你應該要等到 `ready` 在 `app` 模組裡的事件被觸發 (emit),再使用這個模組。 - -舉例來說: - -```javascript -var app = require('app'); - -app.on('ready', function() { - require('power-monitor').on('suspend', function() { - console.log('The system is going to sleep'); - }); -}); -``` - -## 事件 (Events) - -`power-monitor` 模組會觸發 (emits) 以下幾個事件: - -### 事件: 'suspend' - -當系統進入 睡眠 (suspend) 時觸發。 - -### 事件: 'resume' - -當系統 resume 時觸發。 - -### 事件: 'on-ac' - -當系統改變使用交流電源 (AC) 時觸發。 - -### 事件: 'on-battery' - -當系統改變使用電池店員時觸發。 diff --git a/docs-translations/zh-TW/api/power-save-blocker.md b/docs-translations/zh-TW/api/power-save-blocker.md deleted file mode 100644 index a652751c0bb80..0000000000000 --- a/docs-translations/zh-TW/api/power-save-blocker.md +++ /dev/null @@ -1,47 +0,0 @@ -# powerSaveBlocker - -`power-save-blocker` 模組是用來防止系統進入省電模式 low-power (sleep) mode -因此讓應用程式可以保持系統和螢幕的活躍 (active)。 - -舉例來說: - -```javascript -var powerSaveBlocker = require('power-save-blocker'); - -var id = powerSaveBlocker.start('prevent-display-sleep'); -console.log(powerSaveBlocker.isStarted(id)); - -powerSaveBlocker.stop(id); -``` - -## 方法 (Methods) - -`power-save-blocker` 模組有以下幾個方法: - -### `powerSaveBlocker.start(type)` - -* `type` String - Power save blocker type. - * `prevent-app-suspension` - 防止一個應用程式進入睡眠 (suspended)。 將保持系統活躍, - 但允許螢幕被關閉。 使用案例:下載一個檔案或是播放音樂。 - * `prevent-display-sleep`- 防止螢幕進入睡眠。將保持系統和螢幕的活躍。 - 使用案例:播放影片 - -當防止系統進入省電模式 low-power (sleep) mode 。 會回傳一個識別的整數來代表 power save blocker - -**注意:** `prevent-display-sleep` 比 `prevent-app-suspension` 擁有較高的優先權。 -只有高的優先全力才會有效,換句話說 `prevent-display-sleep` 總是會優先於 `prevent-app-suspension` - -例如,一個 API 呼叫 A 請求去做 `prevent-app-suspension`,而另外一個 B 請求去做 `prevent-display-sleep` - `prevent-display-sleep` 將會被使用,直到 B 停止他的請求,`prevent-app-suspension` 才會被使用。 - -### `powerSaveBlocker.stop(id)` - -* `id` Integer - power save blocker 會回傳 id 透過 `powerSaveBlocker.start`. - -將指定的 id 停止 power save blocker - -### `powerSaveBlocker.isStarted(id)` - -* `id` Integer - power save blocker 會回傳 id 透過 `powerSaveBlocker.start`. - -不管對應的 `powerSaveBlocker` 是否已經啟動,將會回傳一個布林值 (boolean) diff --git a/docs-translations/zh-TW/api/process.md b/docs-translations/zh-TW/api/process.md deleted file mode 100644 index bb83f42b15457..0000000000000 --- a/docs-translations/zh-TW/api/process.md +++ /dev/null @@ -1,23 +0,0 @@ -# process - -在 Electron 裡的 `process` 物件具有以下幾個與 upstream node 的不同點: - -* `process.type` String - Process 的型態,可以是 `browser` (i.e. 主行程) 或 `renderer`. -* `process.versions.electron` String - Electron 的版本 -* `process.versions.chrome` String - Chromium 的版本 -* `process.resourcesPath` String - JavaScript 源碼的路徑 - -# 方法 (Methods) - -`process` 物件具有以下的方法: - -### `process.hang` - -會導致目前行程的主執行緒停住 - -## process.setFdLimit(maxDescriptors) _macOS_ _Linux_ - -* `maxDescriptors` Integer - -設置文件描述符 (file descriptor) soft limit `maxDescriptors` 或 OS hard -limit ,以較低者為準當目前的行程。 diff --git a/docs-translations/zh-TW/api/shell.md b/docs-translations/zh-TW/api/shell.md deleted file mode 100644 index 3f3c9ae951c2a..0000000000000 --- a/docs-translations/zh-TW/api/shell.md +++ /dev/null @@ -1,46 +0,0 @@ -# shell - -`shell` 模組提供一些整合桌面應用的功能。 - - -一個範例示範如何利用使用者的預設瀏覽器開啟 URL: - -```javascript -var shell = require('shell'); - -shell.openExternal('https://github.com'); -``` - -## Methods - -`shell` 模組有以下幾個方法: - -### `shell.showItemInFolder(fullPath)` - -* `fullPath` String - -顯示在檔案管理中指定的檔案,如果可以的話,選擇該檔案。 - -### `shell.openItem(fullPath)` - -* `fullPath` String - -打開指定的檔案,在桌面的預設方式。 -Open the given file in the desktop's default manner. - -### `shell.openExternal(url)` - -* `url` String - -打開一個指定的外部協定 URL 在桌面的預設方式。(舉例來說 mailto: URLs 會打開使用者的預設信箱) - - -### `shell.moveItemToTrash(fullPath)` - -* `fullPath` String - -移動指定檔案至垃圾桶,並會對這個操作回傳一個 boolean 狀態 - -### `shell.beep()` - -播放 beep 聲音。 diff --git a/docs-translations/zh-TW/api/synopsis.md b/docs-translations/zh-TW/api/synopsis.md deleted file mode 100644 index e28d1fd8cb0de..0000000000000 --- a/docs-translations/zh-TW/api/synopsis.md +++ /dev/null @@ -1,41 +0,0 @@ -# Synopsis - -所有的 [Node.js's 內建模組](http://nodejs.org/api/) 都可以在 Electron 使用,而且 -第三方的 node 模組同樣的全部支援(包含[原生模組](../tutorial/using-native-node-modules.md)) - -Electron 也提供一些額外的內建模組用來開發原生桌面應用程式,一些模組只可以使用在主行程上 -(main process) 一些只可以使用在渲染行程 (renderer process) 上 (網頁) ,另外還有一些 -模組在兩邊的行程都可以使用。 - -基本的規則是: 如果一個模組是 [GUI](https://zh.wikipedia.org/wiki/%E5%9B%BE%E5%BD%A2%E7%94%A8%E6%88%B7%E7%95%8C%E9%9D%A2) -或者是 low-level 與系統相關的,那麼它就應該只能在主行程上使用 (main process) 你必須要對熟悉 [main process vs. renderer process](../tutorial/quick-start.md#the-main-process) 的觀念,才能去使用這些模組。 - -主行程 (main process) 腳本是一個像一般 Node.js 的腳本: - -```javascript -var app = require('app'); -var BrowserWindow = require('browser-window'); - -var window = null; - -app.on('ready', function() { - window = new BrowserWindow({width: 800, height: 600}); - window.loadURL('https://github.com'); -}); -``` - -渲染行程 (renderer process) 跟一般正常的網頁沒有差別,而且還能有使用 node 模組的能力: - -```html - - - - - - -``` - -執行你的應用程式,請閱讀[Run your app](../tutorial/quick-start.md#run-your-app). diff --git a/docs-translations/zh-TW/tutorial/application-distribution.md b/docs-translations/zh-TW/tutorial/application-distribution.md deleted file mode 100644 index f26f97bf90918..0000000000000 --- a/docs-translations/zh-TW/tutorial/application-distribution.md +++ /dev/null @@ -1,108 +0,0 @@ -# 應用程式部署 - -要部屬你的 Electron 應用程式,你需要把你的應用程式資料夾命名為 `app`,並放置於 Electron 的資源目錄下 (在 macOS 中位在 `Electron.app/Contents/Resources/` 而 Linux 和 Windows 的是在 `resources/`),例如: - -macOS: - -```text -electron/Electron.app/Contents/Resources/app/ -├── package.json -├── main.js -└── index.html -``` - -Windows 和 Linux: - -```text -electron/resources/app -├── package.json -├── main.js -└── index.html -``` - -然後執行 `Electron.app` (或者在 Linux 中是 `electron`, Windows 中是 `electron.exe`),然後 Electron 將會啟動你的應用程式,目錄 `electron` 會接著被部署給最後使用者。 - -## 打包你的應用程式成一個檔案 - -除了透過複製所有原始檔案來發布你的應用程式,你也可以使用 [asar](https://github.com/atom/asar) 來打包你的應用程式為一個壓縮檔,來避免暴露你的原始碼給使用者。 - -要使用 `asar` 壓縮檔來取代 `app` 資料夾,你需要重新命名該壓縮檔為 `app.asar`,然後如下所示把它放到 Electron 的資源目錄中,接著 Electron 就會試著讀取壓縮檔並從它開始執行。 - -macOS: - -```text -electron/Electron.app/Contents/Resources/ -└── app.asar -``` - -Windows 和 Linux: - -```text -electron/resources/ -└── app.asar -``` - -更多詳細的介紹請參閱 [應用程式打包](application-packaging.md). - -## 重新塑造你的下載執行檔品牌形象 - -當你完成 Electron 的應用程式打包後,在發布給使用者前,你會想想要重新塑造你的 Electron。 - -### Windows - -你可以重新命名 `electron.exe` 為任何你喜歡的名稱,然後透過像是 [rcedit](https://github.com/atom/rcedit) -的工具來編輯它的圖示(icon)和其他資訊。 - -### macOS - -你可以重新命名 `Electron.app` 為任何你喜歡的名稱,另外你也需要重新命名下列檔案中的 `CFBundleDisplayName`、`CFBundleIdentifier` 和 `CFBundleName` 欄位: - -* `Electron.app/Contents/Info.plist` -* `Electron.app/Contents/Frameworks/Electron Helper.app/Contents/Info.plist` - -你也可以重新命名 helper 應用程式來避免在活動監視器中秀出 `Electron Helper` -,但請確認你有重新命名 helper 應用程式的可執行檔名稱。 - -重新命名後的應用程式檔案結構可能長得相這樣: - -``` -MyApp.app/Contents -├── Info.plist -├── MacOS/ -│   └── MyApp -└── Frameworks/ - ├── MyApp Helper EH.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper EH - ├── MyApp Helper NP.app - | ├── Info.plist - | └── MacOS/ - |    └── MyApp Helper NP - └── MyApp Helper.app - ├── Info.plist - └── MacOS/ -    └── MyApp Helper -``` - -### Linux - -你可以重新命名 `electron` 可執行檔為任何你想要的名字。 - -## 透過重新建置 Electron 原始碼重塑品牌形象 - -你也可以透過改變產品名稱和重新建置原始碼來重塑 Electron 的品牌形象,要這麼做的話,你需要修改 `atom.gyp` 檔案並在重新建置前清理已建置的所有檔案。 - -### grunt-build-atom-shell - -手動取得 Electron 的原始碼和重新建置可能事件複雜的事,因此有一個建立好的 Grunt 任務(task)可以自動化的處理這些事情: -[grunt-build-atom-shell](https://github.com/paulcbetts/grunt-build-atom-shell). - -這個任務將會自動的處理編輯 `.gyp` 檔,建置原始碼,然後重新建置你的應用程式原生 Node 模組來符合新的可執行檔名稱。 - -## 打包工具 - -除了手動打包你的應用程式,你也可以選擇使用第三方打包工具來幫助你: - -* [electron-packager](https://github.com/maxogden/electron-packager) -* [electron-builder](https://github.com/loopline-systems/electron-builder) diff --git a/docs-translations/zh-TW/tutorial/application-packaging.md b/docs-translations/zh-TW/tutorial/application-packaging.md deleted file mode 100644 index 438d513e2bbff..0000000000000 --- a/docs-translations/zh-TW/tutorial/application-packaging.md +++ /dev/null @@ -1,150 +0,0 @@ -# 應用程式打包 - -為了減少圍繞著 Windows 上長路徑名稱問題的 [issues](https://github.com/joyent/node/issues/6960) ,稍微地加速 `require` 和隱藏你的原始碼避免不小心被看到,你可以選擇把你的應用程式打包成一個 [asar][asar] 壓縮檔,只需要改變一點點你的原始碼就好。 -## 產生 `asar` 壓縮檔 - -一個 [asar][asar] 壓縮檔是一個簡單的類 tar 格式的檔案,它會把幾個檔案串接成一個檔案, Electron 可以不需要解壓縮整個檔案就從中讀取任意檔案。 - -把你的應用程式打包成 `asar` 壓縮檔的步驟: - -### 1. 安裝 asar 工具包 - -```bash -$ npm install -g asar -``` - -### 2. 用 `asar pack` 打包 - -```bash -$ asar pack your-app app.asar -``` - -## 使用 `asar` 壓縮檔 - -在 Electron 中有兩組 API:Node.js 提供的 Node APIs 和 Chromium 提供的 Web -APIs,兩組 API 都支援從 `asar` 壓縮檔中讀取檔案。 - -### Node API - -因為 Electron 中有一些特別的補釘,像是 `fs.readFile` 和 `require` 這樣的 Node API 會將 `asar` 壓縮檔視為許多虛擬目錄,將裡頭的檔案視為在檔案系統上的一般檔案。 - -例如,假設我們有一個 `example.asar` 壓縮檔在 `/path/to` 中: - -```bash -$ asar list /path/to/example.asar -/app.js -/file.txt -/dir/module.js -/static/index.html -/static/main.css -/static/jquery.min.js -``` - -讀取一個在 `asar` 壓縮檔中的檔案: - -```javascript -const fs = require('fs'); -fs.readFileSync('/path/to/example.asar/file.txt'); -``` - -列出所有在壓縮檔根目錄下的檔案: - -```javascript -const fs = require('fs'); -fs.readdirSync('/path/to/example.asar'); -``` - -使用一個壓縮檔中的模組: - -```javascript -require('/path/to/example.asar/dir/module.js'); -``` - -你也可以利用 `BrowserWindow` 在 `asar` 壓縮檔中呈現一個網頁: - -```javascript -const BrowserWindow = require('electron').BrowserWindow; -var win = new BrowserWindow({width: 800, height: 600}); -win.loadURL('file:///path/to/example.asar/static/index.html'); -``` - -### Web API - -在一個網頁中,壓縮檔中的檔案都可以透過 `file:` 這個協定被存取,如同 Node API,`asar` 壓縮檔都被視為目錄。 - -例如,要透過 `$.get` 取得一個檔案: - -```html - -``` - -### 把一個 `asar` 壓縮檔視為一般檔案 - -在一些像是驗證 `asar` 壓縮檔檢查碼(checksum)的例子中,我們需要以檔案的方式讀取 `asar` 壓縮檔中的內容,為了達到這個目的,你可以使用內建的 -`original-fs` 模組,它提供了沒有 `asar` 支援的原生 `fs` API: - -```javascript -var originalFs = require('original-fs'); -originalFs.readFileSync('/path/to/example.asar'); -``` - -你也可以設定 `process.noAsar` 為 `true` 來關掉在 `fs` 模組中的 `asar` 支援: - -```javascript -process.noAsar = true; -fs.readFileSync('/path/to/example.asar'); -``` - -## Node API 上的限制 - -儘管我們盡可能的努力嘗試著使 Node API 中的 `asar` 壓縮檔像目錄一樣運作,還是有一些基於 Node API 低階本質的限制存在。 - -### 壓縮檔都是唯讀的 - -所有壓縮檔都無法被修改,因此所有可以修改檔案的 Node API 都無法與 `asar ` 壓縮檔一起運作。 - -### 使用中的目錄無法被設為壓縮檔中的目錄 - -儘管 `asar` 壓縮檔被視為目錄,卻並沒有真正的目錄在檔案系統中,所以你永遠無法將使用中的目錄設定成 `asar` 壓縮檔中的目錄,把他們以 `cwd` 選項的方式傳遞,對某些 API 也會造成錯誤。 - -### 更多透過 API 拆封的方法 - -大部分 `fs` API 可以讀取一個檔案,或是不用拆封就從 `asar` 壓縮檔中取得一個檔案的資訊,但對一些需要傳遞真實檔案路徑給現行系統呼叫的 API ,Electron 將會解開需要的檔案到一個暫時的檔案,然後傳遞該暫時檔案的路徑給那些 API 以便使他們可以運作,這會增加這些 API 一點負擔。 - - -需要額外拆封的 API : - -* `child_process.execFile` -* `child_process.execFileSync` -* `fs.open` -* `fs.openSync` -* `process.dlopen` - 在原生模組中被 `require` 使用 - -### `fs.stat` 的不真實的狀態資訊 - -`fs.stat` 回傳的 `Stats` 物件和它在 `asar` 壓縮檔中的檔案朋友都是以猜測的方式產生的,因為那些檔案不存在檔案系統,所以你不應該信任 `Stats` 物件,除了取得檔案大小和確認檔案型態之外。 - -### 執行 `asar` 壓縮檔中的二進位檔 - -有像是 `child_process.exec`、`child_process.spawn` 和 `child_process.execFile` 的 Node APIs 可以執行二進位檔,但只有 `execFile` 是 `asar` 壓縮檔中可以執行二進位檔的。 - -這是因為 `exec` 和 `spawn` 接受的輸入是 `command` 而不是 `file`,而 `command` 們都是在 shell 底下執行,我們找不到可靠的方法來決定是否一個命令使用一個在 `asar` 壓縮檔中的檔案,而儘管我們找得到,我們也無法確定是否我們可以在沒有外部影響(side effect)的情況下替換掉命令中的路徑。 - -## 加入拆封檔案到 `asar` 壓縮檔中 - -如前述,一些 Node API 再被呼叫時會拆封檔案到檔案系統,除了效能議題外,它也會導致掃毒軟體發出 false alerts。 - -要繞過這個問題,你可以透過使用 `--unpack` 選向來拆封一些建立壓縮檔的檔案,以下是一個不包含共享原生模組的函式庫的例子: - -```bash -$ asar pack app app.asar --unpack *.node -``` - -執行這個命令以後,除了 `app.asar` 以外,還有一個帶有拆封檔案的 `app.asar.unpacked` 資料夾被產生出來,當你要發布給使用者時,你應該把它和 `app.asar` 一起複。 - -[asar]: https://github.com/atom/asar diff --git a/docs-translations/zh-TW/tutorial/debugging-main-process.md b/docs-translations/zh-TW/tutorial/debugging-main-process.md deleted file mode 100644 index f1a7e8409515b..0000000000000 --- a/docs-translations/zh-TW/tutorial/debugging-main-process.md +++ /dev/null @@ -1,71 +0,0 @@ -# 主行程 Debug - -瀏覽器視窗開發工具 DevTools 只可以用來幫渲染器的行程腳本(renderer process script,網頁畫面)除錯(debug),為了提供一個方法在主行程中除錯,Electron 有提供 `--debug` 和 `--debug-brk` 開關。 - -## 命令列開關 - -使用以下命令列切換來為 Electron 的主行程除錯: - -### `--debug=[port]` - -當這個開關被使用,Electron 將會透過 `port` 來監聽 V8 的除錯協定訊息,預設的 `port` 是 `5858`。 - -### `--debug-brk=[port]` - -同 `--debug` 但暫停在腳本的第一行。 - -## 使用 node-inspector 來除錯 - -__Note:__ Electron 近期沒有跟 node-inspector 處的很好,而且如果你透過 node-inspector's console 查看 `process` 物件,主行程將會爆掉。 - -### 1. 確保你有安裝 [node-gyp required tools][node-gyp-required-tools] - -### 2. 安裝 [node-inspector][node-inspector] - -```bash -$ npm install node-inspector -``` - -### 3. 安裝一個修補過版本的 `node-pre-gyp` - -```bash -$ npm install git+https://git@github.com/enlight/node-pre-gyp.git#detect-electron-runtime-in-find -``` - -### 4. 除心編譯 `node-inspector` `v8` 模組給 Electron (變更 target 為你的 Electron 編號) - -```bash -$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-debug/ --dist-url=https://atom.io/download/atom-shell reinstall -$ node_modules/.bin/node-pre-gyp --target=0.36.2 --runtime=electron --fallback-to-build --directory node_modules/v8-profiler/ --dist-url=https://atom.io/download/atom-shell reinstall -``` - -參閱 [如何安裝原生模組](how-to-install-native-modules). - -### 5. 給 Electron 啟用除錯模式 - -你可以啟動 Electron 並帶有一個除錯 flag ,例如: - -```bash -$ electron --debug=5858 your/app -``` - -或者,讓你的腳本暫停在第一行: - -```bash -$ electron --debug-brk=5858 your/app -``` - -### 6. 使用啟動 [node-inspector][node-inspector] 伺服器 - -```bash -$ ELECTRON_RUN_AS_NODE=true path/to/electron.exe node_modules/node-inspector/bin/inspector.js -``` - -### 7. 載入除錯介面 - -在你的 Chrome 瀏覽器打開 http://127.0.0.1:8080/debug?ws=127.0.0.1:8080&port=5858,你可能需要點擊暫停假如你是透過使用 debug-brk 啟動並停在進入行(entry line)的話。 - -[node-inspector]: https://github.com/node-inspector/node-inspector -[node-gyp-required-tools]: https://github.com/nodejs/node-gyp#installation -[how-to-install-native-modules]: using-native-node-modules.md#how-to-install-native-modules - diff --git a/docs-translations/zh-TW/tutorial/devtools-extension.md b/docs-translations/zh-TW/tutorial/devtools-extension.md deleted file mode 100644 index e65ebbcfa1a58..0000000000000 --- a/docs-translations/zh-TW/tutorial/devtools-extension.md +++ /dev/null @@ -1,46 +0,0 @@ -# DevTools 擴充套件 - -要使除錯更簡單,Electron 有對 [Chrome DevTools(開發人員工具) Extension][devtools-extension] 基本的支援。 - -多數的 DevTools 擴充可以簡單地透過下載原始碼然後使用 `BrowserWindow.addDevToolsExtension` API 來載入它們,已載入的擴充套件會被記住,如此一來你就不用每次建立一個視窗的時候就要呼叫 API。 - -** 注意: React DevTools 無法使用,參考 [issue](https://github.com/electron/electron/issues/915) ** - -例如使用 [React DevTools Extension](https://github.com/facebook/react-devtools),首先你需要下載它的原始碼: - -```bash -$ cd /some-directory -$ git clone --recursive https://github.com/facebook/react-devtools.git -``` - -照著 [`react-devtools/shells/chrome/Readme.md`](https://github.com/facebook/react-devtools/blob/master/shells/chrome/Readme.md) 的指示來建置擴充套件。 - -接著你就可以在 Electron 中打開任何視窗來載入擴充套件了,然後在 DevTools console 執行以下的程式碼: - -```javascript -const BrowserWindow = require('electron').remote.BrowserWindow; -BrowserWindow.addDevToolsExtension('/some-directory/react-devtools/shells/chrome'); -``` - -要卸載擴充套件,你可以呼叫 `BrowserWindow.removeDevToolsExtension` -API,並帶入套件的名稱,則套件就不會在下次起打開 DevTools 的時候載入了: - -```javascript -BrowserWindow.removeDevToolsExtension('React Developer Tools'); -``` - -## DevTools 擴充套件的格式 - -理想上,所有寫給 Chrome 瀏覽器用的 DevTools 擴充套件都要能夠被 Electron 載入,但它們需要是在一個普通的目錄下,那些以 `crx` 包裝的擴充套件,Electron 沒有辦法載入它們除非你找到一個解壓縮他們到目錄的方法。 - -## Background Pages - -目前 Electron 沒有支援 Chrome 擴充套件的 background pages,所以一些會用到 background pages 的 DevTools 擴充套件可能會無法在 Electron 中運作。 - -## `chrome.*` APIs - -一些 Chrome 擴充套件可能使用到 `chrome.*` API,而儘管在 Electron 中有一些這種 API 的實作,還是沒有所有的部分都被實作到。 - -因為並非所有 `chrome.*` API 都有實作,如果一個 DevTools 擴充套件有使用到而非 `chrome.devtools.*`,這個套件非常有可能無法運作,你可以回報失敗的擴充套件到 issue tracker,那我們就可以把這些 API 加入支援。 - -[devtools-extension]: https://developer.chrome.com/extensions/devtools diff --git a/docs-translations/zh-TW/tutorial/mac-app-store-submission-guide.md b/docs-translations/zh-TW/tutorial/mac-app-store-submission-guide.md deleted file mode 100644 index b33ddeda40524..0000000000000 --- a/docs-translations/zh-TW/tutorial/mac-app-store-submission-guide.md +++ /dev/null @@ -1,104 +0,0 @@ -# Mac App Store 提交指引 - -自從版本 v0.34.0 開始,Electron 允許提交打包好的應用程式到 Mac App Store(MAS),這個指引提供了以下資訊:如何提交你的應用程式和 MAS 的建置限制。 - -__Note:__ 提交一個應用程式到 Mac App Store 需要註冊要付費的 [Apple Developer -Program][developer-program]. - -## 如何提交你的應用程式 - -以下步驟介紹了一個簡單的方法提交你的應用程式到 Mac App Store,然而這些步驟不保證你的應用程式會被 Apple 批准,你仍然需要閱讀 Apple 的 [Submitting Your App][submitting-your-app] 指引來達到 Mac App Store 的要求。 - -### 取得認證 - -要提交你的應用程式到 Mac App Store,你首先必須取得 Apple 的認證,你可以遵循這些網路上的 [existing guides][nwjs-guide]。 - -### 簽署你的應用程式 - -取得了 Apple 的認證以後,你可以遵照 [Application Distribution](application-distribution.md) 來打包你的應用程式,然後進行你應用程式的簽署,這個步驟基本上與其他程式相同,但重點在於你要一一為每個 Electron 的相依套件做簽署。 - -首先,你需要準備兩個管理權限用的檔案。 - -`child.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - com.apple.security.inherit - - - -``` - -`parent.plist`: - -```xml - - - - - com.apple.security.app-sandbox - - - -``` - -接著遵照下面的腳本簽署你的應用程式: - -```bash -#!/bin/bash - -# Name of your app. -APP="YourApp" -# The path of you app to sign. -APP_PATH="/path/to/YouApp.app" -# The path to the location you want to put the signed package. -RESULT_PATH="~/Desktop/$APP.pkg" -# The name of certificates you requested. -APP_KEY="3rd Party Mac Developer Application: Company Name (APPIDENTITY)" -INSTALLER_KEY="3rd Party Mac Developer Installer: Company Name (APPIDENTITY)" - -FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks" - -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Libraries/libnode.dylib" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/Electron Framework" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/Electron Framework.framework/" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper.app/" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper EH.app/" -codesign --deep -fs "$APP_KEY" --entitlements child.plist "$FRAMEWORKS_PATH/$APP Helper NP.app/" -codesign -fs "$APP_KEY" --entitlements parent.plist "$APP_PATH" -productbuild --component "$APP_PATH" /Applications --sign "$INSTALLER_KEY" "$RESULT_PATH" -``` - -如果你是第一次使用 macOS 下的應用程式沙盒(app sandboxing),你應該也要閱讀 Apple 的 [Enabling App Sandbox][enable-app-sandbox] 以具備基本概念,然後把你的應用程式會用到的 key 的權限都加入管理權現的檔案中。 - -### 上傳你的應用程式和提交檢視 - -當你簽署好你的應用程式後,你可以使用應用程式載入器(Application Loader)把他上傳到 iTunes,處理中請保持連線順暢,在上傳以前請確保你已經 [建立一個紀錄][create-record],機著你就可以提交你的應用程式去檢視了。 - -## MAS 建置的限制 - -為了滿足應用程式沙盒的所有的要求,以下模組需要在 MAS 建置過程中被停用: - -* `crash-reporter` -* `auto-updater` - -然後以下的動作已經被變更: - -* 在某些機器上影像捕捉可能不能運作 -* 特定的存取特性可能無法運作 -* 應用程式將不管 DNS 的改變 - -此外,由於使用了應用程式沙盒,那些可以被應用程式存取的資源會被嚴格限制,你可以閱讀 [App Sandboxing][app-sandboxing] 以取得更多資訊。 - -[developer-program]: https://developer.apple.com/support/compare-memberships/ -[submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html -[nwjs-guide]: https://github.com/nwjs/nw.js/wiki/Mac-App-Store-%28MAS%29-Submission-Guideline#first-steps -[enable-app-sandbox]: https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html -[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html -[submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html -[app-sandboxing]: https://developer.apple.com/app-sandboxing/ diff --git a/docs-translations/zh-TW/tutorial/online-offline-events.md b/docs-translations/zh-TW/tutorial/online-offline-events.md deleted file mode 100644 index 234a02710eb7c..0000000000000 --- a/docs-translations/zh-TW/tutorial/online-offline-events.md +++ /dev/null @@ -1,80 +0,0 @@ -# 在線/離線事件偵測 - -我們可以在渲染引擎 (renderer) 的行程裡用標準的 HTML5 API 來實作在線與離線事件的偵測。 -請參考以下範例: - -_main.js_ - -```javascript -var app = require('app'); -var BrowserWindow = require('browser-window'); -var onlineStatusWindow; - -app.on('ready', function() { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` - -您也許有時候也會有想要在主行程裡回應這些事件的情況。然而,在主行程裡並沒有 `navigator` 這個物件,因此不能直接地偵測這些事件。 -但我們可以使用 Electron 所提供的跨行程 (inter-process) 溝通的工具,事件就可以被傳送到主程序內並做您所需的處理。 -請參考以下範例: - -_main.js_ - -```javascript -var app = require('app'); -var ipc = require('ipc'); -var BrowserWindow = require('browser-window'); -var onlineStatusWindow; - -app.on('ready', function() { - onlineStatusWindow = new BrowserWindow({ width: 0, height: 0, show: false }); - onlineStatusWindow.loadURL('file://' + __dirname + '/online-status.html'); -}); - -ipc.on('online-status-changed', function(event, status) { - console.log(status); -}); -``` - -_online-status.html_ - -```html - - - - - - -``` diff --git a/docs-translations/zh-TW/tutorial/quick-start.md b/docs-translations/zh-TW/tutorial/quick-start.md deleted file mode 100644 index ec1f612868cd8..0000000000000 --- a/docs-translations/zh-TW/tutorial/quick-start.md +++ /dev/null @@ -1,174 +0,0 @@ -# 快速入門 - -## 簡介 - -Electron 可以讓你使用純 JavaScript 提供豐富的原生的 APIs 來創造桌面應用程式。 -你可以把它視為一個 Node.js 的變體,專注於桌面應用程式而不是 web 伺服器。 - -這不表示 Electron 是一個用 JavaScript 去綁定 GUI 函式庫。取而代之的,Electron 是使用網頁介面來作為它的 GUI , -所以你可以把它看作是一個被 JavaScript 所控制且精簡化的 Chromium 瀏覽器。 - -## 主行程 - -在 Electron 裡,有個行程會去運行 `package.json` 裡的 `main` 腳本被稱為 __主行程__ 。 -這個腳本運行在主行程裏可以顯示一個 GUI 就由創建一個 web 頁面。 - -## 渲染行程 - -因為 Electron 使用 Chromium 來顯示網頁,所以 Chromium 的多行程架構也被充分利用。 -每一個網頁在 Electron 裏執行各自的行程,被稱為 __渲染行程__。 - -在一般瀏覽器中,網頁通常會在沙盒環境下運行,並且不允許存取原生資源。然而, -Electron 的用戶擁有在網頁中呼叫 Node.js APIs 的能力,允許低級別操作與作業系統的交互作用。 - -## 主行程與渲染行程的區別 - -主行程創造網頁透過創造 `BroswerWindow` 實例。每一個 `BroswerWindow` 實例都在自己的渲染行程裡運行著一個網頁。 -當一個 `BroswerWindow` 實例被銷毀,對應的渲染行程也會被終止。主行程管理所有網頁和與之對應的渲染行程。 -每一個渲染行程都是相互獨立的,並且只關心他們自己的網頁。 - -在網頁中,是不允許呼叫原生 GUI 相關 APIs 因為管理原生 GUI 資源在網頁上是非常危險而且容易造成資源洩露。 -如果你想要在網頁中呼叫 GUI 相關的 APIs 的操作,網頁的渲染行程必須與主行程進行通訊,請求主行程進行相關的操作。 - -在 Electron,我們提供用於在主行程與渲染行程之間通訊的 [ipc](../api/ipc-renderer.md) 模組。並且也有一個遠端模組使用 RPC 通訊方式 [remote](../api/remote.md)。 - -# 打造你第一個 Electron 應用 - -一般來說,一個 Electron 應用程式的目錄結構像下面這樣: - -```text -your-app/ -├── package.json -├── main.js -└── index.html -``` - -`package.json` 的格式與 Node 的模組完全一樣,並且有個腳本被指定為 `main` 是用來啟動你的應用程式,它運行在主行程上。 -你應用裡的 一個範例在你的 `package.json` 看起來可能像這樣: - -```json -{ - "name" : "your-app", - "version" : "0.1.0", - "main" : "main.js" -} -``` - -__注意__:如果 `main` 沒有在 `package.json` 裏, Electron會嘗試載入 `index.js`。 - -`main.js` 用於創建視窗和處理系統事件,一個典型的例子如下: - -``` javascript -var app = require('app'); // 控制應用程式生命週期的模組。 -var BrowserWindow = require('browser-window'); // 創造原生瀏覽器窗口的模組 - -// 保持一個對於 window 物件的全域的引用,不然,當 JavaScript 被GC, -// window 會被自動地關閉 -var mainWindow = null; - -// 當所有窗口被關閉了,退出。 -app.on('window-all-closed', function() { -  // 在macOS 上,通常使用者在明確地按下 Cmd + Q 之前 -  // 應用會保持活動狀態 -  if (process.platform != 'darwin') { -    app.quit(); -  } -}); - -// 當Electron 完成了初始化並且準備創建瀏覽器視窗的時候 -// 這個方法就被調用 -app.on('ready', function() { -  // 創建瀏覽器視窗 -  mainWindow = new BrowserWindow({width: 800, height: 600}); - -  // 載入應用程式的 index.html -  mainWindow.loadURL('file://' + __dirname + '/index.html'); - -  // 打開開發者工具 -  mainWindow.webContents.openDevTools(); - -  // 當window 被關閉,這個事件會被觸發 -  mainWindow.on('closed', function() { -    // 取消引用 window 物件,如果你的應用程式支援多視窗的話, -    // 通常會把多個 window 物件存放在一個數組裡面, -    // 但這次不是。 -    mainWindow = null; -  }); -}); -``` - -最後,你想顯示的 `index.html` : - -```html - - -   -    Hello World! -   -   -    

Hello World!

- We are using node , - Chrome , - and Electron . -   - -``` - -# 運行你的應用程式 - -一旦你創造了最初的 `main.js` , `index.html` 和 `package.json` 這幾個文件,你可能會想嘗試在本地運行並測試,看看是不是和期望的那樣正常運行。 - -## electron-prebuild -如果你已經使用 `npm` 安裝了全域的 `electron-prebuilt`,那麼你只需要按照如下方式直接運行你的應用程式: - -```bash -electron . -``` - -如果你是局部性地安裝,那運行: - -```bash -./node_modules/.bin/electron . -``` - -## 手動下載 Electron Binary - -如果你手動下載了 Electron ,你可以直接使的 Binary 直接運行你的應用程式。 - -### Windows - -``` bash -$ .\electron\electron.exe your-app\ -``` - -### Linux - -``` bash -$ ./electron/electron your-app/ -``` - -### macOS - -``` bash -$ ./Electron.app/Contents/MacOS/Electron your-app/ -``` - -`Electron.app` 裡面是 Electron 釋出包,你可以在[這裡](https://github.com/electron/electron/releases)下載到。 - -# 作為版本發行 -在你完成了你的應用程式後,你可以依照 [應用部署](https://github.com/electron/electron/blob/master/docs/tutorial/application-distribution.md) 指南發布一個版本,並且運行已經打包好的應用程式。 - -# 試試這個範例 - -Clone 與執行本篇教學的程式碼,它們都放在 [`atom/electron-quick-start`](https://github.com/electron/electron-quick-start) 這個 repository。 - -**Note**: 執行這個範例需要 [Git](https://git-scm.com) 以及 [Node.js](https://nodejs.org/en/download/) (其中包括 [npm](https://npmjs.org)) 在你的作業系統。 - -```bash -# Clone the repository -$ git clone https://github.com/electron/electron-quick-start -# Go into the repository -$ cd electron-quick-start -# Install dependencies and run the app -$ npm install && npm start -``` diff --git a/docs-translations/zh-TW/tutorial/supported-platforms.md b/docs-translations/zh-TW/tutorial/supported-platforms.md deleted file mode 100644 index d17943761d994..0000000000000 --- a/docs-translations/zh-TW/tutorial/supported-platforms.md +++ /dev/null @@ -1,26 +0,0 @@ -# 支援的平台 - -Electron 已支援以下平台: - -### macOS - -macOS 系統只有 64 位元的執行檔,且 macOS 的最低版本要求為 macOS 10.8。 - -### Windows - -Windows 7 和更新的版本都有支援,早期的作業系統都不支援(且無法運作)。 - - - -`x86` 和 `amd64` (x64) 的執行檔都有提供,請注意,`ARM` 版本的 Electron 還沒有支援。 - -### Linux - -已經建置好的 `ia32`(`i686`) 和 `x64`(`amd64`) Electron 執行檔都是在 Ubuntu 12.04 的環境下編譯,`arm` 執行檔是在 hard-float ABI 和 -Debian Wheezy 的 NEON 的 ARM v7 下編譯的。 - -已建置好的執行檔是否能夠成功在 Linux 發行版執行,要看該發行版在建置的平台上是否含有 Electron 會連結的函式庫,所以只有 Ubuntu 12.04 是已確定可以運行的,而以下平台也都有驗證過可以運行已建置好的 Electron 執行檔: - -* Ubuntu 12.04 and later -* Fedora 21 -* Debian 8 diff --git a/docs-translations/zh-TW/tutorial/using-native-node-modules.md b/docs-translations/zh-TW/tutorial/using-native-node-modules.md deleted file mode 100644 index 8d90b82d02fe7..0000000000000 --- a/docs-translations/zh-TW/tutorial/using-native-node-modules.md +++ /dev/null @@ -1,50 +0,0 @@ -# 使用原生 node 模組 - -原生的 Node 模組 Electron 都有支援,但自從 Electron 使用了與 Node 官方不同的 V8 版本後,當你要建置原生模組的時候,你需要手動指定 Electron 標頭的位置。 - -## 原生 Node 模組的相容性 - -原生模組可能在 Node 開始使用一個新版本的 V8 時毀損,為了確保你想要用的模組能正確與 Electron 一起運行,你應該檢查是否支援 Electron 內部 Node 版本,你可以查看 [releases](https://github.com/electron/electron/releases) 或是使用 `process.version` (範例請見 [Quick Start](https://github.com/electron/electron/blob/master/docs/tutorial/quick-start.md)) 來檢查哪個 Node 版本是現在的 Electron 使用的。 - -你可以考慮給你自己的模組使用 [NAN](https://github.com/nodejs/nan/),因為它可以較輕易的支援多種版本的 Node,它對於移植舊的模組到新版本的 Node 以便與 Electron 一起運作也是很有用的。 - -## 如何安裝原生模組 - -三種安裝原生模組的方式: - -### 簡單的方法 - -最直接重新建置原生模組的方法是透過 [`electron-rebuild`](https://github.com/paulcbetts/electron-rebuild) 套件,這個套件處理了手動下載標頭和建制原生模組的步驟: - -```sh -npm install --save-dev electron-rebuild - -# 每次你執行 "npm install", 執行這句 -./node_modules/.bin/electron-rebuild - -# 在 Windows 上如果你有狀況,試試看: -.\node_modules\.bin\electron-rebuild.cmd -``` - -### 使用 npm - -你也可以使用 `npm` 安裝模組,步驟與 Node 模組的安裝相同,除了你需要設定一些環境變數: - -```bash -export npm_config_disturl=https://atom.io/download/atom-shell -export npm_config_target=0.33.1 -export npm_config_arch=x64 -export npm_config_runtime=electron -HOME=~/.electron-gyp npm install module-name -``` - -### 使用 node-gyp - -要把 Node 模組與 Eletron 的標頭一起建置,你需要告訴 `node-gyp` 下載標頭到哪裡,以及要使用哪個版本: - -```bash -$ cd /path-to-module/ -$ HOME=~/.electron-gyp node-gyp rebuild --target=0.29.1 --arch=x64 --dist-url=https://atom.io/download/atom-shell -``` - -`HOME=~/.electron-gyp` 改變了尋找開發標頭的地方,`--target=0.29.1` 是 Eletron 的版本, `--dist-url=...` 指定了下載標頭到哪, `--arch=x64` 指出模組要建置在 64 位元系統。 diff --git a/docs-translations/zh-TW/tutorial/using-pepper-flash-plugin.md b/docs-translations/zh-TW/tutorial/using-pepper-flash-plugin.md deleted file mode 100644 index 2e1ea49f0216f..0000000000000 --- a/docs-translations/zh-TW/tutorial/using-pepper-flash-plugin.md +++ /dev/null @@ -1,45 +0,0 @@ -# 使用 Pepper Flash 外掛 - -Electron 現在支援 Pepper Flash 外掛,要在 Electron 中使用 Pepper Flash 外掛,你應該手動指定 Pepper Flash 外掛的位置,並在你的應用程式中啟用它。 - -## 準備一份 Flash 外掛 - -在 macOS 和 Linux 上,Pepper Flash 外掛的細節可以透過查看 Chrome 瀏覽器中的 `chrome://plugins` 來得知,它的位置和版本對於 Electron 的 Pepper Flash 支援都有很大的幫助,你可以把它複製一份到別的位置。 - -## 加入 Electron 開關 - -你可以直接加入 `--ppapi-flash-path` 和 `ppapi-flash-version` 到 -Electron 命定列或是在應用程式的 ready 事件之前使用 `app.commandLine.appendSwitch` 方法,並且加入 `browser-window` 的 `plugins` 開關。 - -例如: - -```javascript -// 指定 Flash 路徑 -// Windows 中可能是 /path/to/pepflashplayer.dll -// macOS 中 /path/to/PepperFlashPlayer.plugin -// Linux 中 /path/to/libpepflashplayer.so -app.commandLine.appendSwitch('ppapi-flash-path', '/path/to/libpepflashplayer.so'); - -// 指定 Flash 版本, 例如 v17.0.0.169 -app.commandLine.appendSwitch('ppapi-flash-version', '17.0.0.169'); - -app.on('ready', function() { - mainWindow = new BrowserWindow({ - 'width': 800, - 'height': 600, - 'web-preferences': { - 'plugins': true - } - }); - mainWindow.loadURL('file://' + __dirname + '/index.html'); - // Something else -}); -``` - -## 在一個 `` Tag 中啟用 Flash 外掛 - -把 `plugins` 屬性加入 `` tag。 - -```html - -``` diff --git a/docs-translations/zh-TW/tutorial/using-selenium-and-webdriver.md b/docs-translations/zh-TW/tutorial/using-selenium-and-webdriver.md deleted file mode 100644 index e312ffa4a1d4b..0000000000000 --- a/docs-translations/zh-TW/tutorial/using-selenium-and-webdriver.md +++ /dev/null @@ -1,123 +0,0 @@ -# 使用 Selenium 和 WebDriver - -根據 [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. - -為了與 Electron 一起使用 `chromedriver`,你需要告訴 `chromedriver` 去哪找 Electron 並讓他知道 Electron 是 Chrome 瀏覽器。 - -## 透過 WebDriverJs 設定 - -[WebDriverJs](https://code.google.com/p/selenium/wiki/WebDriverJs) 提供一個 Node 套件來透過 web driver 做測試,我們將使用它作為例子。 - -### 1. 啟動 ChromeDriver - -首先你需要下載 `chromedriver` 執行檔,然後執行它: - -```bash -$ ./chromedriver -Starting ChromeDriver (v2.10.291558) on port 9515 -Only local connections are allowed. -``` - -記住埠號(port number) `9515`,等等會使用到它 - -### 2. 安裝 WebDriverJS - -```bash -$ npm install selenium-webdriver -``` - -### 3. 連接到 ChromeDriver - -與 Electron 一起使用 `selenium-webdriver` 的方法基本上與 upstream 相同,除了你需要手動指定如何連接 chrome driver 和去哪找 Electron 的執行檔: - -```javascript -const webdriver = require('selenium-webdriver'); - -var driver = new webdriver.Builder() - // The "9515" is the port opened by chrome driver. - .usingServer('http://localhost:9515') - .withCapabilities({ - chromeOptions: { - // Here is the path to your Electron binary. - binary: '/Path-to-Your-App.app/Contents/MacOS/Atom', - } - }) - .forBrowser('electron') - .build(); - -driver.get('http://www.google.com'); -driver.findElement(webdriver.By.name('q')).sendKeys('webdriver'); -driver.findElement(webdriver.By.name('btnG')).click(); -driver.wait(function() { - return driver.getTitle().then(function(title) { - return title === 'webdriver - Google Search'; - }); -}, 1000); - -driver.quit(); -``` - -## 透過 WebdriverIO 設定 - -[WebdriverIO](http://webdriver.io/) 提供一個 Node 套件來透過 web driver 做測試。 - -### 1. 啟動 ChromeDriver - -首先你需要下載 `chromedriver` 執行檔,然後執行它: - -```bash -$ chromedriver --url-base=wd/hub --port=9515 -Starting ChromeDriver (v2.10.291558) on port 9515 -Only local connections are allowed. -``` - -記住埠號(port number) `9515`,等等會用到它 - -### 2. 安裝 WebdriverIO - -```bash -$ npm install webdriverio -``` - -### 3. 連接到 chrome driver - -```javascript -const webdriverio = require('webdriverio'); -var options = { - host: "localhost", // Use localhost as chrome driver server - port: 9515, // "9515" is the port opened by chrome driver. - desiredCapabilities: { - browserName: 'chrome', - chromeOptions: { - binary: '/Path-to-Your-App/electron', // Path to your Electron binary. - args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/ - } - } -}; - -var client = webdriverio.remote(options); - -client - .init() - .url('http://google.com') - .setValue('#q', 'webdriverio') - .click('#btnG') - .getTitle().then(function(title) { - console.log('Title was: ' + title); - }) - .end(); -``` - -## 運作流程 - -要在不重新建置 Electron 的情況下測試你的應用程式,只需要 [放置](https://github.com/electron/electron/blob/master/docs/tutorial/application-distribution.md) 你的應用程式到 Electron 的資源目錄中即可。 - -或者,傳遞一個指向你應用程式資料夾的參數來透過你的 Electron 執行檔運行,這會減少複製你應用程式到 Electron 資源資料夾的需求。 - -[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/ 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 9c9e27900398a..02d5d1331ca29 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,99 +1,159 @@ +# Official Guides + Please make sure that you use the documents that match your Electron version. The version number should be a part of the page URL. If it's not, you are probably using the documentation of a development branch which may contain API -changes that are not compatible with your Electron version. If that's the case, -you can switch to a different version of the documentation at the -[available versions](http://electron.atom.io/docs/) list on atom.io, or if -you're using the GitHub interface, open the "Switch branches/tags" dropdown and -select the tag that matches your version. +changes that are not compatible with your Electron version. To view older +versions of the documentation, you can +[browse by tag](https://github.com/electron/electron/tree/v1.4.0) +on GitHub by opening the "Switch branches/tags" dropdown and selecting the tag +that matches your version. ## FAQ -There are questions that are asked quite often, check this out before creating +There are questions that are asked quite often. Check this out before creating an issue: * [Electron FAQ](faq.md) -## Guides - -* [Supported Platforms](tutorial/supported-platforms.md) -* [Security](tutorial/security.md) -* [Electron Versioning](tutorial/electron-versioning.md) -* [Application Distribution](tutorial/application-distribution.md) -* [Mac App Store Submission Guide](tutorial/mac-app-store-submission-guide.md) -* [Windows Store Guide](tutorial/windows-store-guide.md) -* [Application Packaging](tutorial/application-packaging.md) -* [Using Native Node Modules](tutorial/using-native-node-modules.md) -* [Debugging Main Process](tutorial/debugging-main-process.md) -* [Using Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md) -* [DevTools Extension](tutorial/devtools-extension.md) -* [Using Pepper Flash Plugin](tutorial/using-pepper-flash-plugin.md) -* [Using Widevine CDM Plugin](tutorial/using-widevine-cdm-plugin.md) -* [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md) -* [Offscreen Rendering](tutorial/offscreen-rendering.md) - -## Tutorials - -* [Quick Start](tutorial/quick-start.md) -* [Desktop Environment Integration](tutorial/desktop-environment-integration.md) -* [Online/Offline Event Detection](tutorial/online-offline-events.md) +## Guides and Tutorials + +### Getting started + +* [Introduction](tutorial/introduction.md) +* [Process Model](tutorial/process-model.md) + +### Learning the basics + +* Adding Features to Your App + * [Notifications](tutorial/notifications.md) + * [Recent Documents](tutorial/recent-documents.md) + * [Application Progress](tutorial/progress-bar.md) + * [Custom Dock Menu](tutorial/macos-dock.md) + * [Custom Windows Taskbar](tutorial/windows-taskbar.md) + * [Custom Linux Desktop Actions](tutorial/linux-desktop-actions.md) + * [Keyboard Shortcuts](tutorial/keyboard-shortcuts.md) + * [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-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) + +### Advanced steps + +* Application Architecture + * [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) + * [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md) + * [DevTools Extension](tutorial/devtools-extension.md) + * [Automated Testing](tutorial/automated-testing.md) + * [REPL](tutorial/repl.md) +* [Distribution](tutorial/application-distribution.md) + * [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) +* [Getting Support](tutorial/support.md) + +## Detailed Tutorials + +These individual tutorials expand on topics discussed in the guide above. + +* [Installing Electron](tutorial/installation.md) + * [Proxies](tutorial/installation.md#proxies) + * [Custom Mirrors and Caches](tutorial/installation.md#custom-mirrors-and-caches) + * [Troubleshooting](tutorial/installation.md#troubleshooting) +* Electron Releases & Developer Feedback + * [Versioning Policy](tutorial/electron-versioning.md) + * [Release Timelines](tutorial/electron-timelines.md) + +--- + +* [Glossary of Terms](glossary.md) ## API References -* [Synopsis](api/synopsis.md) * [Process Object](api/process.md) -* [Supported Chrome Command Line Switches](api/chrome-command-line-switches.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) -* [`` Tag](api/web-view-tag.md) +* [`-electron-corner-smoothing` CSS Rule](api/corner-smoothing-css.md) +* [`` Tag](api/webview-tag.md) * [`window.open` Function](api/window-open.md) ### Modules for the Main Process: * [app](api/app.md) * [autoUpdater](api/auto-updater.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) +* [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) -* [screen](api/screen.md) -* [shell](api/shell.md) +* [shell](api/shell.md) (non-sandboxed renderers only) ## Development -* [Coding Style](development/coding-style.md) -* [Source Code Directory Structure](development/source-code-directory-structure.md) -* [Technical Differences to NW.js (formerly node-webkit)](development/atom-shell-vs-node-webkit.md) -* [Build System Overview](development/build-system-overview.md) -* [Build Instructions (macOS)](development/build-instructions-osx.md) -* [Build Instructions (Windows)](development/build-instructions-windows.md) -* [Build Instructions (Linux)](development/build-instructions-linux.md) -* [Debug Instructions (macOS)](development/debug-instructions-macos.md) -* [Debug Instructions (Windows)](development/debug-instructions-windows.md) -* [Setting Up Symbol Server in debugger](development/setting-up-symbol-server.md) +See [development/README.md](development/README.md) 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 1f760b4636154..0000000000000 --- a/docs/api/accelerator.md +++ /dev/null @@ -1,55 +0,0 @@ -# Accelerator - -> Define keyboard shortcuts. - -Accelerators can contain multiple modifiers and key codes, combined by -the `+` character. - -Examples: - -* `CommandOrControl+A` -* `CommandOrControl+Shift+Z` - -## 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` -* Punctuations like `~`, `!`, `@`, `#`, `$`, etc. -* `Plus` -* `Space` -* `Tab` -* `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` diff --git a/docs/api/app.md b/docs/api/app.md index ca1a36c9f984a..db15d2c366788 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -2,11 +2,14 @@ > Control your application's event lifecycle. +Process: [Main](../glossary.md#main-process) + The following example shows how to quit the application when the last window is closed: -```javascript -const {app} = require('electron') +```js +const { app } = require('electron') + app.on('window-all-closed', () => { app.quit() }) @@ -21,14 +24,28 @@ 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 just do everything in the `ready` event handler. +In most cases, you should do everything in the `ready` event handler. ### Event: 'ready' -Emitted when Electron has finished initialization. +Returns: + +* `event` Event +* `launchInfo` Record\ | [NotificationResponse](structures/notification-response.md) _macOS_ + +Emitted once, when Electron has finished initializing. On macOS, `launchInfo` +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' @@ -48,9 +65,18 @@ Returns: * `event` Event Emitted before the application starts closing its windows. -Calling `event.preventDefault()` will prevent the default behaviour, which is +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] +> 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' Returns: @@ -58,12 +84,16 @@ Returns: * `event` Event Emitted when all windows have been closed and the application will quit. -Calling `event.preventDefault()` will prevent the default behaviour, which is +Calling `event.preventDefault()` will prevent the default behavior, which is 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. + ### Event: 'quit' Returns: @@ -73,12 +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. + ### 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 @@ -97,32 +131,60 @@ filepath. Returns: * `event` Event -* `url` String +* `url` string -Emitted when the user wants to open a URL with the application. The URL scheme -must be registered to be opened by your application. +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 +to re-launch the application when it's already running, or clicking on the +application's dock or taskbar icon. + +### Event: 'did-become-active' _macOS_ + +Returns: + +* `event` Event + +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. 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 application is activated, which usually happens when the user -clicks on the application's dock icon. +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` Object - Contains app-specific state stored by the activity on +* `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 @@ -133,12 +195,71 @@ ID as the activity's source app and that supports the activity's type. Supported activity types are specified in the app's `Info.plist` under the `NSUserActivityTypes` key. +### Event: 'will-continue-activity' _macOS_ + +Returns: + +* `event` Event +* `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 +to be resumed. You should call `event.preventDefault()` if you want to handle +this event. + +### Event: 'continue-activity-error' _macOS_ + +Returns: + +* `event` Event +* `type` string - A string identifying the activity. Maps to + [`NSUserActivity.activityType`][activity-type]. +* `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. + +### Event: 'activity-was-continued' _macOS_ + +Returns: + +* `event` Event +* `type` string - A string identifying the activity. Maps to + [`NSUserActivity.activityType`][activity-type]. +* `userInfo` unknown - Contains app-specific state stored by the activity. + +Emitted during [Handoff][handoff] after an activity from this device was successfully +resumed on another one. + +### Event: 'update-activity-state' _macOS_ + +Returns: + +* `event` Event +* `type` string - A string identifying the activity. Maps to + [`NSUserActivity.activityType`][activity-type]. +* `userInfo` unknown - Contains app-specific state stored by the activity. + +Emitted when [Handoff][handoff] is about to be resumed on another device. If you need to update the state to be transferred, you should call `event.preventDefault()` immediately, construct a new `userInfo` dictionary and call `app.updateCurrentActivity()` in a timely manner. Otherwise, the operation will fail and `continue-activity-error` will be called. + +### Event: 'new-window-for-tab' _macOS_ + +Returns: + +* `event` Event + +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: 'browser-window-blur' Returns: * `event` Event -* `window` BrowserWindow +* `window` [BrowserWindow](browser-window.md) Emitted when a [browserWindow](browser-window.md) gets blurred. @@ -147,7 +268,7 @@ Emitted when a [browserWindow](browser-window.md) gets blurred. Returns: * `event` Event -* `window` BrowserWindow +* `window` [BrowserWindow](browser-window.md) Emitted when a [browserWindow](browser-window.md) gets focused. @@ -156,7 +277,7 @@ Emitted when a [browserWindow](browser-window.md) gets focused. Returns: * `event` Event -* `window` BrowserWindow +* `window` [BrowserWindow](browser-window.md) Emitted when a new [browserWindow](browser-window.md) is created. @@ -165,7 +286,7 @@ Emitted when a new [browserWindow](browser-window.md) is created. Returns: * `event` Event -* `webContents` WebContents +* `webContents` [WebContents](web-contents.md) Emitted when a new [webContents](web-contents.md) is created. @@ -175,24 +296,19 @@ Returns: * `event` Event * `webContents` [WebContents](web-contents.md) -* `url` URL -* `error` String - The error code -* `certificate` Object - * `data` Buffer - PEM encoded data - * `issuerName` String - Issuer's Common Name - * `subjectName` String - Subject's Common Name - * `serialNumber` String - Hex value represented string - * `validStart` Integer - Start date of the certificate being valid in seconds - * `validExpiry` Integer - End date of the certificate being valid in seconds - * `fingerprint` String - Fingerprint of the certificate +* `url` string +* `error` string - The error code +* `certificate` [Certificate](structures/certificate.md) * `callback` Function + * `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 -const {app} = require('electron') +```js +const { app } = require('electron') app.on('certificate-error', (event, webContents, url, error, certificate, callback) => { if (url === 'https://github.com') { @@ -212,25 +328,19 @@ Returns: * `event` Event * `webContents` [WebContents](web-contents.md) * `url` URL -* `certificateList` [Objects] - * `data` Buffer - PEM encoded data - * `issuerName` String - Issuer's Common Name - * `subjectName` String - Subject's Common Name - * `serialNumber` String - Hex value represented string - * `validStart` Integer - Start date of the certificate being valid in seconds - * `validExpiry` Integer - End date of the certificate being valid in seconds - * `fingerprint` String - Fingerprint of the certificate +* `certificateList` [Certificate[]](structures/certificate.md) * `callback` Function + * `certificate` [Certificate](structures/certificate.md) (optional) Emitted when a client certificate is requested. The `url` corresponds to the navigation entry requesting the client certificate -and `callback` needs to be called with an entry filtered from the list. Using +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 -const {app} = require('electron') +```js +const { app } = require('electron') app.on('select-client-certificate', (event, webContents, url, list, callback) => { event.preventDefault() @@ -243,44 +353,92 @@ app.on('select-client-certificate', (event, webContents, url, list, callback) => Returns: * `event` Event -* `webContents` [WebContents](web-contents.md) -* `request` Object - * `method` String +* `webContents` [WebContents](web-contents.md) (optional) +* `authenticationResponseDetails` Object * `url` URL - * `referrer` 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) -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 +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 -const {app} = require('electron') +```js +const { app } = require('electron') -app.on('login', (event, webContents, request, authInfo, callback) => { +app.on('login', (event, webContents, details, authInfo, callback) => { event.preventDefault() callback('username', 'secret') }) ``` -### Event: 'gpu-process-crashed' +If `callback` is called without a username or password, the authentication +request will be cancelled and the authentication error will be returned to the +page. + +### Event: 'gpu-info-update' + +Emitted whenever there is a GPU info update. + +### Event: 'render-process-gone' + +Returns: + +* `event` Event +* `webContents` [WebContents](web-contents.md) +* `details` [RenderProcessGoneDetails](structures/render-process-gone-details.md) + +Emitted when the renderer process unexpectedly disappears. This is normally +because it was crashed or killed. -Emitted when the gpu process crashes. +### Event: 'child-process-gone' + +Returns: + +* `event` Event +* `details` Object + * `type` string - Process type. One of the following values: + * `Utility` + * `Zygote` + * `Sandbox helper` + * `GPU` + * `Pepper Plugin` + * `Pepper Plugin Broker` + * `Unknown` + * `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 + * `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` 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 +because it was crashed or killed. It does not include renderer processes. ### Event: 'accessibility-support-changed' _macOS_ _Windows_ 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 @@ -288,12 +446,61 @@ assistive technologies, such as screen readers, are enabled or disabled. See https://www.chromium.org/developers/design-documents/accessibility for more details. +### Event: 'session-created' + +Returns: + +* `session` [Session](session.md) + +Emitted when Electron has created a new `session`. + +```js +const { app } = require('electron') + +app.on('session-created', (session) => { + console.log(session) +}) +``` + +### Event: 'second-instance' + +Returns: + +* `event` Event +* `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()`. + +`argv` is an Array of the second instance's command line arguments, +and `workingDirectory` is its current working directory. Usually +applications respond to this by making their primary window focused and +non-minimized. + +> [!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`. + ## 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()` @@ -305,277 +512,594 @@ This method guarantees that all `beforeunload` and `unload` event handlers are correctly executed. It is possible that a window cancels the quitting by returning `false` in the `beforeunload` event handler. -### `app.exit(exitCode)` +### `app.exit([exitCode])` -* `exitCode` Integer +* `exitCode` Integer (optional) -Exits immediately with `exitCode`. +Exits immediately with `exitCode`. `exitCode` defaults to 0. -All windows will be closed immediately without asking user and the `before-quit` +All windows will be closed immediately without asking the user, and the `before-quit` and `will-quit` events will not be emitted. ### `app.relaunch([options])` * `options` Object (optional) - * `args` Array (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. +By default, the new instance will use the same working directory and command line +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 -const {app} = require('electron') +```js +const { app } = require('electron') -app.relaunch({args: process.argv.slice(1) + ['--relaunch']}) +app.relaunch({ args: process.argv.slice(1).concat(['--relaunch']) }) app.exit(0) ``` -### `app.focus()` +### `app.isReady()` + +Returns `boolean` - `true` if Electron has finished initializing, `false` otherwise. +See also `app.whenReady()`. + +### `app.whenReady()` + +Returns `Promise` - fulfilled when Electron is initialized. +May be used as a convenient alternative to checking `app.isReady()` +and subscribing to the `ready` event if the app is not ready yet. -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. +### `app.focus([options])` + +* `options` Object (optional) + * `steal` boolean _macOS_ - Make the receiver the active app even if another app is + currently active. + +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 them. +### `app.setAppLogsPath([path])` + +* `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)`. + +Calling `app.setAppLogsPath()` without a `path` parameter will result in this directory being set to `~/Library/Logs/YourAppName` on _macOS_, and inside the `userData` directory on _Linux_ and _Windows_. + ### `app.getAppPath()` -Returns the current application directory. +Returns `string` - The current application directory. ### `app.getPath(name)` -* `name` String - -Retrieves a path to a special directory or file associated with `name`. On -failure an `Error` is thrown. - -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. -* `temp` Temporary directory. -* `exe` The current executable file. -* `module` The `libchromiumcontent` library. -* `desktop` The current user's Desktop directory. -* `documents` Directory for a user's "My Documents". -* `downloads` Directory for a user's downloads. -* `music` Directory for a user's music. -* `pictures` Directory for a user's pictures. -* `videos` Directory for a user's videos. -* `pepperFlashSystemPlugin` Full path to the system version of the Pepper Flash plugin. +* `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 + * `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 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. + * `music` Directory for a user's music. + * `pictures` Directory for a user's pictures. + * `videos` Directory for a user's videos. + * `recent` Directory for the user's recent files (Windows only). + * `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 +failure, an `Error` is thrown. + +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 +* `options` Object (optional) + * `size` string + * `small` - 16x16 + * `normal` - 32x32 + * `large` - 48x48 on _Linux_, 32x32 on _Windows_, unsupported on _macOS_. + +Returns `Promise` - fulfilled with the app's icon, which is a [NativeImage](native-image.md). + +Fetches a path's associated icon. + +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`. + +On _Linux_ and _macOS_, icons depend on the application associated with file mime type. ### `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, the directory will be -created by this method. On failure an `Error` is thrown. +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. +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 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 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 lowercased name, according +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` field, which is your application's full capitalized name, and which will be 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. + ### `app.getLocale()` -Returns 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). + +> [!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. + +> [!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'] +``` + +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. -This list is managed by the OS. On Windows you can visit the list from the task -bar, and on macOS you can visit it from dock menu. +This list is managed by the OS. On Windows, you can visit the list from the task +bar, and on macOS, you can visit it from dock menu. ### `app.clearRecentDocuments()` _macOS_ _Windows_ Clears the recent documents list. -### `app.setAsDefaultProtocolClient(protocol)` _macOS_ _Windows_ +### `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, + 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. + Defaults to `process.execPath` +* `args` string[] (optional) _Windows_ - Arguments passed to the executable. + Defaults to an empty array -* `protocol` String - The name of your protocol, without `://`. If you want your - app to handle `electron://` links, call this method with `electron` as the - parameter. +Returns `boolean` - Whether the call succeeded. -This method 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. 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. +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. +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 can not be modified at runtime. You can however -change the file with a simple text editor or script during build time. -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. -The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally. +> [!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). -### `app.removeAsDefaultProtocolClient(protocol)` _macOS_ _Windows_ +The API uses the Windows Registry and `LSSetDefaultHandlerForURLScheme` internally. -* `protocol` String - The name of your protocol, without `://`. +### `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 + +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)` _macOS_ _Windows_ +### `app.isDefaultProtocolClient(protocol[, path, args])` -* `protocol` String - The name of your protocol, without `://`. +* `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 -This method checks if the current executable is the default handler for a protocol -(aka URI scheme). If so, it will return true. Otherwise, it will return false. +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. +The API uses the Windows Registry and `LSCopyDefaultHandlerForURLScheme` internally. -### `app.setUserTasks(tasks)` _Windows_ +### `app.getApplicationNameForProtocol(url)` -* `tasks` Array - Array of `Task` objects +* `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://`). -Adds `tasks` to the [Tasks][tasks] category of the JumpList on Windows. +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. + Expect a different format on Linux, possibly with a `.desktop` suffix. -`tasks` is an array of `Task` objects in the following format: +This method returns the application name of the default handler for the protocol +(aka URI scheme) of a URL. -`Task` Object: +### `app.getApplicationInfoForProtocol(url)` -* `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 - 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 - 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` Integer - 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. +* `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://`). -### `app.makeSingleInstance(callback)` +Returns `Promise` - Resolve with an object containing the following: -* `callback` Function +* `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. -This method makes your application a Single Instance Application - instead of -allowing multiple instances of your app to run, this will ensure that only a -single instance of your app is running, and other instances signal this -instance and exit. +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. -`callback` will be called with `callback(argv, workingDirectory)` when a second -instance has been executed. `argv` is an Array of the second instance's command -line arguments, and `workingDirectory` is its current working directory. Usually -applications respond to this by making their primary window focused and -non-minimized. +### `app.setUserTasks(tasks)` _Windows_ -The `callback` is guaranteed to be executed after the `ready` event of `app` -gets emitted. +* `tasks` [Task[]](structures/task.md) - Array of `Task` objects + +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. + +> [!NOTE] +> If you'd like to customize the Jump List even more use +> `app.setJumpList(categories)` instead. + +### `app.getJumpListSettings()` _Windows_ + +Returns `Object`: + +* `minItems` Integer - The minimum number of items that will be shown in the + Jump List (for a more detailed description of this value see the + [MSDN docs][JumpListBeginListMSDN]). +* `removedItems` [JumpListItem[]](structures/jump-list-item.md) - Array of `JumpListItem` + objects that correspond to items that the user has explicitly removed from custom categories in the + Jump List. These items must not be re-added to the Jump List in the **next** + call to `app.setJumpList()`, Windows will not display any custom category + that contains any of the removed items. + +### `app.setJumpList(categories)` _Windows_ + +* `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: + +* `ok` - Nothing went wrong. +* `error` - One or more errors occurred, enable runtime logging to figure out + the likely cause. +* `invalidSeparatorError` - An attempt was made to add a separator to a + custom category in the Jump List. Separators are only allowed in the + standard `Tasks` category. +* `fileTypeRegistrationError` - An attempt was made to add a file link to + the Jump List for a file type the app isn't registered to handle. +* `customCategoryAccessDeniedError` - Custom categories can't be added to the + Jump List due to user privacy or group policy settings. + +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 +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] +> 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: + +```js +const { app } = require('electron') + +app.setJumpList([ + { + type: 'custom', + name: 'Recent Projects', + items: [ + { type: 'file', path: 'C:\\Projects\\project1.proj' }, + { type: 'file', path: 'C:\\Projects\\project2.proj' } + ] + }, + { // has a name so `type` is assumed to be "custom" + name: 'Tools', + items: [ + { + type: 'task', + title: 'Tool A', + program: process.execPath, + args: '--run-tool-a', + iconPath: process.execPath, + iconIndex: 0, + description: 'Runs Tool A' + }, + { + type: 'task', + title: 'Tool B', + program: process.execPath, + args: '--run-tool-b', + iconPath: process.execPath, + iconIndex: 0, + description: 'Runs Tool B' + } + ] + }, + { type: 'frequent' }, + { // has no name and no type so `type` is assumed to be "tasks" + items: [ + { + type: 'task', + title: 'New Project', + program: process.execPath, + args: '--new-project', + description: 'Create a new project.' + }, + { type: 'separator' }, + { + type: 'task', + title: 'Recover Project', + program: process.execPath, + args: '--recover-project', + description: 'Recover Project' + } + ] + } +]) +``` -This method returns `false` if your process is the primary instance of the -application and your app should continue loading. And returns `true` if your -process has sent its parameters to another instance, and you should immediately -quit. +### `app.requestSingleInstanceLock([additionalData])` -On macOS the system enforces single instance automatically when users try to open +* `additionalData` Record\ (optional) - A JSON object containing additional data to send to the first instance. + +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, +you can assume that another instance of your application is already running with +the lock and exit immediately. + +I.e. This method returns `true` if your process is the primary instance of your +application and your app should continue loading. It returns `false` if your +process should immediately quit as it has sent its parameters to another +instance that has already acquired the lock. + +On macOS, the system enforces single instance automatically when users try to open a second instance of your app in Finder, and the `open-file` and `open-url` events will be emitted for that. However when users start your app in command -line the system's single instance mechanism will be bypassed and you have to +line, the system's single instance mechanism will be bypassed, and you have to 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 shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => { - // Someone tried to run a second instance, we should focus our window. - if (myWindow) { - if (myWindow.isMinimized()) myWindow.restore() - myWindow.focus() - } -}) +const additionalData = { myKey: 'myValue' } +const gotTheLock = app.requestSingleInstanceLock(additionalData) -if (shouldQuit) { +if (!gotTheLock) { app.quit() +} else { + 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() + myWindow.focus() + } + }) + + app.whenReady().then(() => { + myWindow = new BrowserWindow({}) + myWindow.loadURL('https://electronjs.org') + }) } - -// Create myWindow, load the rest of the app, etc... -app.on('ready', () => { -}) ``` -### `app.releaseSingleInstance()` +### `app.hasSingleInstanceLock()` + +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 +`app.requestSingleInstanceLock()` and release with +`app.releaseSingleInstanceLock()` -Releases all locks that were created by `makeSingleInstance`. This will allow -multiple instances of the application to once again run side by side. +### `app.releaseSingleInstanceLock()` + +Releases all locks that were created by `requestSingleInstanceLock`. This will +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` Object - App-specific state to store for use by another device. -* `webpageURL` String - The webpage to load in a browser if no suitable app is +* `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 installed on the resuming device. The scheme must be `http` or `https`. Creates an `NSUserActivity` and sets it as the current activity. The activity @@ -583,25 +1107,183 @@ is eligible for [Handoff][handoff] to another device afterward. ### `app.getCurrentActivityType()` _macOS_ -Returns the type of the currently running activity. +Returns `string` - The type of the currently running activity. + +### `app.invalidateCurrentActivity()` _macOS_ + +Invalidates the current [Handoff][handoff] user activity. + +### `app.resignCurrentActivity()` _macOS_ + +Marks the current [Handoff][handoff] user activity as inactive without invalidating it. + +### `app.updateCurrentActivity(type, userInfo)` _macOS_ + +* `type` string - Uniquely identifies the activity. Maps to + [`NSUserActivity.activityType`][activity-type]. +* `userInfo` any - App-specific state to store for use by another device. + +Updates the current activity if its type matches `type`, merging the entries from +`userInfo` into its current `userInfo` dictionary. ### `app.setAppUserModelId(id)` _Windows_ -* `id` String +* `id` string Changes the [Application User Model ID][app-user-model-id] to `id`. -### `app.importCertificate(options, callback)` _LINUX_ +### `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'. + +Sets the activation policy for a given app. + +Activation policy types: + +* 'regular' - The application is an ordinary app that appears in the Dock and may have a user interface. +* 'accessory' - The application doesn’t appear in the Dock and doesn’t have a menu bar, but it may be activated programmatically or by clicking on one of its windows. +* 'prohibited' - The application doesn’t appear in the Dock and may not create windows or be activated. + +### `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://code.google.com/p/chromium/codesearch#chromium/src/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.configureWebAuthn(options)` _macOS_ + +* `options` Object + * `touchID` Object (optional) - Enables the Touch ID / Secure Enclave platform + authenticator for [Web Authentication](https://www.w3.org/TR/webauthn-2/) + requests. + * `keychainAccessGroup` string - The keychain access group that WebAuthn + credentials will be stored under. This value **must** also be present in + your app's `keychain-access-groups` code-signing entitlement, and is + typically of the form `..webauthn`. + * `promptReason` string (optional) - Customizes the reason text shown in + the macOS Touch ID prompt. macOS renders the prompt as + `"" is trying to `, so the value should be a + lowercase sentence fragment. An optional `$1` placeholder is replaced + with the relying party ID (e.g. `example.com`) of the request being + authenticated. Defaults to `verify your identity on $1`. + +Configures platform authenticators for the Web Authentication API +(`navigator.credentials.create()` / `navigator.credentials.get()`). Until this +is called, `PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()` +resolves to `false` and platform-authenticator requests are not serviced. + +When `touchID` is provided, WebAuthn credentials are stored in the macOS +keychain and bound to this device's Secure Enclave. Electron automatically +generates and persists a per-[`session`](session.md) metadata secret so that +credentials created in one partition are not visible to another. + +```js +const { app } = require('electron') + +app.configureWebAuthn({ + touchID: { + keychainAccessGroup: 'A1B2C3D4E5.com.example.app.webauthn', + promptReason: 'sign in to $1' + } +}) +``` + +With the matching entitlement in your app's `entitlements.plist`: + +```xml +keychain-access-groups + + A1B2C3D4E5.com.example.app.webauthn + +``` + +> [!NOTE] +> Touch ID WebAuthn credentials are device-bound and are not synced via iCloud +> Keychain. They are only available on Macs with a Secure Enclave (Apple +> silicon, or Intel Macs with a T2 chip). ### `app.disableHardwareAcceleration()` @@ -609,145 +1291,521 @@ Disables hardware acceleration for current app. This method can only be called before app is ready. -### `app.setBadgeCount(count)` _Linux_ _macOS_ +### `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 process crashes too frequently. This function +disables that behavior. + +This method can only be called before app is ready. -* `count` Integer +### `app.getAppMetrics()` -Sets the counter badge for current app. Setting the count to `0` will hide the -badge. Returns `true` when the call succeeded, otherwise returns `false`. +Returns [`ProcessMetric[]`](structures/process-metric.md): Array of `ProcessMetric` objects that correspond to memory and CPU usage statistics of all the processes associated with the app. -On macOS it shows on the dock icon. On Linux it only works for Unity launcher, +### `app.getGPUFeatureStatus()` -**Note:** Unity launcher requires the exsistence of a `.desktop` file to work, -for more information please read [Desktop Environment Integration][unity-requiremnt]. +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. + +### `app.getGPUInfo(infoType)` + +* `infoType` string - Can be `basic` or `complete`. + +Returns `Promise` + +For `infoType` equal to `complete`: + Promise is fulfilled with `Object` containing all the GPU Information as in [chromium's GPUInfo object](https://chromium.googlesource.com/chromium/src/+/4178e190e9da409b055e5dff469911ec6f6b716f/gpu/config/gpu_info.cc). This includes the version and driver information that's shown on `chrome://gpu` page. + +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: + { + amdSwitchable: true, + canSupportThreadedTextureMailbox: false, + directComposition: false, + directRendering: true, + glResetNotificationStrategy: 0, + inProcessGpu: true, + initializationTime: 0, + jpegDecodeAcceleratorSupported: false, + optimus: false, + passthroughCmdDecoder: false, + sandboxed: false, + softwareRendering: false, + supportsOverlays: false, + videoDecodeAcceleratorFlags: 0 + }, + gpuDevice: + [{ active: true, deviceId: 26657, vendorId: 4098 }, + { active: false, deviceId: 3366, vendorId: 32902 }], + machineModelName: 'MacBookPro', + machineModelVersion: '11.5' +} +``` -### `app.getBadgeCount()` _Linux_ _macOS_ +Using `basic` should be preferred if only basic information like `vendorId` or `deviceId` is needed. -Returns the current value displayed in the counter badge. +Promise is rejected if the GPU is completely disabled, i.e. no hardware and software implementations are available. -### `app.isUnityRunning()` _Linux_ +### `app.setBadgeCount([count])` _macOS_ -Returns whether current desktop environment is Unity launcher. +* `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). -### `app.getLoginItemSettings()` _macOS_ _Windows_ +Returns `boolean` - Whether the call succeeded. -Return an Object with the login item settings of the app. +Sets the Dock icon counter badge for current app. Setting the count to `0` will hide the +badge. -* `openAtLogin` Boolean - `true` if the app is set to open at login. -* `openAsHidden` Boolean - `true` if the app is set to open as hidden at login. - This setting is only supported on macOS. -* `wasOpenedAtLogin` Boolean - `true` if the app was opened at login - automatically. This setting is only supported on macOS. -* `wasOpenedAsHidden` Boolean - `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 only supported on macOS. -* `restoreState` Boolean - `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 only supported on macOS. +> [!NOTE] +> You need to ensure that your application has the permission +> to display notifications for this method to work. + +### `app.getBadgeCount()` _macOS_ + +Returns `Integer` - The current value displayed in the counter badge. + +### `app.getLoginItemSettings([options])` _macOS_ _Windows_ + +* `options` Object (optional) + * `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_ _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_ - 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 - `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 - `true` to open the app as hidden. Defaults to - `false`. The user can edit this setting from the System Preferences so - `app.getLoginItemStatus().wasOpenedAsHidden` should be checked when the app - is opened to know the current value. This setting is only supported on - macOS. + * `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 + 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. + Defaults to `true`. + * `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 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') + +const appFolder = path.dirname(process.execPath) +const ourExeName = path.basename(process.execPath) +const stubLauncher = path.resolve(appFolder, '..', ourExeName) + +app.setLoginItemSettings({ + openAtLogin: true, + path: stubLauncher, + args: [ + // 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 a `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 details. -### `app.commandLine.appendSwitch(switch[, value])` +### `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 + +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. 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)`. 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. 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. + +If you do not set `credits` but still wish to surface them in your app, AppKit will look for a file named "Credits.html", "Credits.rtf", and "Credits.rtfd", in that order, in the bundle returned by the NSBundle class method main. The first file found is used, and if none is found, the info area is left blank. See Apple [documentation](https://developer.apple.com/documentation/appkit/nsaboutpaneloptioncredits?language=objc) for more information. + +### `app.isEmojiPanelSupported()` + +Returns `boolean` - whether or not the current OS version allows for native emoji pickers. + +### `app.showEmojiPanel()` _macOS_ _Windows_ + +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. + +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 +const { app, dialog } = require('electron') + +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() +``` + +Start accessing a security scoped resource. With this method Electron applications that are packaged for the Mac App Store may reach outside their sandbox to access files chosen by the user. See [Apple's documentation](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) for a description of how this system works. + +### `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`](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 +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. + +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 +the user to confirm the operation, you may do so using the +[`dialog`](dialog.md) API. + +**NOTE:** This method throws errors if anything other than the user causes the +move to fail. For instance if the user cancels the authorization dialog, this +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 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') { + return dialog.showMessageBoxSync({ + type: 'question', + buttons: ['Halt Move', 'Continue Move'], + defaultId: 0, + message: 'An app of this name already exists' + }) === 1 + } + } +}) +``` + +Would mean that if an app already exists in the user directory, if the user chooses to 'Continue Move' then the function would continue with its default behavior and the existing app will be trashed and the active app moved into its place. + +### `app.isSecureKeyboardEntryEnabled()` _macOS_ + +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` + +Set the `Secure Keyboard Entry` is enabled in your application. + +By using this API, important information such as password and other sensitive information can be prevented from being intercepted by other processes. + +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. -Append a switch (with optional `value`) to Chromium's command line. +### `app.setProxy(config)` -**Note:** This will not affect `process.argv`, and is mainly used by developers -to control some low-level Chromium behaviors. +* `config` [ProxyConfig](structures/proxy-config.md) -### `app.commandLine.appendArgument(value)` +Returns `Promise` - Resolves when the proxy setting process is complete. -Append an argument to Chromium's command line. The argument will be quoted -correctly. +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). -**Note:** This will not affect `process.argv`. +This method can only be called after app is ready. -### `app.dock.bounce([type])` _macOS_ +### `app.resolveProxy(url)` + +* `url` URL -* `type` String (optional) - Can be `critical` or `informational`. The default is - `informational` +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). -When `critical` is passed, the dock icon will bounce until either the -application becomes active or the request is canceled. +### `app.setClientCertRequestPasswordHandler(handler)` _Linux_ -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. +* `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 an ID representing the request. + Returns `Promise` - Resolves with the password -### `app.dock.cancelBounce(id)` _macOS_ +The handler is called when a password is needed to unlock a client certificate for +`hostname`. -* `id` Integer +```js +const { app } = require('electron') -Cancel the bounce of `id`. +async function passwordPromptUI (text) { + return new Promise((resolve, reject) => { + // display UI to prompt user for password + // ... + // ... + resolve('the password') + }) +} -### `app.dock.downloadFinished(filePath)` _macOS_ +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 +}) +``` -* `filePath` String +## Properties -Bounces the Downloads stack if the filePath is inside the Downloads folder. +### `app.accessibilitySupportEnabled` _macOS_ _Windows_ -### `app.dock.setBadge(text)` _macOS_ +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. -* `text` String +See [Chromium's accessibility docs](https://www.chromium.org/developers/design-documents/accessibility) for more details. Disabled by default. -Sets the string to be displayed in the dock’s badging area. +This API must be called after the `ready` event is emitted. -### `app.dock.getBadge()` _macOS_ +> [!NOTE] +> Rendering accessibility tree can significantly affect the performance of your app. It should not be enabled by default. -Returns the badge string of the dock. +### `app.applicationMenu` -### `app.dock.hide()` _macOS_ +A `Menu | null` property that returns [`Menu`](menu.md) if one has been set and `null` otherwise. +Users can pass a [Menu](menu.md) to set this property. -Hides the dock icon. +### `app.badgeCount` _macOS_ -### `app.dock.show()` _macOS_ +An `Integer` property that returns the badge count for current app. Setting the count to `0` will hide the badge. Setting this with any nonzero integer shows the count on the Dock icon. -Shows the dock icon. +> [!NOTE] +> You need to ensure that your application has the permission +> to display notifications for this property to take effect. -### `app.dock.isVisible()` _macOS_ +### `app.commandLine` _Readonly_ -Returns whether the dock icon is visible. -The `app.dock.show()` call is asynchronous so this method might not -return true immediately after that call. +A [`CommandLine`](./command-line.md) object that allows you to read and manipulate the +command line arguments that Chromium uses. -### `app.dock.setMenu(menu)` _macOS_ +### `app.dock` _macOS_ _Readonly_ -* `menu` [Menu](menu.md) +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. -Sets the application's [dock menu][dock-menu]. +### `app.isPackaged` _Readonly_ -### `app.dock.setIcon(image)` _macOS_ +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. -* `image` [NativeImage](native-image.md) +### `app.toastActivatorCLSID` _Windows_ _Readonly_ -Sets the `image` associated with this dock icon. +A `string` property that returns the app's [Toast Activator CLSID][toast-activator-clsid]. -[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 -[tasks]:http://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/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-requiremnt]: ../tutorial/desktop-environment-integration.md#unity-launcher-shortcuts-linux +[mas-builds]: ../tutorial/mac-app-store-submission-guide.md +[Squirrel-Windows]: https://github.com/Squirrel/Squirrel.Windows +[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. + +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` +field, which is your application's full capitalized name, and which will be +preferred over `name` by Electron. + +### `app.userAgentFallback` + +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.runningUnderARM64Translation` _Readonly_ _macOS_ _Windows_ + +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 mistakenly running the x64 version under Rosetta or WOW. diff --git a/docs/api/auto-updater.md b/docs/api/auto-updater.md index 20ba44c721c51..5472904f106cf 100644 --- a/docs/api/auto-updater.md +++ b/docs/api/auto-updater.md @@ -2,53 +2,76 @@ > Enable apps to automatically update themselves. -The `autoUpdater` module provides an interface for the -[Squirrel](https://github.com/Squirrel) framework. +Process: [Main](../glossary.md#main-process) -You can quickly launch a multi-platform release server for distributing your -application by using one of these projects: +**See also: [A detailed guide about how to implement updates in your application](../tutorial/updates.md).** -- [nuts][nuts]: *A smart release server for your applications, using GitHub as a backend. Auto-updates with Squirrel (Mac & Windows)* -- [electron-release-server][electron-release-server]: *A fully featured, - self-hosted release server for electron applications, compatible with - auto-updater* -- [squirrel-updates-server][squirrel-updates-server]: *A simple node.js server - for Squirrel.Mac and Squirrel.Windows which uses GitHub releases* +`autoUpdater` is an [EventEmitter][event-emitter]. -## Platform notices +## Platform Notices -Though `autoUpdater` provides a uniform API for different platforms, there are -still some subtle differences on each platform. +Currently, only macOS and Windows are supported. There is no built-in support +for auto-updater on Linux, so it is recommended to use the +distribution's package manager to update your app. + +In addition, there are some subtle differences on each platform: ### macOS 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]. +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-builder][electron-builder-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: + +* **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. + +You don't need to configure which updater to use; Electron automatically detects the packaging +format and uses the appropriate one. + +#### Squirrel.Windows -The installer generated with Squirrel will create a shortcut icon with an +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. -The server-side setup is also different from macOS. You can read the documents of -[Squirrel.Windows][squirrel-windows] to get more details. +#### MSIX Packages -### Linux +When your app is packaged as an MSIX, the `autoUpdater` module provides additional +functionality: -There is no built-in support for auto-updater on Linux, so it is recommended to -use the distribution's package manager to update your app. +* 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 @@ -64,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' @@ -80,47 +103,89 @@ 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. + +### 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`. ## Methods The `autoUpdater` object has the following methods: -### `autoUpdater.setFeedURL(url[, requestHeaders])` - -* `url` String -* `requestHeaders` Object _macOS_ - HTTP request headers. +### `autoUpdater.setFeedURL(options)` + + + +* `options` Object + * `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 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 should only be called after `update-downloaded` has been emitted. +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. + [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-builder-lib]: https://github.com/electron-userland/electron-builder -[app-user-model-id]: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378459(v=vs.85).aspx -[electron-release-server]: https://github.com/ArekSredzki/electron-release-server -[squirrel-updates-server]: https://github.com/Aluxian/squirrel-updates-server -[nuts]: https://github.com/GitbookIO/nuts +[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..138266d17f518 --- /dev/null +++ b/docs/api/base-window.md @@ -0,0 +1,1539 @@ +# 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])` _Windows_ _macOS_ + +* `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 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 new file mode 100644 index 0000000000000..87f6ead865960 --- /dev/null +++ b/docs/api/browser-view.md @@ -0,0 +1,184 @@ +# BrowserView + + + +> [!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 + +```js +// In the main process. +const { app, BrowserView, BrowserWindow } = require('electron') + +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') +}) +``` + +### `new BrowserView([options])` _Experimental_ _Deprecated_ + + + +* `options` Object (optional) + * `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_ _Deprecated_ + + + +A [`WebContents`](web-contents.md) object owned by this view. + +### Instance Methods + +Objects created with `new BrowserView` have the following instance methods: + +#### `view.setAutoResize(options)` _Experimental_ _Deprecated_ + + + +* `options` Object + * `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 + together with the window. `false` by default. + * `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 + and shrink proportionally with the window. `false` by default. + +#### `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_ _Deprecated_ + + + +Returns [`Rectangle`](structures/rectangle.md) + +The `bounds` of this BrowserView instance as `Object`. + +#### `view.setBackgroundColor(color)` _Experimental_ _Deprecated_ + + + +* `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.md b/docs/api/browser-window.md index 22ad3a8c4fd29..0db37256f2156 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -2,295 +2,173 @@ > Create and control browser windows. -```javascript -// In the main process. -const {BrowserWindow} = require('electron') +Process: [Main](../glossary.md#main-process) -// Or use `remote` from the renderer process. -// const {BrowserWindow} = require('electron').remote +This module cannot be used until the `ready` event of the `app` +module is emitted. -let win = new BrowserWindow({width: 800, height: 600}) -win.on('closed', () => { - win = null -}) +```js +// In the main process. +const { BrowserWindow } = require('electron') +const win = new BrowserWindow({ width: 800, height: 600 }) + +// Load a remote URL win.loadURL('https://github.com') + +// Or load a local HTML file +win.loadFile('index.html') ``` -## Frameless window +## Window customization + +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. -To create a window without chrome, or a transparent window in arbitrary shape, -you can use the [Frameless Window](frameless-window.md) API. +## Showing the window gracefully -## Showing 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 a visual flash, there are two solutions for different situations. -When loading a page in window directly, users will see the progress of loading -page, which is not good experience for native app. To make the window display -without visual flash, there are two solutions for different situations. +### Using the `ready-to-show` event -### Using `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: -While loading the page, the `ready-to-show` event will be emitted when renderer -process has done drawing for the first time, showing window after this event -will have no visual flash: +```js +const { BrowserWindow } = require('electron') -```javascript -const {BrowserWindow} = require('electron') -let win = new BrowserWindow({show: false}) +const win = new BrowserWindow({ show: false }) win.once('ready-to-show', () => { win.show() }) ``` -This is event is usually emitted after the `did-finish-load` event, but for +This event is usually emitted after the `did-finish-load` event, but for pages with many remote resources, it may be emitted before the `did-finish-load` event. -### Setting `backgroundColor` +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 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 -const {BrowserWindow} = require('electron') +```js +const { BrowserWindow } = require('electron') -let win = new BrowserWindow({backgroundColor: '#2e2c29'}) +const win = new BrowserWindow({ backgroundColor: '#2e2c29' }) 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 -const {BrowserWindow} = require('electron') +```js +const { BrowserWindow } = require('electron') -let top = new BrowserWindow() -let child = new BrowserWindow({parent: top}) +const top = new BrowserWindow() +const child = new BrowserWindow({ parent: top }) child.show() top.show() ``` The `child` window will always show on top of the `top` window. -### Modal windows +## 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 -const {BrowserWindow} = require('electron') +```js +const { BrowserWindow } = require('electron') -let child = new BrowserWindow({parent: top, modal: true, show: false}) +const top = new BrowserWindow() +const child = new BrowserWindow({ parent: top, modal: true, show: false }) child.loadURL('https://github.com') child.once('ready-to-show', () => { child.show() }) ``` -### Platform notices +## Page visibility + +The [Page Visibility API][page-visibility-api] works as follows: +* On all platforms, the visibility state tracks whether the window is + hidden/minimized or not. +* Additionally, on macOS, the visibility state also tracks the window + occlusion state. If the window is occluded (i.e. fully covered) by another + window, the visibility state will be `hidden`. On other platforms, the + visibility state will be `hidden` only when the window is minimized or + explicitly hidden with `win.hide()`. +* If a `BrowserWindow` is created with `show: false`, the initial visibility + state will be `visible` despite the window actually being hidden. +* If `backgroundThrottling` is disabled, the visibility state will remain + `visible` even if the window is minimized, occluded, or hidden. + +It is recommended that you pause expensive operations when the visibility +state is `hidden` in order to minimize power consumption. + +## 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 Windows it is not supported to change parent window dynamically. * 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 extends `BaseWindow` + +> Create and control browser windows. -## Class: BrowserWindow +Process: [Main](../glossary.md#main-process) -`BrowserWindow` is an -[EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter). +`BrowserWindow` is an [EventEmitter][event-emitter]. 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 - * `width` Integer - Window's width in pixels. Default is `800`. - * `height` Integer - Window's height in pixels. Default is `600`. - * `x` Integer (**required** if y is used) - Window's left offset from screen. - Default is to center the window. - * `y` Integer (**required** if x is used) - Window's top offset from screen. - Default is to center the window. - * `useContentSize` Boolean - 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 - Show window in the center of the screen. - * `minWidth` Integer - Window's minimum width. Default is `0`. - * `minHeight` Integer - Window's minimum height. Default is `0`. - * `maxWidth` Integer - Window's maximum width. Default is no limit. - * `maxHeight` Integer - Window's maximum height. Default is no limit. - * `resizable` Boolean - Whether window is resizable. Default is `true`. - * `movable` Boolean - Whether window is movable. This is not implemented - on Linux. Default is `true`. - * `minimizable` Boolean - Whether window is minimizable. This is not - implemented on Linux. Default is `true`. - * `maximizable` Boolean - Whether window is maximizable. This is not - implemented on Linux. Default is `true`. - * `closable` Boolean - Whether window is closable. This is not implemented - on Linux. Default is `true`. - * `focusable` Boolean - 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 - Whether the window should always stay on top of - other windows. Default is `false`. - * `fullscreen` Boolean - 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 - 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`. - * `skipTaskbar` Boolean - Whether to show the window in taskbar. Default is - `false`. - * `kiosk` Boolean - The kiosk mode. Default is `false`. - * `title` String - Default window title. Default is `"Electron"`. - * `icon` [NativeImage](native-image.md) - 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 - Whether window should be shown when created. Default is - `true`. - * `frame` Boolean - Specify `false` to create a - [Frameless Window](frameless-window.md). Default is `true`. - * `parent` BrowserWindow - Specify parent window. Default is `null`. - * `modal` Boolean - Whether this is a modal window. This only works when the - window is a child window. Default is `false`. - * `acceptFirstMouse` Boolean - Whether the web view accepts a single - mouse-down event that simultaneously activates the window. Default is - `false`. - * `disableAutoHideCursor` Boolean - Whether to hide cursor when typing. - Default is `false`. - * `autoHideMenuBar` Boolean - Auto hide the menu bar unless the `Alt` - key is pressed. Default is `false`. - * `enableLargerThanScreen` Boolean - Enable the window to be resized larger - than screen. Default is `false`. - * `backgroundColor` String - Window's background color as Hexadecimal value, - like `#66CD00` or `#FFF` or `#80FFFFFF` (alpha is supported). Default is - `#FFF` (white). - * `hasShadow` Boolean - Whether window should have a shadow. This is only - implemented on macOS. Default is `true`. - * `darkTheme` Boolean - Forces using dark theme for the window, only works on - some GTK+3 desktop environments. Default is `false`. - * `transparent` Boolean - Makes the window [transparent](frameless-window.md). - Default is `false`. - * `type` String - The type of window, default is normal window. See more about - this below. - * `titleBarStyle` String - The style of window title bar. See more about this - below. - * `thickFrame` Boolean - 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`. - * `webPreferences` Object - Settings of web page's features. See more about - this below. - -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`. - -The `titleBarStyle` option is only supported on macOS 10.10 Yosemite and newer. -Possible values are: - -* `default` or not specified, 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. -* `hidden-inset` results in a hidden title bar with an alternative look - where the traffic light buttons are slightly more inset from the window edge. - -The `webPreferences` option is an object that can have the following properties: - -* `nodeIntegration` Boolean - Whether node integration is enabled. Default - is `true`. -* `preload` String - 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). -* `session` [Session](session.md#class-session) - 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 - 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 - The default zoom factor of the page, `3.0` represents - `300%`. Default is `1.0`. -* `javascript` Boolean - Enables JavaScript support. Default is `true`. -* `webSecurity` Boolean - When `false`, it will disable the - same-origin policy (usually using testing websites by people), and set - `allowDisplayingInsecureContent` and `allowRunningInsecureContent` to - `true` if these two options are not set by user. Default is `true`. -* `allowDisplayingInsecureContent` Boolean - Allow an https page to display - content like images from http URLs. Default is `false`. -* `allowRunningInsecureContent` Boolean - Allow an https page to run - JavaScript, CSS or plugins from http URLs. Default is `false`. -* `images` Boolean - Enables image support. Default is `true`. -* `textAreasAreResizable` Boolean - Make TextArea elements resizable. Default - is `true`. -* `webgl` Boolean - Enables WebGL support. Default is `true`. -* `webaudio` Boolean - Enables WebAudio support. Default is `true`. -* `plugins` Boolean - Whether plugins should be enabled. Default is `false`. -* `experimentalFeatures` Boolean - Enables Chromium's experimental features. - Default is `false`. -* `experimentalCanvasFeatures` Boolean - Enables Chromium's experimental - canvas features. Default is `false`. -* `scrollBounce` Boolean - Enables scroll bounce (rubber banding) effect on - macOS. Default is `false`. -* `blinkFeatures` String - 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.in][blink-feature-string] - file. -* `disableBlinkFeatures` String - 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.in][blink-feature-string] file. -* `defaultFontFamily` Object - Sets the default font for the font-family. - * `standard` String - Defaults to `Times New Roman`. - * `serif` String - Defaults to `Times New Roman`. - * `sansSerif` String - Defaults to `Arial`. - * `monospace` String - Defaults to `Courier New`. -* `defaultFontSize` Integer - Defaults to `16`. -* `defaultMonospaceFontSize` Integer - Defaults to `13`. -* `minimumFontSize` Integer - Defaults to `0`. -* `defaultEncoding` String - Defaults to `ISO-8859-1`. -* `backgroundThrottling` Boolean - Whether to throttle animations and timers - when the page becomes background. Defaults to `true`. -* `offscreen` Boolean - Whether to enable offscreen rendering for the browser - window. Defaults to `false`. +* `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' @@ -298,9 +176,12 @@ labeled as such. Returns: * `event` Event +* `title` string +* `explicitSet` boolean Emitted when the document changed its title, calling `event.preventDefault()` will prevent the native window's title from changing. +`explicitSet` is false when title is synthesized from file URL. #### Event: 'close' @@ -317,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') @@ -329,11 +210,36 @@ window.onbeforeunload = (e) => { } ``` +> [!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: 'unresponsive' Emitted when the web page becomes unresponsive. @@ -360,9 +266,12 @@ Emitted when the window is hidden. #### Event: 'ready-to-show' -Emitted when the web page has been rendered and window can be displayed without +Emitted when the web page has been rendered (while not being shown) and window can be displayed without a visual flash. +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` + #### Event: 'maximize' Emitted when window is maximized. @@ -379,20 +288,58 @@ Emitted when the window is minimized. 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 when the window is being resized. +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. -__Note__: On macOS this event is just an alias of `moved`. - -#### Event: 'moved' _macOS_ +#### 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. @@ -409,14 +356,23 @@ Emitted when the window enters a full-screen state triggered by HTML API. Emitted when the window leaves a full-screen state triggered by HTML API. -#### Event: 'app-command' _Windows_ +#### Event: 'always-on-top-changed' Returns: * `event` Event -* `command` String +* `isAlwaysOnTop` boolean + +Emitted when the window is set or unset to show always on top of other windows. + +#### Event: 'app-command' _Windows_ _Linux_ -Emitted when an [App Command](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275(v=vs.85).aspx) +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. @@ -424,9 +380,10 @@ 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 -const {BrowserWindow} = require('electron') -let win = new BrowserWindow() +```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 if (cmd === 'browser-backward' && win.webContents.canGoBack()) { @@ -435,118 +392,261 @@ win.on('app-command', (e, cmd) => { }) ``` -#### Event: 'scroll-touch-begin' _macOS_ - -Emitted when scroll wheel event phase has begun. +The following app commands are explicitly supported on Linux: -#### Event: 'scroll-touch-end' _macOS_ - -Emitted when scroll wheel event phase has ended. +* `browser-backward` +* `browser-forward` #### Event: 'swipe' _macOS_ Returns: * `event` Event -* `direction` String +* `direction` string Emitted on 3-finger swipe. Possible directions are `up`, `right`, `down`, `left`. -### Static Methods +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'. -The `BrowserWindow` class has the following static methods: +#### Event: 'rotate-gesture' _macOS_ -#### `BrowserWindow.getAllWindows()` +Returns: -Returns an array of all opened browser windows. +* `event` Event +* `rotation` Float -#### `BrowserWindow.getFocusedWindow()` +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. -Returns the window that is focused in this application, otherwise returns `null`. +#### Event: 'sheet-begin' _macOS_ -#### `BrowserWindow.fromWebContents(webContents)` +Emitted when the window opens a sheet. -* `webContents` [WebContents](web-contents.md) +#### Event: 'sheet-end' _macOS_ -Find a window according to the `webContents` it owns. +Emitted when the window has closed a sheet. -#### `BrowserWindow.fromId(id)` +#### Event: 'new-window-for-tab' _macOS_ -* `id` Integer +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`. -Find a window according to its ID. +You must create a window in this handler in order for macOS tabbing to work as expected. -#### `BrowserWindow.addDevToolsExtension(path)` +#### Event: 'system-context-menu' _Windows_ _Linux_ -* `path` String +Returns: -Adds DevTools extension located at `path`, and returns extension's name. +* `event` Event +* `point` [Point](structures/point.md) - The screen coordinates where the context menu was triggered. -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. +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. -The method will also not return if the extension's manifest is missing or incomplete. +Calling `event.preventDefault()` will prevent the menu from being displayed. -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. +To convert `point` to DIP, use [`screen.screenToDipPoint(point)`](./screen.md#screenscreentodippointpoint-windows-linux). -#### `BrowserWindow.removeDevToolsExtension(name)` +### Static Methods -* `name` String +The `BrowserWindow` class has the following static methods: -Remove a DevTools extension by name. +#### `BrowserWindow.getAllWindows()` -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. +Returns `BrowserWindow[]` - An array of all opened browser windows. -#### `BrowserWindow.getDevToolsExtensions()` +#### `BrowserWindow.getFocusedWindow()` -Returns an Object where the keys are the extension names and each value is -an Object containing `name` and `version` properties. +Returns `BrowserWindow | null` - The window that is focused in this application, otherwise returns `null`. -To check if a DevTools extension is installed you can run the following: +#### `BrowserWindow.fromWebContents(webContents)` -```javascript -const {BrowserWindow} = require('electron') +* `webContents` [WebContents](web-contents.md) -let installed = BrowserWindow.getDevToolsExtensions().hasOwnProperty('devtron') -console.log(installed) -``` +Returns `BrowserWindow | null` - The window that owns the given `webContents` +or `null` if the contents are not owned by a window. -**Note:** This API cannot be called before the `ready` event of the `app` module -is emitted. +#### `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)` + +* `id` Integer + +Returns `BrowserWindow | null` - The window with the given `id`. ### Instance Properties Objects created with `new BrowserWindow` have the following properties: -```javascript -const {BrowserWindow} = require('electron') +```js +const { BrowserWindow } = require('electron') // In this example `win` is our instance -let win = new BrowserWindow({width: 800, height: 600}) +const win = new BrowserWindow({ width: 800, height: 600 }) win.loadURL('https://github.com') ``` -#### `win.webContents` +#### `win.webContents` _Readonly_ -The `WebContents` object this window owns. All web page related events and +A `WebContents` object this window owns. All web page related events and operations will be done via it. See the [`webContents` documentation](web-contents.md) for its methods and events. -#### `win.id` +#### `win.id` _Readonly_ + +A `Integer` property representing the unique ID of the window. Each ID is unique among all `BrowserWindow` instances of the entire Electron application. + +#### `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. -The unique ID of the window. +#### `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=[11] +const win = new BrowserWindow({ 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 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()` @@ -564,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 a boolean, whether the window is focused. +Returns `boolean` - Whether the window is focused. #### `win.isDestroyed()` -Returns a boolean, whether the window is destroyed. +Returns `boolean` - Whether the window is destroyed. #### `win.show()` @@ -584,21 +689,24 @@ 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 a 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 a boolean, whether current window is a modal window. +Returns `boolean` - Whether current window is a modal window. #### `win.maximize()` -Maximizes the window. +Maximizes the window. This will also show (but not focus) the window if it +isn't being displayed already. #### `win.unmaximize()` @@ -606,7 +714,7 @@ Unmaximizes the window. #### `win.isMaximized()` -Returns a boolean, whether the window is maximized. +Returns `boolean` - Whether the window is maximized. #### `win.minimize()` @@ -619,26 +727,46 @@ Restores the window from minimized state to its previous state. #### `win.isMinimized()` -Returns a 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 a 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 + +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()` -#### `win.setAspectRatio(aspectRatio[, extraSize])` _macOS_ +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` Object (optional) - The extra size not to be included while +* `extraSize` [Size](structures/size.md) (optional) _macOS_ - The extra size not to be included while maintaining the aspect ratio. - * `width` Integer - * `height` Integer 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 @@ -650,65 +778,164 @@ 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 -[ 40, 50 ]. The second argument doesn't care where the extra width and height -are within the content view--only that they exist. Just sum any extra width 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. -#### `win.setBounds(options[, animate])` +The aspect ratio is not respected when window is resized programmatically with +APIs like `win.setSize`. -* `options` Object - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer -* `animate` Boolean (optional) _macOS_ +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`](#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. + +On Wayland (Linux), has the same limitations as `setSize` and `setPosition`. + +```js +const { BrowserWindow } = require('electron') + +const win = new BrowserWindow() + +// 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()) +``` -Resizes and moves the window to `width`, `height`, `x`, `y`. +> [!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 an object that contains window's width, height, x and y values. +Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `Object`. -#### `win.setContentBounds(options[, animate])` +> [!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 }`. -* `options` Object - * `x` Integer - * `y` Integer - * `width` Integer - * `height` Integer -* `animate` Boolean (optional) _macOS_ +> [!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`](#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 -`width`, `height`, `x`, `y`. +the supplied bounds. + +On Wayland (Linux), has the same limitations as `setContentSize` and `setPosition`. #### `win.getContentBounds()` -Returns an object that contains the window's client area (e.g. the web page) -width, height, x and y values. +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` return 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_ +* `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. -Resizes the window to `width` and `height`. +On Wayland (Linux), may not work as some window managers restrict programmatic window resizing. #### `win.getSize()` -Returns an array that contains window's width and height. +Returns `Integer[]` - Contains the window's width and height. #### `win.setContentSize(width, height[, animate])` * `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 an array that contains window's client area's width and height. +Returns `Integer[]` - Contains the window's client area's width and height. #### `win.setMinimumSize(width, height)` @@ -719,7 +946,7 @@ Sets the minimum size of window to `width` and `height`. #### `win.getMinimumSize()` -Returns an array that contains window's minimum width and height. +Returns `Integer[]` - Contains the window's minimum width and height. #### `win.setMaximumSize(width, height)` @@ -730,79 +957,100 @@ Sets the maximum size of window to `width` and `height`. #### `win.getMaximumSize()` -Returns an array that contains window's maximum width and height. +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 user. +Sets whether the window can be manually resized by the user. #### `win.isResizable()` -Returns whether the window can be manually resized by 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 whether the window can be moved by user. On Linux always returns -`true`. +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. +Sets whether the window can be manually minimized by user. On Linux does nothing. #### `win.isMinimizable()` _macOS_ _Windows_ -Returns whether the window can be manually minimized by user. On Linux always -returns `true`. +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. +Sets whether the window can be manually maximized by user. On Linux does nothing. #### `win.isMaximizable()` _macOS_ _Windows_ -Returns whether the window can be manually maximized by user. On Linux always -returns `true`. +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. +Sets whether the maximize/zoom window button toggles fullscreen mode or maximizes the window. #### `win.isFullScreenable()` -Returns 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 whether the window can be manually closed by user. On Linux always -returns `true`. +Returns `boolean` - Whether the window can be manually closed by user. -#### `win.setAlwaysOnTop(flag)` +On Linux always returns `true`. -* `flag` Boolean +#### `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 @@ -810,36 +1058,58 @@ can not be focused on. #### `win.isAlwaysOnTop()` -Returns 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". + +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. + +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 an array that contains window's current position. +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 the title of the native window. +Returns `string` - The title of the native window. -**Note:** The title of 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_ @@ -850,39 +1120,69 @@ 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 -const {BrowserWindow} = require('electron') -let win = new BrowserWindow() +```js +const { BrowserWindow } = require('electron') -let toolbarRect = document.getElementById('toolbar').getBoundingClientRect() +const win = new BrowserWindow() + +const toolbarRect = document.getElementById('toolbar').getBoundingClientRect() win.setSheetOffset(toolbarRect.height) ``` #### `win.flashFrame(flag)` -* `flag` Boolean + + +* `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 the kiosk mode. +Enters or leaves kiosk mode. #### `win.isKiosk()` -Returns 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. + +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 the platform-specific handle of the window as `Buffer`. +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. @@ -891,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. @@ -899,7 +1201,7 @@ the message is received in the WndProc. * `message` Integer -Returns `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_ @@ -913,37 +1215,111 @@ 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 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_ -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, ]callback)` +#### `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`. -Same as `webContents.capturePage([rect, ]callback)`. +Returns `Promise` - Resolves with a [NativeImage](native-image.md) + +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])` -Same as `webContents.loadURL(url[, options])`. +* `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. + +Returns `Promise` - 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. 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). + +The `url` can be a remote address (e.g. `http://`) or a path to a local +HTML file using the `file://` protocol. + +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: + +```js +const { BrowserWindow } = require('electron') + +const win = new BrowserWindow() + +const url = require('node:url').format({ + protocol: 'file', + slashes: true, + pathname: require('node:path').join(__dirname, 'index.html') +}) + +win.loadURL(url) +``` + +You can load a URL using a `POST` request with URL-encoded data by doing +the following: + +```js +const { BrowserWindow } = require('electron') + +const win = new BrowserWindow() + +win.loadURL('http://localhost:8000/post', { + postData: [{ + type: 'rawData', + bytes: Buffer.from('hello=world') + }], + extraHeaders: 'Content-Type: application/x-www-form-urlencoded' +}) +``` + +#### `win.loadFile(filePath[, options])` + +* `filePath` string +* `options` Object (optional) + * `query` Record\ (optional) - Passed to `url.format()`. + * `search` string (optional) - Passed to `url.format()`. + * `hash` string (optional) - Passed to `url.format()`. + +Returns `Promise` - 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)). + +Same as `webContents.loadFile`, `filePath` should be a path to an HTML +file relative to the root of your application. See the `webContents` docs +for more information. #### `win.reload()` @@ -951,53 +1327,88 @@ Same as `webContents.reload`. #### `win.setMenu(menu)` _Linux_ _Windows_ -* `menu` Menu +* `menu` Menu | null + +Sets the `menu` as the window's menu bar. + +#### `win.removeMenu()` _Linux_ _Windows_ -Sets the `menu` as the window's menu bar, setting it to `null` will remove the -menu bar. +Remove the window's menu bar. -#### `win.setProgressBar(progress)` +#### `win.setProgressBar(progress[, options])` _Windows_ _macOS_ * `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]. +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.getName().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) - the icon to display on the bottom +* `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.setHasShadow(hasShadow)` _macOS_ +#### `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 + +Sets whether the window should have a shadow. + +#### `win.hasShadow()` + +Returns `boolean` - Whether the window has a shadow. + +#### `win.setOpacity(opacity)` _Windows_ _macOS_ -* `hasShadow` Boolean +* `opacity` number - between 0.0 (fully transparent) and 1.0 (fully opaque) -Sets whether the window should have a shadow. On Windows and Linux does -nothing. +Sets the opacity of the window. On Linux, does nothing. Out of bound number +values are clamped to the \[0, 1] range. -#### `win.hasShadow()` _macOS_ +#### `win.getOpacity()` -Returns whether the window has a shadow. On Windows and Linux always returns -`true`. +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` Array +* `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 +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 @@ -1011,11 +1422,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` Array (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 @@ -1030,16 +1441,77 @@ The `flags` is an array that can include following `String`s: #### `win.setThumbnailClip(region)` _Windows_ -* `region` - Object - * `x` Integer - x-position of region - * `y` Integer - y-position of region - * `width` Integer - width of region - * `height` Integer - height of region +* `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}`. +`{ 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.showDefinitionForSelection()` _macOS_ @@ -1047,52 +1519,80 @@ Same as `webContents.showDefinitionForSelection()`. #### `win.setIcon(icon)` _Windows_ _Linux_ -* `icon` [NativeImage](native-image.md) +* `icon` [NativeImage](native-image.md) | string Changes window icon. -#### `win.setAutoHideMenuBar(hide)` +#### `win.setWindowButtonVisibility(visible)` _macOS_ + +* `visible` boolean -* `hide` 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. +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.isMenuBarAutoHide()` +#### `win.setMenuBarVisibility(visible)` _Windows_ _Linux_ -Returns whether menu bar automatically hides itself. +* `visible` boolean -#### `win.setMenuBarVisibility(visible)` +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. -* `visible` Boolean +#### `win.isMenuBarVisible()` _Windows_ _Linux_ -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. +Returns `boolean` - Whether the menu bar is visible. -#### `win.isMenuBarVisible()` +#### `win.isSnapped()` _Windows_ -Returns 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)` +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. + * `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 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)` +#### `win.setIgnoreMouseEvents(ignore[, options])` -* `ignore` Boolean +* `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. @@ -1102,30 +1602,217 @@ 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_MONITOR. +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.setFocusable(focusable)` _Windows_ +#### `win.isContentProtected()` _macOS_ _Windows_ -* `focusable` Boolean +Returns `boolean` - whether or not content protection is currently enabled. + +#### `win.setFocusable(focusable)` _macOS_ _Windows_ + +* `focusable` boolean Changes whether the window can be focused. -[blink-feature-string]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +On macOS it does not remove the focus from the window. + +#### `win.isFocusable()` _macOS_ _Windows_ -#### `win.setParentWindow(parent)` _Linux_ _macOS_ +Returns `boolean` - Whether the window can be focused. -* `parent` BrowserWindow +#### `win.setParentWindow(parent)` + +* `parent` BrowserWindow | null Sets `parent` as current window's parent window, passing `null` will turn current window into a top-level window. #### `win.getParentWindow()` -Returns the parent window. +Returns `BrowserWindow | null` - The parent window or `null` if there is no parent. #### `win.getChildWindows()` -Returns all child windows. +Returns `BrowserWindow[]` - 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(browserWindow)` _macOS_ + +* `browserWindow` BrowserWindow + +Adds a window as a tab on this window, after the tab for the window instance. + +#### `win.setVibrancy(type[, options])` _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. +* `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. 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. + +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.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. + +> [!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. + +> [!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. + +> [!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) + +> [!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. + +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. + +[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 +[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/chrome-command-line-switches.md b/docs/api/chrome-command-line-switches.md deleted file mode 100644 index 7d840f1a3e235..0000000000000 --- a/docs/api/chrome-command-line-switches.md +++ /dev/null @@ -1,181 +0,0 @@ -# Supported Chrome Command Line Switches - -> Command line switches supported by Electron. - -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 -const {app} = require('electron') -app.commandLine.appendSwitch('remote-debugging-port', '8315') -app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1') - -app.on('ready', () => { - // Your code here -}) -``` - -## --ignore-connections-limit=`domains` - -Ignore the connections limit for `domains` list separated by `,`. - -## --disable-http-cache - -Disables the disk cache for HTTP requests. - -## --disable-http2 - -Disable HTTP/2 and SPDY/3.1 protocols. - -## --remote-debugging-port=`port` - -Enables remote debugging over HTTP on the specified `port`. - -## --js-flags=`flags` - -Specifies the flags passed to JS engine. It has to be passed when starting -Electron if you want to enable the `flags` in the main process. - -```bash -$ electron --js-flags="--harmony_proxies --harmony_collections" your-app -``` - -## --proxy-server=`address:port` - -Use a specified proxy server, which overrides the system setting. This switch -only affects requests with HTTP protocol, including HTTPS and WebSocket -requests. It is also noteworthy that not all proxy servers support HTTPS and -WebSocket requests. - -## --proxy-bypass-list=`hosts` - -Instructs Electron to bypass the proxy server for the given semi-colon-separated -list of hosts. This flag has an effect only if used in tandem with -`--proxy-server`. - -For example: - -```javascript -const {app} = require('electron') -app.commandLine.appendSwitch('proxy-bypass-list', ';*.google.com;*foo.com;1.2.3.4:5678') -``` - -Will use the proxy server for all hosts except for local addresses (`localhost`, -`127.0.0.1` etc.), `google.com` subdomains, hosts that contain the suffix -`foo.com` and anything at `1.2.3.4:5678`. - -## --proxy-pac-url=`url` - -Uses the PAC script at the specified `url`. - -## --no-proxy-server - -Don't use a proxy server and always make direct connections. Overrides any other -proxy server flags that are passed. - -## --host-rules=`rules` - -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 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). - -## --host-resolver-rules=`rules` - -Like `--host-rules` but these `rules` only apply to the host resolver. - -## --auth-server-whitelist=`url` - -A comma-separated list of servers for which integrated authentication is enabled. - -For example: - -``` ---auth-server-whitelist='*example.com, *foobar.com, *baz' -``` - -then any `url` ending with `example.com`, `foobar.com`, `baz` will be considered -for integrated authentication. Without `*` prefix the url has to match exactly. - -## --auth-negotiate-delegate-whitelist=`url` - -A comma-separated list of servers for which delegation of user credentials is required. -Without `*` prefix the url has to match exactly. - -## --ignore-certificate-errors - -Ignores certificate related errors. - -## --ppapi-flash-path=`path` - -Sets the `path` of the pepper flash plugin. - -## --ppapi-flash-version=`version` - -Sets the `version` of the pepper flash plugin. - -## --log-net-log=`path` - -Enables net log events to be saved and writes them to `path`. - -## --ssl-version-fallback-min=`version` - -Sets the minimum SSL/TLS version (`tls1`, `tls1.1` or `tls1.2`) that TLS -fallback will accept. - -## --cipher-suite-blacklist=`cipher_suites` - -Specifies comma-separated list of SSL cipher suites to disable. - -## --disable-renderer-backgrounding - -Prevents Chromium from lowering the priority of invisible pages' renderer -processes. - -This flag is global to all renderer processes, if you only want to disable -throttling in one window, you can take the hack of -[playing silent audio][play-silent-audio]. - -## --enable-logging - -Prints Chromium's logging into console. - -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. - -## --v=`log_level` - -Gives the default maximal active V-logging level; 0 is the default. Normally -positive values are used for V-logging levels. - -This switch only works when `--enable-logging` is also passed. - -## --vmodule=`pattern` - -Gives the per-module maximal V-logging levels to override the value given by -`--v`. E.g. `my_module=2,foo*=3` would change the logging level for all code in -source files `my_module.*` and `foo*.*`. - -Any pattern containing a forward or backward slash will be tested against the -whole pathname and not just the module. E.g. `*/foo/bar/*=2` would change the -logging level for all code in the source files under a `foo/bar` directory. - -This switch only works when `--enable-logging` is also passed. - -[app]: app.md -[append-switch]: app.md#appcommandlineappendswitchswitch-value -[ready]: app.md#event-ready -[play-silent-audio]: https://github.com/atom/atom/pull/9485/files diff --git a/docs/api/client-request.md b/docs/api/client-request.md new file mode 100644 index 0000000000000..0205346319d05 --- /dev/null +++ b/docs/api/client-request.md @@ -0,0 +1,288 @@ +## Class: ClientRequest + +> Make HTTP/HTTPS requests. + +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process)
+_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 +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. + * `url` string (optional) - The request URL. Must be provided in the absolute + form with the protocol scheme specified as http or https. + * `headers` Record\ (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) + 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. + * `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). 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 + 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 + scheme in the form 'scheme:'. Defaults to 'http:'. + * `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. + * `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 + 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. + * `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 +[URL](https://nodejs.org/api/url.html) module. + +For instance, we could have created the same request to 'github.com' as follows: + +```js +const request = net.request({ + method: 'GET', + protocol: 'https:', + hostname: 'github.com', + port: 443, + path: '/' +}) +``` + +### Instance Events + +#### Event: 'response' + +Returns: + +* `response` [IncomingMessage](incoming-message.md) - An object representing the HTTP response message. + +#### Event: 'login' + +Returns: + +* `authInfo` Object + * `isProxy` boolean + * `scheme` string + * `host` string + * `port` Integer + * `realm` string +* `callback` Function + * `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 + +```js @ts-type={request:Electron.ClientRequest} +request.on('login', (authInfo, callback) => { + callback('username', 'password') +}) +``` + +Providing empty credentials will cancel the request and report an authentication +error on the response object: + +```js @ts-type={request:Electron.ClientRequest} +request.on('response', (response) => { + console.log(`STATUS: ${response.statusCode}`) + response.on('error', (error) => { + console.log(`ERROR: ${JSON.stringify(error)}`) + }) +}) +request.on('login', (authInfo, callback) => { + callback() +}) +``` + +#### Event: 'finish' + +Emitted just after the last chunk of the `request`'s data has been written into +the `request` object. + +#### Event: 'abort' + +Emitted when the `request` is aborted. The `abort` event will not be fired if +the `request` is already closed. + +#### Event: 'error' + +Returns: + +* `error` Error - an error object providing some information about the failure. + +Emitted when the `net` module fails to issue a network request. Typically when +the `request` object emits an `error` event, a `close` event will subsequently +follow and no response object will be provided. + +#### Event: 'close' + +Emitted as the last event in the HTTP request-response transaction. The `close` +event indicates that no more events will be emitted on either the `request` or +`response` objects. + +#### Event: 'redirect' + +Returns: + +* `statusCode` Integer +* `method` string +* `redirectUrl` string +* `responseHeaders` Record\ + +Emitted when the server returns a redirect response (e.g. 301 Moved +Permanently). Calling [`request.followRedirect`](#requestfollowredirect) will +continue with the redirection. If this event is handled, +[`request.followRedirect`](#requestfollowredirect) must be called +**synchronously**, otherwise the request will be cancelled. + +### Instance Properties + +#### `request.chunkedEncoding` + +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 +will throw an error. + +Using chunked encoding is strongly recommended if you need to send a large +request body as data will be streamed in small chunks instead of being +internally buffered inside Electron process memory. + +### Instance Methods + +#### `request.setHeader(name, 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 +`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/+/main:services/network/public/cpp/header_util.cc;drc=1562cab3f1eda927938f8f4a5a91991fefde66d3;bpv=1;bpt=1;l=22). + +* `Content-Length` +* `Host` +* `Trailer` or `Te` +* `Upgrade` +* `Cookie2` +* `Keep-Alive` +* `Transfer-Encoding` + +Additionally, setting the `Connection` header to the value `upgrade` is also disallowed. + +#### `request.getHeader(name)` + +* `name` string - Specify an extra header name. + +Returns `string` - The value of a previously set extra header name. + +#### `request.removeHeader(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 +string, it is converted into a Buffer using the specified encoding. +* `encoding` string (optional) - Used to convert string chunks into Buffer +objects. Defaults to 'utf-8'. +* `callback` Function (optional) - Called after the write operation ends. + +`callback` is essentially a dummy function introduced in the purpose of keeping +similarity with the Node.js API. It is called asynchronously in the next tick +after `chunk` content have been delivered to the Chromium networking layer. +Contrary to the Node.js implementation, it is not guaranteed that `chunk` +content have been flushed on the wire before `callback` is called. + +Adds a chunk of data to the request body. The first write operation may cause +the request headers to be issued on the wire. After the first write operation, +it is not allowed to add or remove a custom header. + +#### `request.end([chunk][, encoding][, callback])` + +* `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. + +#### `request.abort()` + +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. + +#### `request.followRedirect()` + +Continues any pending redirection. Can only be called during a `'redirect'` +event. + +#### `request.getUploadProgress()` + +Returns `Object`: + +* `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 +`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 + +You can use this method in conjunction with `POST` requests to get the progress +of a file upload or other data transfer. + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/clipboard.md b/docs/api/clipboard.md index bc7e15ee09b0c..c64ddf355b158 100644 --- a/docs/api/clipboard.md +++ b/docs/api/clipboard.md @@ -1,20 +1,34 @@ # clipboard + + > Perform copy and paste operations on the system clipboard. -The following example shows how to write a string to the clipboard: +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) _Deprecated_ (non-sandboxed only) -```javascript -const {clipboard} = require('electron') -clipboard.writeText('Example String') -``` +> [!NOTE] +> Using the `clipboard` API from the renderer process is deprecated. -On X Window systems, there is also a selection clipboard. To manipulate it +> [!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 -const {clipboard} = require('electron') -clipboard.writeText('Example String', 'selection') +```js +const { clipboard } = require('electron') + +clipboard.writeText('Example string', 'selection') console.log(clipboard.readText('selection')) ``` @@ -22,117 +36,263 @@ 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) +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. -Returns the content in the clipboard as plain text. +Returns `string` - The content in the clipboard as plain text. + +```js +const { clipboard } = require('electron') + +clipboard.writeText('hello i am a bit of text!') + +const text = clipboard.readText() +console.log(text) +// hello i am a bit of text!' +``` ### `clipboard.writeText(text[, type])` -* `text` String -* `type` String (optional) +* `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. +```js +const { clipboard } = require('electron') + +const text = 'hello i am a bit of text!' +clipboard.writeText(text) +``` + ### `clipboard.readHTML([type])` -* `type` String (optional) +* `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 the content in the clipboard as markup. +```js +const { clipboard } = require('electron') + +clipboard.writeHTML('Hi') +const html = clipboard.readHTML() + +console.log(html) +// Hi +``` ### `clipboard.writeHTML(markup[, type])` -* `markup` String -* `type` String (optional) +* `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('Hi') +``` + ### `clipboard.readImage([type])` -* `type` String (optional) +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. -Returns the content in the clipboard as a [NativeImage](native-image.md). +Returns [`NativeImage`](native-image.md) - The image content in the clipboard. ### `clipboard.writeImage(image[, type])` * `image` [NativeImage](native-image.md) -* `type` String (optional) +* `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) +* `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. + +```js +const { clipboard } = require('electron') -Returns the content in the clipboard as RTF. +clipboard.writeRTF('{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\nThis is some {\\b bold} text.\\par\n}') + +const rtf = clipboard.readRTF() +console.log(rtf) +// {\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\nThis is some {\\b bold} text.\\par\n} +``` ### `clipboard.writeRTF(text[, type])` -* `text` String -* `type` String (optional) +* `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. +```js +const { clipboard } = require('electron') + +const rtf = '{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\nThis is some {\\b bold} text.\\par\n}' +clipboard.writeRTF(rtf) +``` + ### `clipboard.readBookmark()` _macOS_ _Windows_ +Returns `Object`: + +* `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) +* `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` (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. + +```js +const { clipboard } = require('electron') + +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. + +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 -Writes the `title` and `url` into the clipboard as a bookmark. +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) +* `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) +* `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`. + +```js +const { clipboard } = require('electron') + +const formats = clipboard.availableFormats() +console.log(formats) +// [ 'text/plain', 'text/html' ] +``` -Returns an array of supported formats for the clipboard `type`. +### `clipboard.has(format[, type])` _Experimental_ -### `clipboard.has(data[, type])` _Experimental_ +* `format` string +* `type` string (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux. -* `data` String -* `type` String (optional) +Returns `boolean` - Whether the clipboard supports the specified `format`. -Returns whether the clipboard supports the format of specified `data`. +```js +const { clipboard } = require('electron') -```javascript -const {clipboard} = require('electron') -console.log(clipboard.has('

selection

')) +const hasFormat = clipboard.has('public/utf8-plain-text') +console.log(hasFormat) +// 'true' or 'false' ``` -### `clipboard.read(data[, type])` _Experimental_ +### `clipboard.read(format)` _Experimental_ -* `data` String -* `type` String (optional) +* `format` string -Reads `data` 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 + +Returns `Buffer` - Reads `format` type from the clipboard. + +```js +const { clipboard } = require('electron') + +const buffer = Buffer.from('this is binary', 'utf8') +clipboard.writeBuffer('public/utf8-plain-text', buffer) + +const ret = clipboard.readBuffer('public/utf8-plain-text') + +console.log(buffer.equals(ret)) +// true +``` + +### `clipboard.writeBuffer(format, buffer[, type])` _Experimental_ + +* `format` string +* `buffer` Buffer +* `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`. + +```js +const { clipboard } = require('electron') + +const buffer = Buffer.from('writeBuffer', 'utf8') +clipboard.writeBuffer('public/utf8-plain-text', buffer) +``` ### `clipboard.write(data[, type])` * `data` Object - * `text` String - * `html` String - * `image` [NativeImage](native-image.md) - * `rtf` String - * `bookmark` String - The title of the url at `text`. -* `type` String (optional) - -```javascript -const {clipboard} = require('electron') -clipboard.write({text: 'test', html: 'test'}) -``` + * `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. + Writes `data` to the clipboard. + +```js +const { clipboard } = require('electron') + +clipboard.write({ + text: 'test', + html: 'Hi', + rtf: '{\\rtf1\\utf8 text}', + bookmark: 'a title' +}) + +console.log(clipboard.readText()) +// 'test' + +console.log(clipboard.readHTML()) +// Hi + +console.log(clipboard.readRTF()) +// '{\\rtf1\\utf8 text}' + +console.log(clipboard.readBookmark()) +// { title: 'a title', url: 'test' } +``` diff --git a/docs/api/command-line-switches.md b/docs/api/command-line-switches.md new file mode 100644 index 0000000000000..ef8ee0f05f1f9 --- /dev/null +++ b/docs/api/command-line-switches.md @@ -0,0 +1,404 @@ +# Supported Command Line Switches + +> Command line switches supported by Electron. + +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: + +```js +const { app } = require('electron') + +app.commandLine.appendSwitch('remote-debugging-port', '8315') +app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1') + +app.whenReady().then(() => { + // Your code here +}) +``` + +## Electron CLI Flags + +### --auth-server-whitelist=`url` + +A comma-separated list of servers for which integrated authentication is enabled. + +For example: + +```sh +--auth-server-whitelist='*example.com, *foobar.com, *baz' +``` + +then any `url` ending with `example.com`, `foobar.com`, `baz` will be considered +for integrated authentication. Without `*` prefix the URL has to match exactly. + +### --auth-negotiate-delegate-whitelist=`url` + +A comma-separated list of servers for which delegation of user credentials is required. +Without `*` prefix the URL has to match exactly. + +### --disable-ntlm-v2 + +Disables NTLM v2 for POSIX platforms, no effect elsewhere. + +### --disable-http-cache + +Disables the disk cache for HTTP requests. + +### --disable-http2 + +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 +processes. + +This flag is global to all renderer processes, if you only want to disable +throttling in one window, you can take the hack of +[playing silent audio][play-silent-audio]. + +### --disk-cache-size=`size` + +Forces the maximum disk space to be used by the disk cache, in bytes. + +### --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`. + +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. + +> [!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. + +See also `--log-file`, `--log-level`, `--v`, and `--vmodule`. + +### --force-fieldtrials=`trials` + +Field trials to be forcefully enabled or disabled. + +For example: `WebRTC-Audio-Red-For-Opus/Enabled/` + +### --host-rules=`rules` _Deprecated_ + +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 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` + +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 + +Ignores certificate related errors. + +### --ignore-connections-limit=`domains` + +Ignore the connections limit for `domains` list separated by `,`. + +### --js-flags=`flags` + +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 +``` + +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 +proxy server flags that are passed. + +### --no-sandbox + +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 +list of hosts. This flag has an effect only if used in tandem with +`--proxy-server`. + +For example: + +```js +const { app } = require('electron') + +app.commandLine.appendSwitch('proxy-bypass-list', ';*.google.com;*foo.com;1.2.3.4:5678') +``` + +Will use the proxy server for all hosts except for local addresses (`localhost`, +`127.0.0.1` etc.), `google.com` subdomains, hosts that contain the suffix +`foo.com` and anything at `1.2.3.4:5678`. + +### --proxy-pac-url=`url` + +Uses the PAC script at the specified `url`. + +### --proxy-server=`address:port` + +Use a specified proxy server, which overrides the system setting. This switch +only affects requests with HTTP protocol, including HTTPS and WebSocket +requests. It is also noteworthy that not all proxy servers support HTTPS and +WebSocket requests. The proxy URL does not support username and password +authentication [per Chromium issue](https://bugs.chromium.org/p/chromium/issues/detail?id=615947). + +### --remote-debugging-port=`port` + +Enables remote debugging over HTTP on the specified `port`. + +### --v=`log_level` + +Gives the default maximal active V-logging level; 0 is the default. Normally +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 +`--v`. E.g. `my_module=2,foo*=3` would change the logging level for all code in +source files `my_module.*` and `foo*.*`. + +Any pattern containing a forward or backward slash will be tested against the +whole pathname and not only the module. E.g. `*/foo/bar/*=2` would change the +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. + +### --force_low_power_gpu + +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. + +### `--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-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]` + +Activate inspector on `host:port`. Default is `127.0.0.1:9229`. + +V8 inspector integration allows tools such as Chrome DevTools and IDEs to debug and profile Electron instances. The tools attach to Electron instances via a TCP port and communicate using the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). + +See the [Debugging the Main Process][debugging-main-process] guide for more details. + +Aliased to `--debug[=[host:]port`. + +### `--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`. + +### `--experimental-network-inspection` + +Enable support for DevTools network inspector events, for visibility into requests made by the nodejs `http` and `https` modules. + +### `--experimental-inspector-network-resource` + +Enable support for resolving source maps over the network when using the Node.js inspector. + +When enabled, DevTools can retrieve remote source maps for main and utility +process scripts via the Node.js inspector. + +**Note:** When enabled, the Node.js inspector will make network requests to +URLs specified in source maps. Be mindful of this in environments where the +process has access to internal networks. + +### `--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 +[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 new file mode 100644 index 0000000000000..e424ba1f1c498 --- /dev/null +++ b/docs/api/command-line.md @@ -0,0 +1,111 @@ +## Class: CommandLine + +> Manipulate the command line arguments for your app that Chromium reads + +Process: [Main](../glossary.md#main-process)
+_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. + +```js +const { app } = require('electron') + +app.commandLine.hasSwitch('disable-gpu') +``` + +For more information on what kinds of flags and switches you can use, check +out the [Command Line Switches](./command-line-switches.md) +document. + +### Instance Methods + +#### `commandLine.appendSwitch(switch[, value])` + +* `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. + +```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. + +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. + +```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. + +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. + +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] +> 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 8cfc7670c6a69..1217f024bbcbe 100644 --- a/docs/api/content-tracing.md +++ b/docs/api/content-tracing.md @@ -1,28 +1,29 @@ # contentTracing -> Collect tracing data from Chromium's content module for finding performance -bottlenecks and slow operations. +> Collect tracing data from Chromium to find performance bottlenecks and slow operations. -This module does not include a web interface so you need to open -`chrome://tracing/` in a Chrome browser and load the generated file to view the -result. +Process: [Main](../glossary.md#main-process) -```javascript -const {contentTracing} = require('electron') +This module does not include a web interface. To view recorded traces, use +[trace viewer][], available at `chrome://tracing` in Chrome. -const options = { - categoryFilter: '*', - traceOptions: 'record-until-full,enable-sampling' -} +> [!NOTE] +> You should not use this module until the `ready` event of the app +> module is emitted. -contentTracing.startRecording(options, () => { - console.log('Tracing started') +```js +const { app, contentTracing } = require('electron') - setTimeout(() => { - contentTracing.stopRecording('', (path) => { - console.log('Tracing data recorded to ' + path) +app.whenReady().then(() => { + (async () => { + await contentTracing.startRecording({ + included_categories: ['*'] }) - }, 5000) + console.log('Tracing started') + await new Promise(resolve => setTimeout(resolve, 5000)) + const path = await contentTracing.stopRecording() + console.log('Tracing data recorded to ' + path) + })() }) ``` @@ -30,137 +31,158 @@ contentTracing.startRecording(options, () => { The `contentTracing` module has the following methods: -### `contentTracing.getCategories(callback)` +### `contentTracing.getCategories()` -* `callback` Function + -Get a set of category groups. The category groups can change as new code paths -are reached. +Returns `Promise` - resolves with an array of category groups once all child processes have acknowledged the `getCategories` request -Once all child processes have acknowledged the `getCategories` request the -`callback` is invoked with an array of category groups. +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/+/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)` + + -### `contentTracing.startRecording(options, callback)` +* `options` ([TraceConfig](structures/trace-config.md) | [TraceCategoriesAndOptions](structures/trace-categories-and-options.md)) -* `options` Object - * `categoryFilter` String - * `traceOptions` String -* `callback` Function +Returns `Promise` - resolved once all child processes have acknowledged the `startRecording` request. Start recording on all processes. Recording begins immediately locally and asynchronously on child processes -as soon as they receive the EnableRecording request. The `callback` will be -called once all child processes have acknowledged the `startRecording` request. - -`categoryFilter` is 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` controls what kind of tracing is enabled, it is a comma-delimited -list. Possible options are: +as soon as they receive the EnableRecording request. -* `record-until-full` -* `record-continuously` -* `trace-to-console` -* `enable-sampling` -* `enable-systrace` +If a recording is already running, the promise will be immediately resolved, as +only one trace operation can be in progress at a time. -The first 3 options are trace recoding modes and hence mutually exclusive. -If more than one trace recording modes appear in the `traceOptions` string, -the last one takes precedence. If none of the trace recording modes are -specified, recording mode is `record-until-full`. +### `contentTracing.stopRecording([resultFilePath])` -The trace option will first be reset to the default option (`record_mode` set to -`record-until-full`, `enable_sampling` and `enable_systrace` set to `false`) -before options parsed from `traceOptions` are applied on it. + -### `contentTracing.stopRecording(resultFilePath, callback)` +* `resultFilePath` string (optional) -* `resultFilePath` String -* `callback` Function +Returns `Promise` - 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. Child processes typically cache trace data and only rarely flush and send trace data back to the main process. This helps to minimize the runtime overhead of tracing since sending trace data over IPC can be an expensive operation. So, -to end tracing, we must asynchronously ask all child processes to flush any +to end tracing, Chromium asynchronously asks all child processes to flush any pending trace data. -Once all child processes have acknowledged the `stopRecording` request, -`callback` will be called with a file that contains the traced data. +Trace data will be written into `resultFilePath`. If `resultFilePath` is empty +or not provided, trace data will be written to a temporary file, and the path +will be returned in the promise. -Trace data will be written into `resultFilePath` if it is not empty or into a -temporary file. The actual file path will be passed to `callback` if it's not -`null`. +### `contentTracing.getTraceBufferUsage()` -### `contentTracing.startMonitoring(options, callback)` + -* `options` Object - * `categoryFilter` String - * `traceOptions` String -* `callback` Function +Returns `Promise` - Resolves with an object containing the `value` and `percentage` of trace buffer maximum usage -Start monitoring on all processes. +* `value` number +* `percentage` number -Monitoring begins immediately locally and asynchronously on child processes as -soon as they receive the `startMonitoring` request. +Get the maximum usage across processes of trace buffer as a percentage of the +full state. -Once all child processes have acknowledged the `startMonitoring` request the -`callback` will be called. +### `contentTracing.enableHeapProfiling([options])` _Experimental_ -### `contentTracing.stopMonitoring(callback)` + -* `callback` Function +* `options` ([EnableHeapProfilingOptions](structures/enable-heap-profiling-options.md)) (optional) -Stop monitoring on all processes. +Returns `Promise` - Resolves once heap profiling has been enabled. -Once all child processes have acknowledged the `stopMonitoring` request the -`callback` is called. +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. -### `contentTracing.captureMonitoringSnapshot(resultFilePath, callback)` +Only takes effect if the `disabled-by-default-memory-infra` category is included. -* `resultFilePath` String -* `callback` Function +Needs to be called before `contentTracing.startRecording()`. -Get the current monitoring traced data. +Usage: -Child processes typically cache trace data and only rarely flush and send -trace data back to the main process. This is because it may be an expensive -operation to send the trace data over IPC and we would like to avoid unneeded -runtime overhead from tracing. So, to end tracing, we must asynchronously ask -all child processes to flush any pending trace data. +```js +const { contentTracing } = require('electron') -Once all child processes have acknowledged the `captureMonitoringSnapshot` -request the `callback` will be called with a file that contains the traced data. +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)) -### `contentTracing.getTraceBufferUsage(callback)` - -* `callback` Function + const filePath = await contentTracing.stopRecording() +} +``` -Get the maximum usage across processes of trace buffer as a percentage of the -full state. When the TraceBufferUsage value is determined the `callback` is -called. +To view the recorded heap dumps: -### `contentTracing.setWatchEvent(categoryName, eventName, callback)` +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: -* `categoryName` String -* `eventName` String -* `callback` Function + ```bash + python3 third_party/catapult/tracing/bin/symbolize_trace --use-breakpad-symbols --breakpad-symbols-directory /path/to/breakpad_symbols /path/to/trace.json + ``` -`callback` will be called every time the given event occurs on any -process. +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) -### `contentTracing.cancelWatchEvent()` +Screenshot showing how to view a heapdump in Chromium's tracing view -Cancel the watch event. This may lead to a race condition with the watch event -callback if tracing is enabled. +[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 new file mode 100644 index 0000000000000..6eb7dd2a2bcc8 --- /dev/null +++ b/docs/api/context-bridge.md @@ -0,0 +1,203 @@ +# 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: + +```js +// Preload (Isolated World) +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld( + 'electron', + { + doThing: () => ipcRenderer.send('do-a-thing') + } +) +``` + +```js @ts-nocheck +// Renderer (Main World) + +window.electron.doThing() +``` + +## Glossary + +### Main World + +The "Main World" is the JavaScript context that your main renderer code runs in. By default, the +page you load in your renderer executes code in this world. + +### Isolated World + +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) docs. + +## Methods + +The `contextBridge` module has the following methods: + +### `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. + +### `contextBridge.executeInMainWorld(executionScript)` _Experimental_ + + + +* `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 + +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 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 is shown below: + +```js +const { contextBridge, ipcRenderer } = require('electron') + +contextBridge.exposeInMainWorld( + 'electron', + { + doThing: () => ipcRenderer.send('do-a-thing'), + myPromises: [Promise.resolve(), Promise.reject(new Error('whoops'))], + anAsyncFunction: async () => 123, + data: { + myFlags: ['a', 'b', 'c'], + bootTime: 1234 + }, + nestedAPI: { + evenDeeper: { + youCanDoThisAsMuchAsYouWant: { + fn: () => ({ + returnData: 123 + }) + } + } + } + } +) +``` + +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 +results in some key limitations that we've outlined below. + +#### Parameter / Error / Return Type support + +Because parameters, errors and return values are **copied** when they are sent over the bridge, there are only certain types that can be used. +At a high level, if the type you want to use can be serialized and deserialized into the same object it will work. A table of type support +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 | +| `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, 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 new file mode 100644 index 0000000000000..b85d6635d1369 --- /dev/null +++ b/docs/api/cookies.md @@ -0,0 +1,131 @@ +## Class: Cookies + +> Query and modify a session's cookies. + +Process: [Main](../glossary.md#main-process)
+_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: + +```js +const { session } = require('electron') + +// Query all cookies. +session.defaultSession.cookies.get({}) + .then((cookies) => { + console.log(cookies) + }).catch((error) => { + console.log(error) + }) + +// Query all cookies associated with a specific url. +session.defaultSession.cookies.get({ url: 'https://www.github.com' }) + .then((cookies) => { + console.log(cookies) + }).catch((error) => { + console.log(error) + }) + +// Set a cookie with the given cookie data; +// may overwrite equivalent cookies if they exist. +const cookie = { url: 'https://www.github.com', name: 'dummy_name', value: 'dummy' } +session.defaultSession.cookies.set(cookie) + .then(() => { + // success + }, (error) => { + console.error(error) + }) +``` + +### Instance Events + +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: + * `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. + +Emitted when a cookie is changed because it was added, edited, removed, or +expired. + +### Instance Methods + +The following methods are available on instances of `Cookies`: + +#### `cookies.get(filter)` + +* `filter` Object + * `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 + 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. + * `httpOnly` boolean (optional) - Filters cookies by httpOnly. + +Returns `Promise` - A promise which resolves an array of cookie objects. + +Sends a request to get all cookies matching `filter`, and resolves a promise with +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 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 `lax`. + +Returns `Promise` - 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. + +Returns `Promise` - A promise which resolves when the cookie has been removed. + +Removes the cookies matching `url` and `name`. + +#### `cookies.flushStore()` + +Returns `Promise` - 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 = + | + system-ui +``` diff --git a/docs/api/crash-reporter.md b/docs/api/crash-reporter.md index 5c84cb4cb1139..4954d37c4c615 100644 --- a/docs/api/crash-reporter.md +++ b/docs/api/crash-reporter.md @@ -2,77 +2,277 @@ > Submit crash reports to a remote server. -The following is an example of automatically submitting a crash report to a -remote server: - -```javascript -const {crashReporter} = require('electron') - -crashReporter.start({ - productName: 'YourName', - companyName: 'YourCompany', - submitURL: 'https://your-domain.com/url-to-submit', - autoSubmit: true -}) +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: + +```js +const { crashReporter } = require('electron') + +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'. You can override +this directory by calling `app.setPath('crashDumps', '/path/to/crashes')` +before starting the crash reporter. + +Electron uses [crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/README.md) +to monitor and report crashes. + ## Methods -The `crash-reporter` module has the following methods: +The `crashReporter` module has the following methods: ### `crashReporter.start(options)` + + * `options` Object - * `companyName` String - * `submitURL` String - URL that crash reports will be sent to as POST. - * `productName` String (optional) - Default is `Electron`. - * `autoSubmit` Boolean - Send the crash report without user interaction. - Default is `true`. - * `ignoreSystemCrashHandler` Boolean - Default is `false`. - * `extra` Object - An object you can define that will be sent along with the - report. Only string properties are sent correctly, Nested objects are not - supported. - -You are required to call this method before using other `crashReporter` -APIs. - -**Note:** On macOS, Electron uses a new `crashpad` client, which is different -from `breakpad` on Windows and Linux. To enable the crash collection feature, -you are required to call the `crashReporter.start` API to initialize `crashpad` -in the main process and in each renderer process from which you wish to collect -crash reports. + * `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 + 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 + 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 + number of crashes uploaded to 1/hour. Default is `false`. + * `compress` boolean (optional) - If true, crash reports will be compressed + and uploaded with `Content-Encoding: gzip`. Default is `true`. + * `extra` Record\ (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 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\ (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 + the process-specific extra parameters, then the global one will take + precedence. By default, `productName` and the app version are included, as + well as the Electron version. + +This method must be called before using any other `crashReporter` APIs. Once +initialized this way, the crashpad handler collects crashes from all +subsequently created processes. The crash reporter cannot be disabled once +started. + +This method should be called as early as possible in app startup, preferably +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] +> 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] +> This method is only available in the main process. ### `crashReporter.getLastCrashReport()` -Returns the date and ID of the last crash report. If no crash reports have been -sent or the crash reporter has not been started, `null` is returned. + + +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] +> This method is only available in the main process. ### `crashReporter.getUploadedReports()` + + +Returns [`CrashReport[]`](structures/crash-report.md): + Returns all uploaded crash reports. Each report contains the date and uploaded ID. -## crash-reporter Payload +> [!NOTE] +> This method is only available in the main process. + +### `crashReporter.getUploadToServer()` + + + +Returns `boolean` - Whether reports should be submitted to the server. Set through +the `start` method or `setUploadToServer`. + +> [!NOTE] +> This method is only available in the main process. + +### `crashReporter.setUploadToServer(uploadToServer)` + + + +* `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] +> 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. + +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 +`start` was called. + +Parameters added in this fashion (or via the `extra` parameter to +`crashReporter.start`) are specific to the calling process. Adding extra +parameters in the main process will not cause those parameters to be sent along +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. + +### `crashReporter.removeExtraParameter(key)` + +* `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` - 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`. - `options` object +* All level one properties of the `extra` object in the `crashReporter` + `options` object. diff --git a/docs/api/debugger.md b/docs/api/debugger.md new file mode 100644 index 0000000000000..c29673f3d4840 --- /dev/null +++ b/docs/api/debugger.md @@ -0,0 +1,95 @@ +## Class: Debugger + +> An alternate transport for Chrome's remote debugging protocol. + +Process: [Main](../glossary.md#main-process)
+_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. + +```js +const { BrowserWindow } = require('electron') + +const win = new BrowserWindow() + +try { + win.webContents.debugger.attach('1.1') +} catch (err) { + console.log('Debugger attach failed : ', err) +} + +win.webContents.debugger.on('detach', (event, reason) => { + console.log('Debugger detached due to : ', reason) +}) + +win.webContents.debugger.on('message', (event, method, params) => { + if (method === 'Network.requestWillBeSent') { + if (params.request.url === 'https://www.github.com') { + win.webContents.debugger.detach() + } + } +}) + +win.webContents.debugger.sendCommand('Network.enable') +``` + +### Instance Events + +#### Event: 'detach' + +Returns: + +* `event` Event +* `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`. + +#### Event: 'message' + +Returns: + +* `event` Event +* `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, + will match the value sent from `debugger.sendCommand`. + +Emitted whenever the debugging target issues an instrumentation event. + +[rdp]: https://chromedevtools.github.io/devtools-protocol/ + +### Instance Methods + +#### `debugger.attach([protocolVersion])` + +* `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`. + +#### `debugger.detach()` + +Detaches the debugger from the `webContents`. + +#### `debugger.sendCommand(method[, commandParams, sessionId])` + +* `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 + debugging session id. The initial value can be obtained by sending + [Target.attachToTarget][attachToTarget] message. + +[attachToTarget]: https://chromedevtools.github.io/devtools-protocol/tot/Target/#method-attachToTarget + +Returns `Promise` - A promise that resolves with the response defined by +the 'returns' attribute of the command description in the remote debugging protocol +or is rejected indicating the failure of the command. + +Send given command to the debugging target. diff --git a/docs/api/desktop-capturer.md b/docs/api/desktop-capturer.md index af35b11fdeeb7..fb1bfb1eb4d27 100644 --- a/docs/api/desktop-capturer.md +++ b/docs/api/desktop-capturer.md @@ -1,85 +1,160 @@ # desktopCapturer > Access information about media sources that can be used to capture audio and -> video from the desktop using the [`navigator.webkitGetUserMedia`] API. +> video from the desktop using the [`navigator.mediaDevices.getUserMedia`][] API. + +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']}, (error, sources) => { - if (error) throw error - for (let i = 0; i < sources.length; ++i) { - if (sources[i].name === 'Electron') { - navigator.webkitGetUserMedia({ - audio: false, - video: { - mandatory: { - chromeMediaSource: 'desktop', - chromeMediaSourceId: sources[i].id, - minWidth: 1280, - maxWidth: 1280, - minHeight: 720, - maxHeight: 720 - } - } - }, handleStream, handleError) - 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') +}) +``` + +```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 handleStream (stream) { - document.querySelector('video').src = URL.createObjectURL(stream) -} +stopButton.addEventListener('click', () => { + video.pause() +}) +``` -function handleError (e) { - console.log(e) -} +```html + + + + + + + + + + ``` -To capture video from a source provided by `desktopCapturer` the constraints -passed to [`navigator.webkitGetUserMedia`] must include -`chromeMediaSource: 'desktop'`, and `audio: false`. +See [`navigator.mediaDevices.getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia) for more information. -To capture both audio and video from the entire desktop the constraints passed -to [`navigator.webkitGetUserMedia`] must include `chromeMediaSource: 'screen'`, -and `audio: true`, but should not include a `chromeMediaSourceId` constraint. +> [!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 The `desktopCapturer` module has the following methods: -### `desktopCapturer.getSources(options, callback)` +### `desktopCapturer.getSources(options)` + + * `options` Object - * `types` Array - An array of String that lists the types of desktop sources - to be captured, available types are `screen` and `window`. - * `thumbnailSize` Object (optional) - The suggested size that the media source - thumbnail should be scaled to, defaults to `{width: 150, height: 150}`. -* `callback` Function - -Starts gathering information about all available desktop media sources, -and calls `callback(error, sources)` when finished. - -`sources` is an array of `Source` objects, each `Source` represents a -screen or an individual window that can be captured, and has the following -properties: - -* `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 - `Screen `, while the name of a window source will match the window - title. -* `thumbnail` [NativeImage](native-image.md) - A thumbnail image. **Note:** - There is no guarantee that the size of the thumbnail is the same as the - `thumnbailSize` specified in the `options` passed to - `desktopCapturer.getSources`. The actual size depends on the scale of the - screen or window. - -[`navigator.webkitGetUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/Navigator/getUserMedia + * `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 + value is false. When false the appIcon property of the sources return null. Same if a source has + the type screen. + +Returns `Promise` - 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 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 + +### 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 +[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 f6bf0fdc19fd0..a5ade687b26d4 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -2,52 +2,164 @@ > Display native system dialogs for opening and saving files, alerting, etc. -An example of showing a dialog to select multiple files and directories: +Process: [Main](../glossary.md#main-process) -```javascript -const {dialog} = require('electron') -console.log(dialog.showOpenDialog({properties: ['openFile', 'openDirectory', 'multiSelections']})) -``` +An example of showing a dialog to select multiple files: -The Dialog is opened from Electron's main thread. If you want to use the dialog -object from a renderer process, remember to access it using the remote: +```js +const { dialog } = require('electron') -```javascript -const {dialog} = require('electron').remote -console.log(dialog) +console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] })) ``` ## Methods The `dialog` module has the following methods: -### `dialog.showOpenDialog([browserWindow, ]options[, callback])` +### `dialog.showOpenDialogSync([window, ]options)` + + -* `browserWindow` BrowserWindow (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object - * `title` String - * `defaultPath` String - * `buttonLabel` String - 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` Array - * `properties` Array - Contains which features the dialog should use, can - contain `openFile`, `openDirectory`, `multiSelections`, `createDirectory` - and `showHiddenFiles`. -* `callback` Function (optional) + * `filters` [FileFilter[]](structures/file-filter.md) (optional) + * `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` _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 + the path but allows non-existent paths to be returned that should be + created by the application. + * `noResolveAliases` _macOS_ - Disable the automatic alias (symlink) path + resolution. Selected aliases will now return the alias path instead of + their target path. + * `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 + 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. -On success this method returns an array of file paths chosen by the user, -otherwise it returns `undefined`. +Returns `string[] | undefined`, the file paths chosen by the user; if the dialog is cancelled it returns `undefined`. + +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: + + +```js +{ + filters: [ + { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, + { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] }, + { name: 'Custom File Type', extensions: ['as'] }, + { name: 'All Files', extensions: ['*'] } + ] +} +``` + +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. + +```js @ts-type={mainWindow:Electron.BaseWindow} +dialog.showOpenDialogSync(mainWindow, { + properties: ['openFile', 'openDirectory'] +}) +``` + +> [!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.showOpenDialog([window, ]options)` + + + +* `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. 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 + 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` _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 + the path but allows non-existent paths to be returned that should be + created by the application. + * `noResolveAliases` _macOS_ - Disable the automatic alias (symlink) path + resolution. Selected aliases will now return the alias path instead of + their target path. + * `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 + 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. + +Returns `Promise` - 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).) + +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: + + + +```js { filters: [ - {name: 'Images', extensions: ['jpg', 'png', 'gif']}, - {name: 'Movies', extensions: ['mkv', 'avi', 'mp4']}, - {name: 'Custom File Type', extensions: ['as']}, - {name: 'All Files', extensions: ['*']} + { name: 'Images', extensions: ['jpg', 'png', 'gif'] }, + { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] }, + { name: 'Custom File Type', extensions: ['as'] }, + { name: 'All Files', extensions: ['*'] } ] } ``` @@ -56,81 +168,297 @@ 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). -If a `callback` is passed, the API call will be asynchronous and the result -will be passed via `callback(filenames)` +> [!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 @ts-type={mainWindow:Electron.BaseWindow} +dialog.showOpenDialog(mainWindow, { + properties: ['openFile', 'openDirectory'] +}).then(result => { + console.log(result.canceled) + console.log(result.filePaths) +}).catch(err => { + console.log(err) +}) +``` + +> [!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)` + + + +* `window` [BaseWindow](base-window.md) (optional) +* `options` Object + * `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 + displayed in front of the filename text field. + * `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. + +Returns `string`, the path of the file chosen by the user; if the dialog is cancelled it returns an empty string. + +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 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. +### `dialog.showSaveDialog([window, ]options)` -### `dialog.showSaveDialog([browserWindow, ]options[, callback])` + -* `browserWindow` BrowserWindow (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object - * `title` String - * `defaultPath` String - * `buttonLabel` String - 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` Array -* `callback` Function (optional) + * `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 + displayed in front of the filename text field. + * `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. + +Returns `Promise` - Resolve with an object containing the following: + +* `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).) -On success this method returns the path of the file chosen by the user, -otherwise it returns `undefined`. +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. -If a `callback` is passed, the API call will be asynchronous and the result -will be passed via `callback(filename)` +> [!NOTE] +> On macOS, using the asynchronous version is recommended to avoid issues when +> expanding and collapsing the dialog. -### `dialog.showMessageBox([browserWindow, ]options[, callback])` +### `dialog.showMessageBoxSync([window, ]options)` + + -* `browserWindow` BrowserWindow (optional) +* `window` [BaseWindow](base-window.md) (optional) * `options` Object - * `type` String - 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. - * `buttons` Array - 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 - Index of the button in the buttons array which will + * `defaultId` Integer (optional) - Index of the button in the buttons array which will be selected by default when the message box opens. - * `title` String - Title of the message box, some platforms will not show it. - * `message` String - Content of the message box. - * `detail` String - Extra information of the message. - * `icon` [NativeImage](native-image.md) - * `cancelId` Integer - The value will be returned when user cancels the dialog - instead of clicking the buttons of the dialog. By default it is the index - of the buttons that have "cancel" or "no" as label, or 0 if there is no such - buttons. On macOS and Windows the index of "Cancel" button will always be - used as `cancelId`, not matter whether it is already specified. - * `noLink` Boolean - On Windows Electron will try to figure out which one of + * `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 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`. -* `callback` Function + * `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, `&` + characters are removed on macOS, converted to `_` on Linux, and left + untouched on Windows. For example, a button label of `Vie&w` will be + converted to `Vie_w` on Linux and `View` on macOS and can be selected + via `Alt-W` on Windows and Linux. + +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. -If a `callback` is passed, the API call will be asynchronous and the result -will be passed via `callback(response)`. +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)` + + + +* `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 + 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. + * `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 + checkbox. `false` by default. + * `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 + 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 + 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, `&` + characters are removed on macOS, converted to `_` on Linux, and left + untouched on Windows. For example, a button label of `Vie&w` will be + converted to `Vie_w` on Linux and `View` on macOS and can be selected + via `Alt-W` on Windows and Linux. + +Returns `Promise` - 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 + `checkboxLabel` was set. Otherwise `false`. + +Shows a message box. + +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. + 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, +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, and no GUI dialog will appear. +### `dialog.showCertificateTrustDialog([window, ]options)` _macOS_ _Windows_ + + + +* `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. + +Returns `Promise` - 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 `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 `window` argument is ignored since it is not possible to make + this confirmation dialog modal. + +## 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 | +|------------|---------------------------------|:-----------:|--------------------------------| +| macOS mas | True | Success | `['LONGBOOKMARKSTRING']` | +| macOS mas | True | Error | `['']` (array of empty string) | +| macOS mas | False | NA | `[]` (empty array) | +| non mas | any | NA | `[]` (empty array) | + ## Sheets On macOS, dialogs are presented as sheets attached to a window if you provide -a `BrowserWindow` 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 new file mode 100644 index 0000000000000..6ea2ac956cda0 --- /dev/null +++ b/docs/api/dock.md @@ -0,0 +1,86 @@ +## Class: Dock + +> Control your app in the macOS dock + +Process: [Main](../glossary.md#main-process)
+_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._ + +> [!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 + `informational` + +Returns `Integer` - an ID representing the request. + +When `critical` is passed, the dock icon will bounce until either the +application becomes active or the request is canceled. + +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. + +> [!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_ + +* `id` Integer + +Cancel the bounce of `id`. + +#### `dock.downloadFinished(filePath)` _macOS_ + +* `filePath` string + +Bounces the Downloads stack if the filePath is inside the Downloads folder. + +#### `dock.setBadge(text)` _macOS_ + +* `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. + +#### `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` - Resolves when the dock icon is shown. + +#### `dock.isVisible()` _macOS_ + +Returns `boolean` - Whether the dock icon is visible. + +#### `dock.setMenu(menu)` _macOS_ + +* `menu` [Menu](menu.md) + +Sets the application's [dock menu][dock-menu]. + +#### `dock.getMenu()` _macOS_ + +Returns `Menu | null` - The application's [dock menu][dock-menu]. + +#### `dock.setIcon(image)` _macOS_ + +* `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 7ec8fd1896feb..253c722f090f4 100644 --- a/docs/api/download-item.md +++ b/docs/api/download-item.md @@ -1,15 +1,19 @@ -# DownloadItem +## Class: DownloadItem > Control file downloads from remote sources. -`DownloadItem` is an `EventEmitter` that represents a download item in Electron. +Process: [Main](../glossary.md#main-process)
+_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') -let win = new BrowserWindow() +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. item.setSavePath('/tmp/save.pdf') @@ -35,14 +39,14 @@ win.webContents.session.on('will-download', (event, item, webContents) => { }) ``` -## Events +### Instance Events -### Event: 'updated' +#### Event: 'updated' Returns: * `event` Event -* `state` String +* `state` string - Can be `progressing` or `interrupted`. Emitted when the download has been updated and is not done. @@ -51,15 +55,15 @@ The `state` can be one of following: * `progressing` - The download is in-progress. * `interrupted` - The download has interrupted and can be resumed. -### Event: 'done' +#### Event: 'done' Returns: * `event` Event -* `state` String +* `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 +download, a cancelled download (via `downloadItem.cancel()`), and interrupted download that can't be resumed. The `state` can be one of following: @@ -68,85 +72,142 @@ The `state` can be one of following: * `cancelled` - The download has been cancelled. * `interrupted` - The download has interrupted and can not resume. -## Methods +### Instance Methods The `downloadItem` object has the following methods: -### `downloadItem.setSavePath(path)` +#### `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. If user doesn't set the save path via the API, Electron will use the original -routine to determine the save path(Usually prompts a save dialog). +routine to determine the save path; this usually prompts a save dialog. -### `downloadItem.getSavePath()` +#### `downloadItem.getSavePath()` -Returns 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. -### `downloadItem.pause()` +#### `downloadItem.setSaveDialogOptions(options)` + +* `options` SaveDialogOptions - Set the save file dialog options. This object has the same +properties as the `options` parameter of [`dialog.showSaveDialog()`](dialog.md). + +This API allows the user to set custom options for the save dialog that opens +for the download item by default. +The API is only available in session's `will-download` callback function. + +#### `downloadItem.getSaveDialogOptions()` + +Returns `SaveDialogOptions` - Returns the object previously set by `downloadItem.setSaveDialogOptions(options)`. + +#### `downloadItem.pause()` Pauses the download. -### `downloadItem.isPaused()` +#### `downloadItem.isPaused()` -Returns whether the download is paused. +Returns `boolean` - Whether the download is paused. -### `downloadItem.resume()` +#### `downloadItem.resume()` Resumes the download that has been paused. -### `downloadItem.canResume()` +> [!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. -Resumes whether the download can resume. +#### `downloadItem.canResume()` -### `downloadItem.cancel()` +Returns `boolean` - Whether the download can resume. + +#### `downloadItem.cancel()` Cancels the download operation. -### `downloadItem.getURL()` +#### `downloadItem.getURL()` + +Returns `string` - The origin URL where the item is downloaded from. + +#### `downloadItem.getMimeType()` + +Returns `string` - The files mime type. -Returns a `String` represents the origin url where the item is downloaded from. +#### `downloadItem.hasUserGesture()` -### `downloadItem.getMimeType()` +Returns `boolean` - Whether the download has user gesture. -Returns a `String` represents the mime type. +#### `downloadItem.getFilename()` -### `downloadItem.hasUserGesture()` +Returns `string` - The file name of the download item. -Returns a `Boolean` indicates whether the download has user gesture. +> [!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.getFilename()` +#### `downloadItem.getCurrentBytesPerSecond()` -Returns a `String` represents the file name of the download item. +Returns `Integer` - The current download speed in bytes per second. -**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.getTotalBytes()` -### `downloadItem.getTotalBytes()` +Returns `Integer` - The total size in bytes of the download item. -Returns a `Integer` represents the total size in bytes of the download item. If the size is unknown, it returns 0. -### `downloadItem.getReceivedBytes()` +#### `downloadItem.getReceivedBytes()` -Returns a `Integer` represents the received bytes of the download item. +Returns `Integer` - The received bytes of the download item. -### `downloadItem.getContentDisposition()` +#### `downloadItem.getPercentComplete()` -Returns a `String` represents the Content-Disposition field from the response +Returns `Integer` - The download completion in percent. + +#### `downloadItem.getContentDisposition()` + +Returns `string` - The Content-Disposition field from the response header. -### `downloadItem.getState()` +#### `downloadItem.getState()` -Returns current state as `String`. +Returns `string` - The current state. Can be `progressing`, `completed`, `cancelled` or `interrupted`. -Possible values are: +> [!NOTE] +> The following methods are useful specifically to resume a +> `cancelled` item when session is restarted. -* `progressing` - The download is in-progress. -* `completed` - The download completed successfully. -* `cancelled` - The download has been cancelled. -* `interrupted` - The download has interrupted. +#### `downloadItem.getURLChain()` + +Returns `string[]` - The complete URL chain of the item including any redirects. + +#### `downloadItem.getLastModifiedTime()` + +Returns `string` - Last-Modified header value. + +#### `downloadItem.getETag()` + +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. + +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 +routine to determine the save path; this usually prompts a save dialog. + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter diff --git a/docs/api/environment-variables.md b/docs/api/environment-variables.md index a4df27504b572..069e42a113fbd 100644 --- a/docs/api/environment-variables.md +++ b/docs/api/environment-variables.md @@ -7,7 +7,7 @@ are initialized earlier than the command line flags and the app's code. POSIX shell example: -```bash +```sh $ export ELECTRON_ENABLE_LOGGING=true $ electron ``` @@ -19,13 +19,161 @@ Windows console example: > electron ``` +## Production Variables + +The following environment variables are intended primarily for use at runtime +in packaged Electron applications. + +### `NODE_OPTIONS` + +Electron includes support for a subset of Node's [`NODE_OPTIONS`](https://nodejs.org/api/cli.html#cli_node_options_options). The majority are supported with the exception of those which conflict with Chromium's use of BoringSSL. + +Example: + +```sh +export NODE_OPTIONS="--no-warnings --max-old-space-size=2048" +``` + +Unsupported options are: + +```sh +--use-bundled-ca +--force-fips +--enable-fips +--openssl-config +--use-openssl-ca +``` + +`NODE_OPTIONS` are explicitly disallowed in packaged apps, except for the following: + +```sh +--max-http-header-size +--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 +geolocation webservice. To enable this feature, acquire a +[Google API key](https://developers.google.com/maps/documentation/geolocation/get-api-key) +and place the following code in your main process file, before opening any +browser windows that will make geolocation requests: + +```js +process.env.GOOGLE_API_KEY = 'YOUR_KEY_HERE' +``` + +By default, a newly generated Google API key may not be allowed to make geolocation requests. +To enable the geolocation webservice for your project, enable it through the +[API library](https://console.cloud.google.com/apis/library). + +N.B. You will need to add a +[Billing Account](https://cloud.google.com/billing/docs/how-to/payment-methods#add_a_payment_method) +to the project associated to the API key for the geolocation webservice to work. + +### `ELECTRON_NO_ASAR` + +Disables ASAR support. This variable is only supported in forked child processes +and spawned child processes that set `ELECTRON_RUN_AS_NODE`. + ### `ELECTRON_RUN_AS_NODE` Starts the process as a normal Node.js process. +In this mode, you will be able to pass [cli options](https://nodejs.org/api/cli.html) to Node.js as +you would when running the normal Node.js executable, with the exception of the following flags: + +* "--openssl-config" +* "--use-bundled-ca" +* "--use-openssl-ca", +* "--force-fips" +* "--enable-fips" + +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. + +### `ELECTRON_FORCE_WINDOW_MENU_BAR` _Linux_ + +Don't use the global menu bar on Linux. + +### `ELECTRON_TRASH` _Linux_ + +Set the trash implementation on Linux. Default is `gio`. + +Options: + +* `gvfs-trash` +* `trash-cli` +* `kioclient5` +* `kioclient` + +## Development Variables + +The following environment variables are intended primarily for development and +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` @@ -45,10 +193,32 @@ Shows the Windows's crash dialog when Electron crashes. This environment variable will not work if the `crashReporter` is started. -### `ELECTRON_NO_ATTACH_CONSOLE` _Windows_ +### `ELECTRON_OVERRIDE_DIST_PATH` -Don't attach to the current console session. +When running from the `electron` package, this variable tells +the `electron` command to use the specified build of Electron instead of +the one downloaded by `npm install`. Usage: -### `ELECTRON_FORCE_WINDOW_MENU_BAR` _Linux_ +```sh +export ELECTRON_OVERRIDE_DIST_PATH=/Users/username/projects/electron/out/Testing +``` -Don't use the global menu bar on Linux. +### `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: + +```sh +ELECTRON_INSTALL_PLATFORM=darwin npm install +``` + +### `ELECTRON_INSTALL_ARCH` + +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)
+_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` - 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 new file mode 100644 index 0000000000000..43f7ccfb40d8a --- /dev/null +++ b/docs/api/extensions.md @@ -0,0 +1,178 @@ +# 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. + +[chrome-extensions-api-index]: https://developer.chrome.com/extensions/api_index + +> [!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. + +## Loading extensions + +Electron only supports loading unpacked extensions (i.e., `.crx` files do not +work). Extensions are installed per-`session`. To load an extension, call +[`ses.extensions.loadExtension`](extensions-api.md#extensionsloadextensionpath-options): + +```js +const { session } = require('electron') + +session.defaultSession.loadExtension('path/to/unpacked/extension').then(({ id }) => { + // ... +}) +``` + +Loaded extensions will not be automatically remembered across exits; if you do +not call `loadExtension` when the app runs, the extension will not be loaded. + +Note that loading extensions is only supported in persistent sessions. +Attempting to load an extension into an in-memory session will throw an error. + +See the [`session`](session.md) documentation for more information about +loading, unloading, and querying active extensions. + +## Supported Extensions APIs + +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: + +- `chrome.extension.lastError` + +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: + +- `chrome.runtime.lastError` +- `chrome.runtime.id` + +The following methods of `chrome.runtime` are supported: + +- `chrome.runtime.getBackgroundPage` +- `chrome.runtime.getManifest` +- `chrome.runtime.getPlatformInfo` +- `chrome.runtime.getURL` +- `chrome.runtime.connect` +- `chrome.runtime.sendMessage` +- `chrome.runtime.reload` + +The following events of `chrome.runtime` are supported: + +- `chrome.runtime.onStartup` +- `chrome.runtime.onInstalled` +- `chrome.runtime.onSuspend` +- `chrome.runtime.onSuspendCanceled` +- `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` + +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 +> tab". Since Electron has no such concept, passing `-1` as a tab ID is not +> supported and will raise an error. + +See [official documentation](https://developer.chrome.com/docs/extensions/reference/tabs) for more information. + +### `chrome.webRequest` + +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 c39a0cf715e69..0000000000000 --- a/docs/api/file-object.md +++ /dev/null @@ -1,33 +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 on getting a real path from a dragged-onto-the-app file: - -```html -
- Drag your file here -
- - -``` diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md deleted file mode 100644 index 1ca64a456f28a..0000000000000 --- a/docs/api/frameless-window.md +++ /dev/null @@ -1,129 +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') -let win = new BrowserWindow({width: 800, height: 600, frame: false}) -win.show() -``` - -### Alternatives on macOS - -On macOS 10.10 Yosemite and newer, 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 new `titleBarStyle` option: - -```javascript -const {BrowserWindow} = require('electron') -let win = new BrowserWindow({titleBarStyle: 'hidden'}) -win.show() -``` - -## Transparent window - -By setting the `transparent` option to `true`, you can also make the frameless -window transparent: - -```javascript -const {BrowserWindow} = require('electron') -let 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://code.google.com/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') -let win = new BrowserWindow() -win.setIgnoreMouseEvents(true) -``` - -## 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. - -To make the whole window draggable, you can add `-webkit-app-region: drag` as -`body`'s style: - -```html - - -``` - -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 setting just a custom titlebar as draggable, you also need to make all -buttons in titlebar non-draggable. - -## Text selection - -In a frameless window the dragging behaviour 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 diff --git a/docs/api/global-shortcut.md b/docs/api/global-shortcut.md index 5a2f819ac368a..dd8c2195f4e99 100644 --- a/docs/api/global-shortcut.md +++ b/docs/api/global-shortcut.md @@ -2,18 +2,28 @@ > Detect keyboard events when the application does not have keyboard focus. +Process: [Main](../glossary.md#main-process) + 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. +> [!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') -```javascript -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.on('ready', () => { +app.whenReady().then(() => { // Register a 'CommandOrControl+X' shortcut listener. const ret = globalShortcut.register('CommandOrControl+X', () => { console.log('CommandOrControl+X is pressed') @@ -36,15 +46,27 @@ 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) + + +* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut. * `callback` Function +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. @@ -52,11 +74,52 @@ When the accelerator is already taken by other applications, this call will silently fail. This behavior is intended by operating systems, since they don't want applications to fight for global shortcuts. +The following accelerators will not be registered successfully on macOS 10.14 Mojave unless +the app has been authorized as a [trusted accessibility client](https://developer.apple.com/library/archive/documentation/Accessibility/Conceptual/AccessibilityMacOSX/OSXAXTestingApps.html): + +* "Media Play/Pause" +* "Media Next Track" +* "Media Previous Track" +* "Media Stop" + +### `globalShortcut.registerAll(accelerators, callback)` + + + +* `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. + +When a given accelerator is already taken by other applications, this call will +silently fail. This behavior is intended by operating systems, since they don't +want applications to fight for global shortcuts. + +The following accelerators will not be registered successfully on macOS 10.14 Mojave unless +the app has been authorized as a [trusted accessibility client](https://developer.apple.com/library/archive/documentation/Accessibility/Conceptual/AccessibilityMacOSX/OSXAXTestingApps.html): + +* "Media Play/Pause" +* "Media Next Track" +* "Media Previous Track" +* "Media Stop" + ### `globalShortcut.isRegistered(accelerator)` -* `accelerator` [Accelerator](accelerator.md) + + +* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut. -Returns 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 @@ -64,10 +127,55 @@ don't want applications to fight for global shortcuts. ### `globalShortcut.unregister(accelerator)` -* `accelerator` [Accelerator](accelerator.md) + + +* `accelerator` string - An [accelerator](../tutorial/keyboard-shortcuts.md#accelerators) shortcut. Unregisters the global shortcut of `accelerator`. ### `globalShortcut.unregisterAll()` + + Unregisters all of the global shortcuts. + +### `globalShortcut.setSuspended(suspended)` + + + +* `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()` + + + +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` + + + +> 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_ + + + +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_ + + + +* `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 new file mode 100644 index 0000000000000..b14b4ef1ba354 --- /dev/null +++ b/docs/api/in-app-purchase.md @@ -0,0 +1,138 @@ +# inAppPurchase + + + +> In-app purchases on Mac App Store. + +Process: [Main](../glossary.md#main-process) + +## Events + +The `inAppPurchase` module emits the following events: + +### Event: 'transactions-updated' + + + +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[, opts])` + + + +* `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` - 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. + +Returns `Promise` - Resolves with an array of [`Product`](structures/product.md) objects. + +Retrieves the product descriptions. + +### `inAppPurchase.canMakePayments()` + + + +Returns `boolean` - whether a user can make a payment. + +### `inAppPurchase.restoreCompletedTransactions()` + + + +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. + +### `inAppPurchase.finishAllTransactions()` + + + +Completes all pending transactions. + +### `inAppPurchase.finishTransactionByDate(date)` + + + +* `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 new file mode 100644 index 0000000000000..5f498f40fa64c --- /dev/null +++ b/docs/api/incoming-message.md @@ -0,0 +1,104 @@ +## Class: IncomingMessage + +> Handle responses to HTTP/HTTPS requests. + +Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-process)
+_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]. + +### Instance Events + +#### Event: 'data' + +Returns: + +* `chunk` Buffer - A chunk of response body's data. + +The `data` event is the usual method of transferring response data into +applicative code. + +#### Event: 'end' + +Indicates that response body has ended. Must be placed before 'data' event. + +#### Event: 'aborted' + +Emitted when a request has been canceled during an ongoing HTTP transaction. + +#### Event: 'error' + +Returns: + +* `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 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. + +### Instance Properties + +An `IncomingMessage` instance has the following readable properties: + +#### `response.statusCode` + +An `Integer` indicating the HTTP response status code. + +#### `response.statusMessage` + +A `string` representing the HTTP status message. + +#### `response.headers` + +A `Record` representing the HTTP response headers. The `headers` object is +formatted as follows: + +* All header names are lowercased. +* Duplicates of `age`, `authorization`, `content-length`, `content-type`, +`etag`, `expires`, `from`, `host`, `if-modified-since`, `if-unmodified-since`, +`last-modified`, `location`, `max-forwards`, `proxy-authorization`, `referer`, +`retry-after`, `server`, or `user-agent` are discarded. +* `set-cookie` is always an array. Duplicates are added to the array. +* For duplicate `cookie` headers, the values are joined together with '; '. +* For all other headers, the values are joined together with ', '. + +#### `response.httpVersion` + +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. + +#### `response.httpVersionMajor` + +An `Integer` indicating the HTTP protocol major version number. + +#### `response.httpVersionMinor` + +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. + + + +> [!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\ | any\> + * `event` [IpcMainServiceWorkerInvokeEvent][ipc-main-service-worker-invoke-event] + * `...args` any[] + +#### `ipcMainServiceWorker.handleOnce(channel, listener)` + +* `channel` string +* `listener` Function\ | 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 6ba9c2656403d..b14b010f1339a 100644 --- a/docs/api/ipc-main.md +++ b/docs/api/ipc-main.md @@ -1,97 +1,175 @@ +--- +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. -The `ipcMain` module is an instance of the -[EventEmitter](https://nodejs.org/api/events.html) class. When used in the main +Process: [Main](../glossary.md#main-process) + +The `ipcMain` module is an [Event Emitter][event-emitter]. When used in the main 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. * When sending a message, the event name is the `channel`. -* To reply a synchronous message, you need to set `event.returnValue`. -* To send an asynchronous back to the sender, you can use - `event.sender.send(...)`. - -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.sender.send('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') -``` +* To reply to a synchronous message, you need to set `event.returnValue`. +* To send an asynchronous message back to the sender, you can use + `event.reply(...)`. This helper method will automatically handle messages + coming from frames that aren't the main frame (e.g. iframes) whereas + `event.sender.send(...)` will always send to the main frame. -## Listening for Messages +## 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][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)` + + + +* `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][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 all listeners from the specified `channel`. Removes all listeners from all channels if no channel is specified. -Removes all listeners, or those of the specified `channel`. +### `ipcMain.handle(channel, listener)` -## Event object + -The `event` object passed to the `callback` has the following methods: +* `channel` string +* `listener` Function\ | any\> + * `event` [IpcMainInvokeEvent][ipc-main-invoke-event] + * `...args` any[] -### `event.returnValue` +Adds a handler for an `invoke`able IPC. This handler will be called whenever a +renderer calls `ipcRenderer.invoke(channel, ...args)`. -Set this to the value to be returned in a synchronous message. +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 title='Main Process' @ts-type={somePromise:(...args:unknown[])=>Promise} +ipcMain.handle('my-invokable-ipc', async (event, ...args) => { + const result = await somePromise(...args) + return result +}) +``` + +```js title='Renderer Process' @ts-type={arg1:unknown} @ts-type={arg2:unknown} +async () => { + const result = await ipcRenderer.invoke('my-invokable-ipc', arg1, arg2) + // ... +} +``` + +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\ | any\> + * `event` [IpcMainInvokeEvent][ipc-main-invoke-event] + * `...args` any[] + +Handles a single `invoke`able IPC message, then removes the listener. See +`ipcMain.handle(channel, listener)`. + +### `ipcMain.removeHandler(channel)` + + -### `event.sender` +* `channel` string -Returns the `webContents` that sent the message, you can call -`event.sender.send` to reply to the asynchronous message, see -[webContents.send][web-contents-send] for more information. +Removes any handler for `channel`, if present. -[web-contents-send]: web-contents.md#webcontentssendchannel-arg1-arg2- +[IPC tutorial]: ../tutorial/ipc.md +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter +[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 9835e42b46793..9438da81268d4 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -1,83 +1,280 @@ +--- +title: "ipcRenderer" +description: "Communicate asynchronously from a renderer process to the main process." +slug: ipc-renderer +hide_title: false +--- + # ipcRenderer + + > Communicate asynchronously from a renderer process to the main process. -The `ipcRenderer` module is an instance of the -[EventEmitter](https://nodejs.org/api/events.html) class. It provides a few +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 +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. -## Listening for Messages +## Methods -The `ipcRenderer` module has the following method to listen for events: +The `ipcRenderer` module has the following method to listen for events and send messages: ### `ipcRenderer.on(channel, listener)` -* `channel` String +* `channel` string * `listener` Function + * `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)` + + + +* `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][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)` + + + +* `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])` -* `channel` String (optional) +* `channel` string (optional) + +Removes all listeners from the specified `channel`. Removes all listeners from all channels if no channel is specified. + +### `ipcRenderer.send(channel, ...args)` + +* `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 +included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will +throw an exception. -Removes all listeners, or those of the specified `channel`. +> **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. -## Sending Messages +The main process handles it by listening for `channel` with the +[`ipcMain`](./ipc-main.md) module. -The `ipcRenderer` module has the following methods for sending messages: +If you need to transfer a [`MessagePort`][] to the main process, use [`ipcRenderer.postMessage`](#ipcrendererpostmessagechannel-message-transfer). -### `ipcRenderer.send(channel[, arg1][, arg2][, ...])` +If you want to receive a single response from the main process, like the result of a method call, consider using [`ipcRenderer.invoke`](#ipcrendererinvokechannel-args). -* `channel` String -* `arg` (optional) +### `ipcRenderer.invoke(channel, ...args)` -Send a message to the main process asynchronously via `channel`, you can also -send arbitrary arguments. Arguments will be serialized in JSON internally and -hence no functions or prototype chain will be included. + -The main process handles it by listening for `channel` with `ipcMain` module. +* `channel` string +* `...args` any[] -### `ipcRenderer.sendSync(channel[, arg1][, arg2][, ...])` +Returns `Promise` - Resolves with the response from the main process. -* `channel` String -* `arg` (optional) +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 +included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will +throw an exception. -Send a message to the main process synchronously via `channel`, you can also -send arbitrary arguments. Arguments will be serialized in JSON internally and -hence no functions or prototype chain will be included. +The main process should listen for `channel` with +[`ipcMain.handle()`](./ipc-main.md#ipcmainhandlechannel-listener). -The main process handles it by listening for `channel` with `ipcMain` module, +For example: + +```js @ts-type={someArgument:unknown} @ts-type={doSomeWork:(arg:unknown)=>Promise} +// Renderer process +ipcRenderer.invoke('some-name', someArgument).then((result) => { + // ... +}) + +// Main process +ipcMain.handle('some-name', async (event, someArgument) => { + const result = await doSomeWork(someArgument) + return result +}) +``` + +If you need to transfer a [`MessagePort`][] to the main process, use [`ipcRenderer.postMessage`](#ipcrendererpostmessagechannel-message-transfer). + +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 +* `...args` any[] + +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 +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 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, and replies by setting `event.returnValue`. -**Note:** Sending a synchronous message will block the whole renderer process, -unless you know what you are doing you should never use it. +> [!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). + +### `ipcRenderer.postMessage(channel, message, [transfer])` + + + +* `channel` string +* `message` any +* `transfer` MessagePort[] (optional) + +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` +property of the emitted event. -### `ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])` +For example: -* `channel` String -* `arg` (optional) +```js +// Renderer process +const { port1, port2 } = new MessageChannel() +ipcRenderer.postMessage('port', { message: 'hello' }, [port1]) + +// Main process +ipcMain.on('port', (e, msg) => { + const [port] = e.ports + // ... +}) +``` + +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 +* `...args` any[] Like `ipcRenderer.send` but the event will be sent to the `` element in the host page instead of the main process. + +[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 16fb7b7100eb1..0000000000000 --- a/docs/api/locales.md +++ /dev/null @@ -1,139 +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 | -| ar-AE | Arabic (U.A.E.) | -| ar-IQ | Arabic (Iraq) | -| ar | Arabic (Standard) | -| ar-BH | Arabic (Bahrain) | -| ar-DZ | Arabic (Algeria) | -| ar-EG | Arabic (Egypt) | -| ar | Aragonese | -| ar-JO | Arabic (Jordan) | -| ar-KW | Arabic (Kuwait) | -| ar-LB | Arabic (Lebanon) | -| ar-LY | Arabic (Libya) | -| ar-MA | Arabic (Morocco) | -| ar-OM | Arabic (Oman) | -| ar-QA | Arabic (Qatar) | -| ar-SA | Arabic (Saudi Arabia) | -| ar-SY | Arabic (Syria) | -| ar-TN | Arabic (Tunisia) | -| ar-YE | Arabic (Yemen) | -| as | Assamese | -| ast | Asturian | -| az | Azerbaijani | -| be | Belarusian | -| bg | Bulgarian | -| bg | Bulgarian | -| bn | Bengali | -| br | Breton | -| bs | Bosnian | -| ca | Catalan | -| ce | Chechen | -| ch | Chamorro | -| co | Corsican | -| cr | Cree | -| cs | Czech | -| cv | Chuvash | -| da | Danish | -| de | German (Standard) | -| de-AT | German (Austria) | -| de-CH | German (Switzerland) | -| de-DE | German (Germany) | -| de-LI | German (Liechtenstein) | -| de-LU | German (Luxembourg) | -| el | Greek | -| en-AU | English (Australia) | -| en-BZ | English (Belize) | -| en | English | -| en-CA | English (Canada) | -| en-GB | English (United Kingdom) | -| en-IE | English (Ireland) | -| en-JM | English (Jamaica) | -| en-NZ | English (New Zealand) | -| en-PH | English (Philippines) | -| en-TT | English (Trinidad & Tobago) | -| en-US | English (United States) | -| en-ZA | English (South Africa) | -| en-ZW | English (Zimbabwe) | -| eo | Esperanto | -| et | Estonian | -| eu | Basque | -| fa | Persian | -| fa | Farsi | -| fa-IR | Persian/Iran | -| fi | Finnish | -| fj | Fijian | -| fo | Faeroese | -| fr-CH | French (Switzerland) | -| fr-FR | French (France) | -| fr-LU | French (Luxembourg) | -| fr-MC | French (Monaco) | -| fr | French (Standard) | -| fr-BE | French (Belgium) | -| fr-CA | French (Canada) | -| fur | Friulian | -| fy | Frisian | -| ga | Irish | -| gd-IE | Gaelic (Irish) | -| gd | Gaelic (Scots) | -| gl | Galacian | -| gu | Gujurati | -| he | Hebrew | -| hi | Hindi | -| hr | Croatian | -| ht | Haitian | -| hu | Hungarian | -| hy | Armenian | -| id | Indonesian | -| is | Icelandic | -| it-CH | Italian (Switzerland) | -| it | Italian (Standard) | -| iu | Inuktitut | -| ja | Japanese | -| ka | Georgian | -| kk | Kazakh | -| km | Khmer | -| kn | Kannada | -| ko | Korean | -| ko-KP | Korean (North Korea) | -| ko-KR | Korean (South Korea) | -| ks | Kashmiri | -| ky | Kirghiz | -| la | Latin | -| lb | Luxembourgish | -| lt | Lithuanian | -| lv | Latvian | -| mi | Maori | -| mk | FYRO Macedonian | -| ml | Malayalam | -| mo | Moldavian | -| mr | Marathi | -| ms | Malay | -| mt | Maltese | -| my | Burmese | -| nb | Norwegian (Bokmal) | -| ne | Nepali | -| ng | Ndonga | -| nl | Dutch (Standard) | -| nl-BE | Dutch (Belgian) | -| nn | Norwegian (Nynorsk) | -| no | Norwegian | -| nv | Navajo | -| oc | Occitan | -| om | Oromo | -| or | Oriya | -| sq | Albanian | -| tlh | Klingon | -| zh-TW | Chinese (Taiwan) | -| zh | Chinese | -| zh-CN | Chinese (PRC) | -| zh-HK | Chinese (Hong Kong) | -| zh-SG | Chinese (Singapore) | diff --git a/docs/api/menu-item.md b/docs/api/menu-item.md index 3a9a565a9dcb5..0b26c34dc4655 100644 --- a/docs/api/menu-item.md +++ b/docs/api/menu-item.md @@ -1,95 +1,164 @@ # MenuItem +## Class: MenuItem + > Add items to native application menus and context menus. -See [`Menu`](menu.md) for examples. +Process: [Main](../glossary.md#main-process) -## Class: MenuItem +See [`Menu`](menu.md) for examples. -Create a new `MenuItem` with the following method: +> [!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) +### `new MenuItem(options)` * `options` Object - * `click` Function - Will be called with - `click(menuItem, browserWindow, event)` when the menu item is clicked. - * `role` String - Define the action of the menu item, when specified the - `click` property will be ignored. - * `type` String - Can be `normal`, `separator`, `submenu`, `checkbox` or - `radio`. - * `label` String - * `sublabel` String - * `accelerator` [Accelerator](accelerator.md) - * `icon` [NativeImage](native-image.md) - * `enabled` Boolean - If false, the menu item will be greyed out and + * `click` Function (optional) - Will be called with + `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`, `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) + * `accessibilityLabel` string (optional) _macOS_ + * `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. - * `visible` Boolean - If false, the menu item will be entirely hidden. - * `checked` Boolean - 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. - * `submenu` Menu - 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` then it will be automatically converted to one using + * `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](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 - 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. - * `position` String - This field allows fine-grained definition of the - specific location within a given menu. - -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` are optional when using a `role` and will default -to appropriate values for each platform. - -The `role` property can have following values: - -* `undo` -* `redo` -* `cut` -* `copy` -* `paste` -* `pasteandmatchstyle` -* `selectall` -* `delete` -* `minimize` - Minimize current window -* `close` - Close current window -* `quit`- Quit the application -* `togglefullscreen`- Toggle full screen mode on the current window - -On macOS `role` can also have following additional values: - -* `about` - Map to the `orderFrontStandardAboutPanel` action -* `hide` - Map to the `hide` action -* `hideothers` - Map to the `hideOtherApplications` action -* `unhide` - Map to the `unhideAllApplications` action -* `front` - Map to the `arrangeInFront` action -* `zoom` - Map to the `performZoom` action -* `window` - The submenu is a "Window" menu -* `help` - The submenu is a "Help" menu -* `services` - The submenu is a "Services" menu - -When specifying `role` on macOS, `label` and `accelerator` are the only options -that will affect the MenuItem. All other options will be ignored. + * `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 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 + the placement of their containing group before the containing group of the item + 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 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 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. + +#### `menuItem.label` + +A `string` indicating the item's visible label. + +This property can be dynamically changed. + +#### `menuItem.accessibilityLabel` _macOS_ + +A `string` indicating the item's accessibility label (used by assistive technology), if set. + +This property can be dynamically changed. + +#### `menuItem.click` + +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` [BaseWindow](base-window.md) +* `focusedWebContents` [WebContents](web-contents.md) + +#### `menuItem.submenu` + +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`, `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`, `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` + +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. + +This property can be dynamically changed. + +#### `menuItem.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. + #### `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. @@ -98,3 +167,24 @@ A `radio` menu item will turn on its `checked` property when clicked, and will turn off that property for all adjacent items in the same menu. You can add a `click` function for additional behavior. + +#### `menuItem.registerAccelerator` + +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`](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. + +#### `menuItem.menu` + +A [`Menu`](menu.md) that the item is a part of. diff --git a/docs/api/menu.md b/docs/api/menu.md index d4163c5f1543d..c04526d41ec2f 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -1,380 +1,168 @@ # Menu -> Create native application menus and context menus. - -Each `Menu` consists of multiple [`MenuItem`](menu-item.md)s and each `MenuItem` -can have a submenu. - -## Examples - -The `Menu` class is only available in the main process, but you can also use it -in the render process via the [`remote`](remote.md) module. - -### Main process - -An example of creating the application menu in the main process with the -simple template API: - -```javascript -const {Menu} = require('electron') - -const template = [ - { - label: 'Edit', - submenu: [ - { - role: 'undo' - }, - { - role: 'redo' - }, - { - type: 'separator' - }, - { - role: 'cut' - }, - { - role: 'copy' - }, - { - role: 'paste' - }, - { - role: 'pasteandmatchstyle' - }, - { - role: 'delete' - }, - { - role: 'selectall' - } - ] - }, - { - label: 'View', - submenu: [ - { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click (item, focusedWindow) { - if (focusedWindow) focusedWindow.reload() - } - }, - { - label: 'Toggle Developer Tools', - accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I', - click (item, focusedWindow) { - if (focusedWindow) focusedWindow.webContents.toggleDevTools() - } - }, - { - type: 'separator' - }, - { - role: 'togglefullscreen' - } - ] - }, - { - role: 'window', - submenu: [ - { - role: 'minimize' - }, - { - role: 'close' - } - ] - }, - { - role: 'help', - submenu: [ - { - label: 'Learn More', - click () { require('electron').shell.openExternal('http://electron.atom.io') } - } - ] - } -] - -if (process.platform === 'darwin') { - const name = require('electron').remote.app.getName() - template.unshift({ - label: name, - submenu: [ - { - role: 'about' - }, - { - type: 'separator' - }, - { - role: 'services', - submenu: [] - }, - { - type: 'separator' - }, - { - role: 'hide' - }, - { - role: 'hideothers' - }, - { - role: 'unhide' - }, - { - type: 'separator' - }, - { - role: 'quit' - } - ] - }) - // Window menu. - template[3].submenu = [ - { - label: 'Close', - accelerator: 'CmdOrCtrl+W', - role: 'close' - }, - { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize' - }, - { - label: 'Zoom', - role: 'zoom' - }, - { - type: 'separator' - }, - { - label: 'Bring All to Front', - role: 'front' - } - ] -} - -const menu = Menu.buildFromTemplate(template) -Menu.setApplicationMenu(menu) -``` - -### Render process - -Below is an example of creating a menu dynamically in a web page -(render process) by using the [`remote`](remote.md) module, and showing it when -the user right clicks the page: - -```html - - -``` - ## Class: Menu +> 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. ### Static Methods -The `menu` class has the following static methods: +The `Menu` class has the following static methods: #### `Menu.setApplicationMenu(menu)` -* `menu` Menu +- `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. -Sets `menu` as the application menu on macOS. On Windows and Linux, the `menu` -will be set as each window's top menu. +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 then gets an +underline, and the `&` character is not displayed on the button label. -**Note:** This API has to be called after the `ready` event of `app` module. +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`, and `Window`. #### `Menu.getApplicationMenu()` -Returns the application menu (an instance of `Menu`), if set, or `null`, if not set. +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. #### `Menu.sendActionToFirstResponder(action)` _macOS_ -* `action` String +- `action` string Sends the `action` to the first responder of application. This is used for -emulating default Cocoa menu behaviors, usually you would just use the -`role` property of `MenuItem`. +emulating default macOS menu behaviors. Usually you would use the +[`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` Array +- `template` ([MenuItemConstructorOptions](menu-item.md#new-menuitemoptions) | [MenuItem](menu-item.md))[] + +Returns [`Menu`](menu.md) -Generally, the `template` is just an array of `options` for constructing a +Generally, the `template` is an array of `options` for constructing a [MenuItem](menu-item.md). The usage can be referenced above. -You can also attach other fields to the element of the `template` and they -will become properties of the constructed menu items. +You can also attach other fields to the element of the `template` and they will become properties of the constructed menu items. ### Instance Methods The `menu` object has the following instance methods: -#### `menu.popup([browserWindow, x, y, positioningItem])` +#### `menu.popup([options])` + +- `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. + Must be declared if `x` is declared. + - `positioningItem` number (optional) _macOS_ - The index of the menu item to + be positioned under the mouse cursor at the specified coordinates. Default + is -1. + - `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 [`BaseWindow`](base-window.md). + +> [!TIP] +> For more details, see the [Context Menu](../tutorial/context-menu.md) guide. + +#### `menu.closePopup([window])` -* `browserWindow` BrowserWindow (optional) - Default is `BrowserWindow.getFocusedWindow()`. -* `x` Number (optional) - Default is the current mouse cursor position. -* `y` Number (**required** if `x` is used) - Default is the current mouse cursor position. -* `positioningItem` Number (optional) _macOS_ - The index of the menu item to - be positioned under the mouse cursor at the specified coordinates. Default is - -1. +- `window` [BaseWindow](base-window.md) (optional) - Default is the focused window. -Pops up this menu as a context menu in the `browserWindow`. +Closes the context menu in the `window`. #### `menu.append(menuItem)` -* `menuItem` MenuItem +- `menuItem` [MenuItem](menu-item.md) Appends the `menuItem` to the menu. +#### `menu.getMenuItemById(id)` + +- `id` string + +Returns [`MenuItem | null`](menu-item.md) - the item with the specified `id` + #### `menu.insert(pos, menuItem)` -* `pos` Integer -* `menuItem` MenuItem +- `pos` Integer +- `menuItem` [MenuItem](menu-item.md) Inserts the `menuItem` to the `pos` position of the menu. +### Instance Events + +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. + +#### Event: 'menu-will-show' + +Returns: + +- `event` Event + +Emitted when `menu.popup()` is called. + +#### Event: 'menu-will-close' + +Returns: + +- `event` Event + +Emitted when a popup is closed either manually or with `menu.closePopup()`. + ### Instance Properties `menu` objects also have the following properties: #### `menu.items` -Get an array containing the menu's items. - -## Notes on macOS Application Menu +A [`MenuItem[]`](menu-item.md) array containing the menu's items. -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` and -`Windows` menus. To make your menu a standard menu, you should set your menu's -`role` to one of 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 `position` and `id` to control how the item will be placed -when building a menu with `Menu.buildFromTemplate`. - -The `position` attribute of `MenuItem` has the form `[placement]=[id]`, where -`placement` is one of `before`, `after`, or `endof` and `id` is the unique ID of -an existing item in the menu: - -* `before` - Inserts this item before the id referenced item. If the - referenced item doesn't exist the item will be inserted at the end of - the menu. -* `after` - Inserts this item after id referenced item. If the referenced - item doesn't exist the item will be inserted at the end of the menu. -* `endof` - Inserts this item at the end of the logical group containing - the id referenced item (groups are created by separator items). If - the referenced item doesn't exist, a new separator group is created with - the given id and this item is inserted after that separator. - -When an item is positioned, all un-positioned items are inserted after -it until a new item is positioned. So if you want to position a group of -menu items in the same location you only need to specify a position for -the first item. - -### Examples - -Template: - -``` -[ - {label: '4', id: '4'}, - {label: '5', id: '5'}, - {label: '1', id: '1', position: 'before=4'}, - {label: '2', id: '2'}, - {label: '3', id: '3'} -] -``` - -Menu: - -``` -- 1 -- 2 -- 3 -- 4 -- 5 -``` - -Template: - -``` -[ - {label: 'a', position: 'endof=letters'}, - {label: '1', position: 'endof=numbers'}, - {label: 'b', position: 'endof=letters'}, - {label: '2', position: 'endof=numbers'}, - {label: 'c', position: 'endof=letters'}, - {label: '3', position: 'endof=numbers'} -] -``` - -Menu: - -``` -- --- -- a -- b -- c -- --- -- 1 -- 2 -- 3 -``` - -[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 +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 new file mode 100644 index 0000000000000..8e0a5e4123305 --- /dev/null +++ b/docs/api/message-channel-main.md @@ -0,0 +1,55 @@ +# MessageChannelMain + +`MessageChannelMain` is the main-process-side equivalent of the DOM +[`MessageChannel`][] object. Its singular function is to create a pair of +connected [`MessagePortMain`](message-port-main.md) objects. + +See the [Channel Messaging API][] documentation for more information on using +channel messaging. + +## Class: MessageChannelMain + +> Channel interface for channel messaging in the main process. + +Process: [Main](../glossary.md#main-process) + +Example: + + + +```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].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` + +A [`MessagePortMain`](message-port-main.md) property. + +#### `channel.port2` + +A [`MessagePortMain`](message-port-main.md) property. + +[`MessageChannel`]: https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel +[Channel Messaging API]: https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API diff --git a/docs/api/message-port-main.md b/docs/api/message-port-main.md new file mode 100644 index 0000000000000..371d358f94cb0 --- /dev/null +++ b/docs/api/message-port-main.md @@ -0,0 +1,59 @@ +# MessagePortMain + +`MessagePortMain` is the main-process-side equivalent of the DOM +[`MessagePort`][] object. It behaves similarly to the DOM version, with the +exception that it uses the Node.js `EventEmitter` event system, instead of the +DOM `EventTarget` system. This means you should use `port.on('message', ...)` +to listen for events, instead of `port.onmessage = ...` or +`port.addEventListener('message', ...)` + +See the [Channel Messaging API][] documentation for more information on using +channel messaging. + +`MessagePortMain` is an [EventEmitter][event-emitter]. + +## Class: MessagePortMain + +> Port interface for channel messaging in the main process. + +Process: [Main](../glossary.md#main-process)
+_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 + +#### `port.postMessage(message, [transfer])` + +* `message` any +* `transfer` MessagePortMain[] (optional) + +Sends a message from the port, and optionally, transfers ownership of objects +to other browsing contexts. + +#### `port.start()` + +Starts the sending of messages queued on the port. Messages will be queued +until this method is called. + +#### `port.close()` + +Disconnects the port, so it is no longer active. + +### Instance Events + +#### Event: 'message' + +Returns: + +* `messageEvent` Object + * `data` any + * `ports` MessagePortMain[] + +Emitted when a MessagePortMain object receives a message. + +#### Event: 'close' + +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/native-image.md b/docs/api/native-image.md index 947a5b77b038c..39a6d55a08420 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -2,81 +2,101 @@ > Create tray, dock, and application icons using PNG or JPG files. -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. +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) -For example, when creating a tray or setting a window's icon, you can pass an -image file path as a `String`: +> [!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. -```javascript -const {BrowserWindow, Tray} = require('electron') +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]. -const appIcon = new Tray('/Users/somebody/images/icon.png') -let win = new BrowserWindow({icon: '/Users/somebody/images/window.png'}) -console.log(appIcon, win) +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 tray = new Tray('/Users/somebody/images/icon.png') +const win = new BrowserWindow({ icon: '/Users/somebody/images/window.png' }) ``` -Or read the image from the clipboard which returns a `nativeImage`: +or generate a `NativeImage` instance from the same file: -```javascript -const {clipboard, Tray} = require('electron') -const image = clipboard.readImage() -const appIcon = new Tray(image) -console.log(appIcon) +```js title='Main Process' +const { BrowserWindow, nativeImage, Tray } = require('electron') + +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) - * 20x20 (125% DPI scale) - * 24x24 (150% DPI scale) - * 32x32 (200% DPI scale) + * 16x16 (100% DPI scale) + * 20x20 (125% DPI scale) + * 24x24 (150% DPI scale) + * 32x32 (200% DPI scale) * Large icon - * 32x32 (100% DPI scale) - * 40x40 (125% DPI scale) - * 48x48 (150% DPI scale) - * 64x64 (200% DPI scale) -* 256x256 + * 32x32 (100% DPI scale) + * 40x40 (125% DPI scale) + * 48x48 (150% DPI scale) + * 64x64 (200% DPI scale) + * 256x256 + +Check the _Icon Scaling_ section in the Windows [App Icon Construction][icons] reference. -Check the *Size requirements* section in [this article][icons]. +[icons]: https://learn.microsoft.com/en-us/windows/apps/design/style/iconography/app-icon-construction#icon-scaling -[icons]:https://msdn.microsoft.com/en-us/library/windows/desktop/dn742485(v=vs.85).aspx +:::note + +EXIF metadata is currently not supported and will not be taken into account during +image encoding and decoding. + +::: ## 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. +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 +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: -```text +```plaintext images/ ├── icon.png ├── icon@2x.png └── icon@3x.png ``` +```js title='Main Process' +const { Tray } = require('electron') -```javascript -const {Tray} = require('electron') -let appIcon = new Tray('/Users/somebody/images/icon.png') -console.log(appIcon) +const appTray = new Tray('/Users/somebody/images/icon.png') ``` -Following suffixes for DPI are also supported: +The following suffixes for DPI are also supported: * `@1x` * `@1.25x` @@ -90,98 +110,240 @@ Following suffixes for DPI are also supported: * `@4x` * `@5x` -## Template Image +## Template Image _macOS_ -Template images consist of black and clear colors (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()` +Returns `NativeImage` + Creates an empty `NativeImage` instance. +### `nativeImage.createThumbnailFromPath(path, size)` _macOS_ _Windows_ + +* `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` - 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`. +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') -let image = nativeImage.createFromPath('/Users/somebody/images/icon.png') +const image = nativeImage.createFromPath('/Users/somebody/images/icon.png') console.log(image) ``` -### `nativeImage.createFromBuffer(buffer[, scaleFactor])` +### `nativeImage.createFromBitmap(buffer, options)` + +* `buffer` [Buffer][buffer] +* `options` Object + * `width` Integer + * `height` Integer + * `scaleFactor` Number (optional) - Defaults to 1.0. + +Returns `NativeImage` + +Creates a new `NativeImage` instance from `buffer` that contains the raw bitmap +pixel data returned by `toBitmap()`. The specific format is platform-dependent. + +### `nativeImage.createFromBuffer(buffer[, options])` * `buffer` [Buffer][buffer] -* `scaleFactor` Double (optional) +* `options` Object (optional) + * `width` Integer (optional) - Required for bitmap buffers. + * `height` Integer (optional) - Required for bitmap buffers. + * `scaleFactor` Number (optional) - Defaults to 1.0. -Creates a new `NativeImage` instance from `buffer`. The default `scaleFactor` is -1.0. +Returns `NativeImage` + +Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or JPEG first. ### `nativeImage.createFromDataURL(dataURL)` -* `dataURL` String +* `dataURL` string + +Returns `NativeImage` + +Creates a new `NativeImage` instance from `dataUrl`, a base 64 encoded [Data URL][data-url] string. + +### `nativeImage.createFromNamedImage(imageName[, options])` _macOS_ + +* `imageName` string +* `options` Object | number[] (optional) - If `options` is a number array (_Deprecated_), it is interpreted as `hslShift`. If it is an object, the +following properties can be specified: + * `hslShift` number[] (optional) + * `pointSize` Number (optional) - Defaults to `30.0`. + * `weight` 'ultralight' | 'thin' | 'light' | 'regular' | 'medium' | 'semibold' | 'bold' | 'heavy' | 'black' (optional) - Defaults to `regular`. + * `scale` 'small' | 'medium' | 'large' (optional) - Defaults to `medium`. + +Returns `NativeImage` + +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). +* `hsl_shift[1]` (saturation): A saturation shift for the image, with the + following key values: + 0 = remove all color. + 0.5 = leave unchanged. + 1 = fully saturate the image. +* `hsl_shift[2]` (lightness): A lightness shift for the image, with the + following key values: + 0 = remove all lightness (make all pixels black). + 0.5 = leave unchanged. + 1 = full lightness (make all pixels white). + +This means that `[-1, 0, 1]` will make the image completely white and +`[-1, 1, 0]` will make the image completely black. + +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: + +```sh +echo -e '#import \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/). + +### `nativeImage.createMenuSymbol(imageName)` _macOS_ -Creates a new `NativeImage` instance from `dataURL`. +* `imageName` string + +Returns `NativeImage` + +Creates a new `NativeImage` instance from an SF Symbol for use in a native [Menu](./menu.md). See [SF Symbols](https://developer.apple.com/sf-symbols/) for a list of possible values. + +```js +const { nativeImage, MenuItem } = require('electron') + +const item = new MenuItem({ + icon: nativeImage.createMenuSymbol('folder.badge.plus'), + label: 'Create Folder' +}) +``` ## Class: NativeImage -A native wrapper for images such as tray, dock, and application icons. +> Natively wrap images such as tray, dock, and application icons. + +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
+_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 The following methods are available on instances of the `NativeImage` class: -#### `image.toPNG()` +#### `image.toPNG([options])` + +* `options` Object (optional) + * `scaleFactor` Number (optional) - Defaults to 1.0. -Returns a [Buffer][buffer] that contains the image's `PNG` encoded data. +Returns `Buffer` - A [Buffer][buffer] that contains the image's `PNG` encoded data. #### `image.toJPEG(quality)` -* `quality` Integer (**required**) - Between 0 - 100. +* `quality` Integer - Between 0 - 100. + +Returns `Buffer` - A [Buffer][buffer] that contains the image's `JPEG` encoded data. -Returns a [Buffer][buffer] that contains the image's `JPEG` encoded data. +#### `image.toBitmap([options])` + + -#### `image.toBitmap()` +* `options` Object (optional) + * `scaleFactor` Number (optional) - Defaults to 1.0. + * `colorSpace` [ColorSpace](structures/color-space.md) (optional) - The target color space + for the output pixel data. Defaults to sRGB. Pass the image's original color space to + preserve the previous behavior, or another color space to get pixel values in that space. -Returns a [Buffer][buffer] that contains a copy of the image's raw bitmap pixel +Returns `Buffer` - A [Buffer][buffer] that contains a copy of the image's raw bitmap pixel data. -#### `image.toDataURL()` +#### `image.toDataURL([options])` -Returns the data URL of the image. + + +* `options` Object (optional) + * `scaleFactor` Number (optional) - Defaults to 1.0. + +Returns `string` - The [Data URL][data-url] of the image. -#### `image.getBitmap()` +#### `image.getBitmap([options])` _Deprecated_ + + -Returns a [Buffer][buffer] that contains the image's raw bitmap pixel data. +* `options` Object (optional) + * `scaleFactor` Number (optional) - Defaults to 1.0. + * `colorSpace` [ColorSpace](structures/color-space.md) (optional) - The target color space + for the output pixel data. Defaults to sRGB. Pass the image's original color space to + preserve the previous behavior, or another color space to get pixel values in that space. -The difference between `getBitmap()` and `toBitmap()` is, `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 a [Buffer][buffer] that stores C pointer to underlying native handle of -the image. On macOS, a pointer to `NSImage` instance would be returned. +Returns `Buffer` - A [Buffer][buffer] that stores C pointer to underlying native handle of +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 @@ -189,20 +351,85 @@ image instead of a copy, so you _must_ ensure that the associated #### `image.isEmpty()` -Returns a boolean whether the image is empty. +Returns `boolean` - Whether the image is empty. -#### `image.getSize()` +#### `image.getSize([scaleFactor])` -Returns the size of the image. +* `scaleFactor` Number (optional) - Defaults to 1.0. -[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer +Returns [`Size`](structures/size.md). + +If `scaleFactor` is passed, this will return the size corresponding to the image representation most closely matching the passed value. #### `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 a boolean whether the image is a template image. +Returns `boolean` - Whether the image is a macOS [template image][template-image]. + +#### `image.crop(rect)` + +* `rect` [Rectangle](structures/rectangle.md) - The area of the image to crop. + +Returns `NativeImage` - The cropped image. + +#### `image.resize(options)` + +* `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 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 + to be mapped to the same algorithm on a given platform. + +Returns `NativeImage` - The resized image. + +If only the `height` or the `width` are specified then the current aspect ratio +will be preserved in the resized image. + +#### `image.getAspectRatio([scaleFactor])` + +* `scaleFactor` Number (optional) - Defaults to 1.0. + +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 `Number[]` - An array of all scale factors corresponding to representations for a given `NativeImage`. + +#### `image.addRepresentation(options)` + +* `options` Object + * `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 + encoded PNG or JPEG image. + +Add an image representation for a specific scale factor. This can be used +to programmatically add different scale factor representations to an image. This +can be called on empty images. + +### Instance Properties + +#### `nativeImage.isMacTemplateImage` _macOS_ + +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 new file mode 100644 index 0000000000000..c587cb8ca2631 --- /dev/null +++ b/docs/api/native-theme.md @@ -0,0 +1,90 @@ +# nativeTheme + +> Read and respond to changes in Chromium's native color theme. + +Process: [Main](../glossary.md#main-process) + +## Events + +The `nativeTheme` module emits the following events: + +### Event: 'updated' + +Emitted when something in the underlying NativeTheme has changed. This normally +means that either the value of `shouldUseDarkColors`, +`shouldUseHighContrastColors` or `shouldUseInvertedColorScheme` has changed. +You will have to check them to determine which one has changed. + +## Properties + +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 +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 +the value that Chromium has chosen to use internally. + +Setting this property to `system` will remove the override and +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 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 + +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 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 + +The usage of this property should align with a classic "dark mode" state machine in your application +where the user has three options. + +* `Follow OS` --> `themeSource = 'system'` +* `Dark Mode` --> `themeSource = 'dark'` +* `Light Mode` --> `themeSource = 'light'` + +Your application should then always use `shouldUseDarkColors` to determine what CSS to apply. + +### `nativeTheme.shouldUseHighContrastColors` _macOS_ _Windows_ _Readonly_ + +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 +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)
+_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` - 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 new file mode 100644 index 0000000000000..2ae5beabfc9ee --- /dev/null +++ b/docs/api/net-log.md @@ -0,0 +1,52 @@ +# netLog + +> Logging network events for a session. + +Process: [Main](../glossary.md#main-process) + +```js +const { app, netLog } = require('electron') + +app.whenReady().then(async () => { + await netLog.startLogging('/path/to/net-log') + // After some network events + const path = await netLog.stopLogging() + console.log('Net-logs written to', path) +}) +``` + +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. + +## Methods + +### `netLog.startLogging(path[, options])` + +* `path` string - File path to record network logs. +* `options` Object (optional) + * `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, + logging will automatically stop. Defaults to unlimited. + +Returns `Promise` - resolves when the net log has begun recording. + +Starts recording network events to `path`. + +### `netLog.stopLogging()` + +Returns `Promise` - resolves when the net log has been flushed to disk. + +Stops recording network events. If not called, net logging will automatically end when app quits. + +## Properties + +### `netLog.currentlyLogging` _Readonly_ + +A `boolean` property that indicates whether network logs are currently being recorded. diff --git a/docs/api/net.md b/docs/api/net.md new file mode 100644 index 0000000000000..c3286b60f01a4 --- /dev/null +++ b/docs/api/net.md @@ -0,0 +1,201 @@ +# net + +> Issue HTTP/HTTPS requests using Chromium's native networking library + +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 +[HTTPS](https://nodejs.org/api/https.html) modules of Node.js but uses +Chromium's native networking library instead of the Node.js implementation, +offering better support for web proxies. It also supports checking network status. + +The following is a non-exhaustive list of why you may consider using the `net` +module instead of the native Node.js modules: + +* Automatic management of system proxy configuration, support of the wpad + protocol and proxy pac configuration files. +* Automatic tunneling of HTTPS requests. +* Support for authenticating proxies using basic, digest, NTLM, Kerberos or + negotiate authentication schemes. +* Support for traffic monitoring proxies: Fiddler-like proxies used for access + control and monitoring. + +The API components (including classes, methods, properties and event names) are similar to those used in +Node.js. + +Example usage: + +```js +const { app } = require('electron') + +app.whenReady().then(() => { + const { net } = require('electron') + const request = net.request('https://github.com') + request.on('response', (response) => { + console.log(`STATUS: ${response.statusCode}`) + console.log(`HEADERS: ${JSON.stringify(response.headers)}`) + response.on('data', (chunk) => { + console.log(`BODY: ${chunk}`) + }) + response.on('end', () => { + console.log('No more data in response.') + }) + }) + request.end() +}) +``` + +The `net` API can be used only after the application emits the `ready` event. +Trying to use the module before the `ready` event will throw an error. + +## Methods + +The `net` module has the following methods: + +### `net.request(options)` + +* `options` ([ClientRequestConstructorOptions](client-request.md#new-clientrequestoptions) | string) - The `ClientRequest` constructor options. + +Returns [`ClientRequest`](./client-request.md) + +Creates a [`ClientRequest`](./client-request.md) instance using the provided +`options` which are directly forwarded to the `ClientRequest` constructor. +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` - 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('my app') + } 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. + +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 +`true` is inconclusive; even if some link is up, it is uncertain +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`](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 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 +`true` is inconclusive; even if some link is up, it is uncertain +whether a particular connection attempt to a particular remote site +will be successful. + +### `net.WebSocket` + +> [!NOTE] +> This property is only available in the [main process](../glossary.md#main-process). + +A [`typeof WebSocket`](./web-socket.md) reference to the [`WebSocket`](./web-socket.md) +class, which can be used to create [WHATWG-compatible](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) +WebSocket connections through Chromium's network stack from the main process. + +```js +const { app, net } = require('electron') + +app.whenReady().then(() => { + const ws = new net.WebSocket('wss://echo.websocket.events') + ws.onmessage = (event) => console.log(event.data) +}) +``` diff --git a/docs/api/notification.md b/docs/api/notification.md new file mode 100644 index 0000000000000..f20a068de7c42 --- /dev/null +++ b/docs/api/notification.md @@ -0,0 +1,494 @@ +# Notification + +> Create OS desktop notifications + +Process: [Main](../glossary.md#main-process) + +> [!NOTE] +> If you want to show notifications from a renderer process you should use the +> [web Notifications 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 + +> Create OS desktop notifications + +Process: [Main](../glossary.md#main-process) + +`Notification` is an [EventEmitter][event-emitter]. + +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 + +#### `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` - 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 +}) +``` + +#### `Notification.remove(id)` _macOS_ + +* `id` (string | string[]) - The notification identifier(s) to remove. These correspond to the `id` values set in the [`Notification` constructor](#new-notificationoptions). + +Removes one or more delivered notifications from Notification Center by their identifier(s). + +```js +const { Notification } = require('electron') + +// Remove a single notification +Notification.remove('my-notification-id') + +// Remove multiple notifications +Notification.remove(['msg-1', 'msg-2', 'msg-3']) +``` + +#### `Notification.removeAll()` _macOS_ + +Removes all of the app's delivered notifications from Notification Center. + +```js +const { Notification } = require('electron') + +Notification.removeAll() +``` + +#### `Notification.removeGroup(groupId)` _macOS_ + +* `groupId` string - The group identifier of the notifications to remove. This corresponds to the `groupId` value set in the [`Notification` constructor](#new-notificationoptions). + +Removes all delivered notifications with the given `groupId` from Notification Center. + +```js +const { Notification } = require('electron') + +// Remove all notifications in the 'chat-thread-1' group +Notification.removeGroup('chat-thread-1') +``` + +### `new Notification([options])` + +* `options` Object (optional) + * `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. Use this identifier with [`Notification.remove()`](#notificationremoveid-macos) to remove specific delivered notifications, or with [`Notification.getHistory()`](#notificationgethistory-macos) to identify them. + * `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. Use this identifier with [`Notification.removeGroup()`](#notificationremovegroupgroupid-macos) to remove all notifications in a group. + * `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: + +:::info + +Some events are only available on specific operating systems and are labeled as such. + +::: + +#### Event: 'show' + +Returns: + +* `event` Event + +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: + +* `event` Event + +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: + +* `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. + +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: + +* `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`. + +```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: + +* `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' _macOS_ _Windows_ + +Returns: + +* `event` Event +* `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 the `new Notification()` constructor have the following instance methods: + +#### `notification.show()` + +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. + +#### `notification.subtitle` + +A `string` property representing the subtitle of the notification. + +#### `notification.body` + +A `string` property representing the body of the notification. + +#### `notification.replyPlaceholder` + +A `string` property representing the reply placeholder of the notification. + +#### `notification.sound` + +A `string` property representing the sound of the notification. + +#### `notification.closeButtonText` + +A `string` property representing the close button text of the notification. + +#### `notification.silent` + +A `boolean` property representing whether the notification is silent. + +#### `notification.hasReply` + +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'. + +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'. + +If `timeoutType` is set to 'never', the notification never expires. It stays open until closed by the calling API or the user. + +#### `notification.actions` + +A [`NotificationAction[]`](structures/notification-action.md) property representing the actions of the notification. + +#### `notification.toastXml` _Windows_ + +A `string` property representing the custom Toast XML of the notification. + +### Playing Sounds + +On macOS, you can specify the name of the sound you'd like to play when the +notification is shown. Any of the default sounds (under System Preferences > +Sound) can be used, in addition to custom sound files. Be sure that the sound +file is copied under the app bundle (e.g., `YourApp.app/Contents/Resources`), +or one of the following locations: + +* `~/Library/Sounds` +* `/Library/Sounds` +* `/Network/Library/Sounds` +* `/System/Library/Sounds` + +See the [`NSSound`](https://developer.apple.com/documentation/appkit/nssound) docs for more information. + +[event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter 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 57e9d030be920..83289e0739123 100644 --- a/docs/api/power-monitor.md +++ b/docs/api/power-monitor.md @@ -2,24 +2,11 @@ > Monitor power state changes. -You can only use it in the main process. You should not use this module until the `ready` -event of the `app` module is emitted. - -For example: - -```javascript -const {app} = require('electron') - -app.on('ready', () => { - require('electron').powerMonitor.on('suspend', () => { - console.log('The system is going to sleep') - }) -}) -``` +Process: [Main](../glossary.md#main-process) ## Events -The `power-monitor` module emits the following events: +The `powerMonitor` module emits the following events: ### Event: 'suspend' @@ -29,10 +16,101 @@ Emitted when the system is suspending. Emitted when system is resuming. -### Event: 'on-ac' _Windows_ +### Event: 'on-ac' _macOS_ _Windows_ Emitted when the system changes to AC power. -### Event: 'on-battery' _Windows_ +### Event: 'on-battery' _macOS_ _Windows_ 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 +invokes `e.preventDefault()`, Electron will attempt to delay system shutdown in +order for the app to exit cleanly. If `e.preventDefault()` is called, the app +should exit as soon as possible by calling something like `app.quit()`. + +### Event: 'lock-screen' _macOS_ _Windows_ + +Emitted when the system is about to lock the screen. + +### Event: 'unlock-screen' _macOS_ _Windows_ + +Emitted as soon as the systems screen is unlocked. + +### Event: 'user-did-become-active' _macOS_ + +Emitted when a login session is activated. See [documentation](https://developer.apple.com/documentation/appkit/nsworkspacesessiondidbecomeactivenotification?language=objc) for more information. + +### Event: 'user-did-resign-active' _macOS_ + +Emitted when a login session is deactivated. See [documentation](https://developer.apple.com/documentation/appkit/nsworkspacesessiondidresignactivenotification?language=objc) for more information. + +## Methods + +The `powerMonitor` module has the following methods: + +### `powerMonitor.getSystemIdleState(idleThreshold)` + +* `idleThreshold` Integer + +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. + +### `powerMonitor.getSystemIdleTime()` + +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. + +To monitor for changes in this property, use the `on-battery` and `on-ac` +events. + +## Properties + +### `powerMonitor.onBatteryPower` + +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 4ad17df53bd25..348a6b78907a6 100644 --- a/docs/api/power-save-blocker.md +++ b/docs/api/power-save-blocker.md @@ -2,10 +2,12 @@ > Block the system from entering low-power (sleep) mode. +Process: [Main](../glossary.md#main-process) + For example: -```javascript -const {powerSaveBlocker} = require('electron') +```js +const { powerSaveBlocker } = require('electron') const id = powerSaveBlocker.start('prevent-display-sleep') console.log(powerSaveBlocker.isStarted(id)) @@ -19,20 +21,23 @@ 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: + Keeps system active but allows screen to be turned off. Example use cases: downloading a file or playing audio. - * `prevent-display-sleep`- Prevent the display from going to sleep. Keeps - system and screen active. Example use case: playing video. + * `prevent-display-sleep` - Prevent the display from going to sleep. Keeps + system and screen active. Example use case: playing video. + +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` @@ -45,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 a 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 e467f2fc2cdb5..3833bf40d58f9 100644 --- a/docs/api/process.md +++ b/docs/api/process.md @@ -2,7 +2,40 @@ > Extensions to process object. -The `process` object is extended in Electron with following APIs: +Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process) + +Electron's `process` object is extended from the +[Node.js `process` object](https://nodejs.org/api/process.html). +It adds the following events, properties, and methods: + +## Sandbox + +In sandboxed renderers the `process` object contains only a subset of the APIs: + +* `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 @@ -11,100 +44,217 @@ The `process` object is extended in Electron with following 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 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 +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 +`undefined`. + ### `process.noAsar` -Setting this to `true` can disable the support for `asar` archives in Node's -built-in modules. +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.type` +### `process.noDeprecation` -Current process's type, can be `"browser"` (i.e. main process) or `"renderer"`. +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.versions.electron` +### `process.resourcesPath` _Readonly_ -Electron's version string. +A `string` representing the path to the resources directory. -### `process.versions.chrome` +### `process.sandboxed` _Readonly_ -Chrome's version string. +A `boolean`. When the renderer process is sandboxed, this property is `true`, +otherwise it is `undefined`. -### `process.resourcesPath` +### `process.contextIsolated` _Readonly_ -Path to the resources directory. +A `boolean` that indicates whether the current renderer context has `contextIsolation` enabled. +It is `undefined` in the main process. -### `process.mas` +### `process.throwDeprecation` -For Mac App Store build, this property is `true`, for other builds it is -`undefined`. +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.windowsStore` +### `process.traceDeprecation` -If the app is running as a Windows Store app (appx), this property is `true`, -for otherwise it is `undefined`. +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 used instead of the `--trace-deprecation` command line flag. -### `process.defaultApp` +### `process.traceProcessWarnings` -When app is started by being passed as parameter to the default app, this -property is `true` in the main process, otherwise it is `undefined`. +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 used instead of the `--trace-warnings` command + line flag. + +### `process.type` _Readonly_ + +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. + +### `process.versions.electron` _Readonly_ + +A `string` representing Electron's version string. + +### `process.windowsStore` _Readonly_ + +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 -The `process` object has the following method: +The `process` object has the following methods: ### `process.crash()` Causes the main thread of the current process crash. -### `process.hang()` +### `process.getCreationTime()` -Causes the main thread of the current process hang. +Returns `number | null` - The number of milliseconds since epoch, or `null` if the information is unavailable -### `process.setFdLimit(maxDescriptors)` _macOS_ _Linux_ +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. -* `maxDescriptors` Integer +### `process.getCPUUsage()` -Sets the file descriptor soft limit to `maxDescriptors` or the OS hard -limit, whichever is lower for the current process. +Returns [`CPUUsage`](structures/cpu-usage.md) + +### `process.getHeapStatistics()` + +Returns `Object`: + +* `totalHeapSize` Integer +* `totalHeapSizeExecutable` Integer +* `totalPhysicalSize` Integer +* `totalAvailableSize` Integer +* `usedHeapSize` Integer +* `heapSizeLimit` Integer +* `mallocedMemory` Integer +* `peakMallocedMemory` Integer +* `doesZapGarbage` boolean + +Returns an object with V8 heap statistics. Note that all statistics are reported in Kilobytes. + +### `process.getBlinkMemoryInfo()` + +Returns `Object`: + +* `allocated` Integer - Size of all allocated objects in Kilobytes. +* `total` Integer - Total allocated space in Kilobytes. + +Returns an object with Blink memory information. +It can be useful for debugging rendering / DOM related memory issues. +Note that all values are reported in Kilobytes. ### `process.getProcessMemoryInfo()` +Returns `Promise` - Resolves with a [ProcessMemoryInfo](structures/process-memory-info.md) + Returns an object giving memory usage statistics about the current process. Note that all statistics are reported in Kilobytes. +This api should be called after app ready. -* `workingSetSize` Integer - The amount of memory currently pinned to actual physical - RAM. -* `peakWorkingSetSize` Integer - The maximum amount of memory that has ever been pinned - to actual physical RAM. -* `privateBytes` Integer - The amount of memory not shared by other processes, such as - JS heap or HTML content. -* `sharedBytes` Integer - The amount of memory shared between processes, typically - memory consumed by the Electron code itself +Chromium does not provide `residentSet` value for macOS. This is because macOS +performs in-memory compression of pages that haven't been recently used. As a +result the resident set size value is not what one would expect. `private` memory +is more representative of the actual pre-compression memory usage of the process +on macOS. ### `process.getSystemMemoryInfo()` -Returns an object giving memory usage statistics about the entire system. Note -that all statistics are reported in Kilobytes. +Returns `Object`: * `total` Integer - The total amount of physical memory in Kilobytes available to the system. * `free` Integer - The total amount of memory not being used by applications or disk cache. -* `swapTotal` Integer - The total amount of swap memory in Kilobytes available to the - system. _Windows_ _Linux_ -* `swapFree` Integer - The free amount of swap memory in Kilobytes available to the - system. _Windows_ _Linux_ +* `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 + system. + +Returns an object giving memory usage statistics about the entire system. Note +that all statistics are reported in Kilobytes. + +### `process.getSystemVersion()` + +Returns `string` - The version of the host operating system. + +Example: + +```js +const version = process.getSystemVersion() +console.log(version) +// On macOS -> '10.13.6' +// On Windows -> '10.0.17763' +// On Linux -> '4.15.0-45-generic' +``` + +> [!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. + +Returns `boolean` - Indicates whether the snapshot has been created successfully. + +Takes a V8 heap snapshot and saves it to `filePath`. + +### `process.hang()` + +Causes the main thread of the current process hang. + +### `process.setFdLimit(maxDescriptors)` _macOS_ _Linux_ + +* `maxDescriptors` Integer + +Sets the file descriptor soft limit to `maxDescriptors` or the OS hard +limit, whichever is lower for the current process. diff --git a/docs/api/protocol.md b/docs/api/protocol.md index 97e37d3c4ba24..c1ee54e511c07 100644 --- a/docs/api/protocol.md +++ b/docs/api/protocol.md @@ -2,39 +2,101 @@ > Register a custom protocol and intercept existing protocol requests. +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.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. + +## Using `protocol` with a custom `partition` or `session` + +A protocol is registered to a specific Electron [`session`](./session.md) +object. If you don't specify a session, then your `protocol` will be applied to +the default session that Electron uses. However, if you define a `partition` or +`session` on your `browserWindow`'s `webPreferences`, then that window will use +a different session and your custom protocol will not work if you just use +`electron.protocol.XXX`. + +To have your custom protocol work in combination with a custom session, you need +to register it to that session explicitly. + +```js +const { app, BrowserWindow, net, protocol, session } = require('electron') + +const path = require('node:path') +const url = require('node:url') -app.on('ready', () => { - protocol.registerFileProtocol('atom', (request, callback) => { - const url = request.url.substr(7) - callback({path: path.normalize(`${__dirname}/${url}`)}) - }, (error) => { - if (error) console.error('Failed to register protocol') +app.whenReady().then(() => { + const partition = 'persist:example' + const ses = session.fromPartition(partition) + + ses.protocol.handle('atom', (request) => { + const filePath = request.url.slice('atom://'.length) + return net.fetch(url.pathToFileURL(path.resolve(__dirname, filePath)).toString()) }) + + const mainWindow = new BrowserWindow({ webPreferences: { partition } }) }) ``` -**Note:** All methods unless specified can only be used after the `ready` event -of the `app` module gets emitted. +## 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: -### `protocol.registerStandardSchemes(schemes)` +### `protocol.registerSchemesAsPrivileged(customSchemes)` + +* `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. -* `schemes` Array - Custom schemes to be registered as standard schemes. +Registers the `scheme` as standard, secure, bypasses content security policy for +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. -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. +An example of registering a privileged scheme, that bypasses Content Security +Policy: -Registering a scheme as standard, will allow relative and absolute resources to +```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. + +Registering a scheme as standard allows relative and absolute resources to be resolved correctly when served. Otherwise the scheme will behave like the `file` protocol, but without the ability to resolve relative URLs. @@ -48,183 +110,441 @@ non-standard schemes can not recognize relative URLs: ``` -So if you want to register a custom protocol to replace the `http` protocol, you -have to register it as standard scheme: +Registering a scheme as standard will allow access to files through the +[FileSystem API][file-system-api]. Otherwise the renderer will throw a security +error for the scheme. + +By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, +cookies) are disabled for non standard schemes. So in general if you want to +register a custom protocol to replace the `http` protocol, you have to register +it as a standard scheme. + +Protocols that use streams (http and stream protocols) should set `stream: true`. +The `