diff --git a/.github/scripts/setup-rust-build.sh b/.github/scripts/setup-rust-build.sh index 4bb424c59508..cd86c74166f3 100644 --- a/.github/scripts/setup-rust-build.sh +++ b/.github/scripts/setup-rust-build.sh @@ -3,7 +3,13 @@ TRIPLE=$1 ANDROID_SDK_LEVEL=$2 LLVM_PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64" LLVM_BIN="$LLVM_PATH/bin" -CLANG_PATH="$LLVM_BIN/${TRIPLE}${ANDROID_SDK_LEVEL}-clang" + +NDK_TRIPLE=$TRIPLE +if [ "$NDK_TRIPLE" = "armv7-linux-androideabi" ]; then + NDK_TRIPLE="armv7a-linux-androideabi" +fi + +CLANG_PATH="$LLVM_BIN/${NDK_TRIPLE}${ANDROID_SDK_LEVEL}-clang" UTRIPLE="$(echo $TRIPLE | sed 's/-/_/g')" UUTRIPLE="$(echo $UTRIPLE | tr a-z A-Z)" diff --git a/.github/workflows/build-manager.yml b/.github/workflows/build-manager.yml index 35c4fe08e8c6..3a7a95eec75e 100644 --- a/.github/workflows/build-manager.yml +++ b/.github/workflows/build-manager.yml @@ -2,8 +2,9 @@ name: Build Manager on: push: - branches: [ "main", "dev", "ci" ] + branches: [ "main", "dev", "ci", "master" ] paths: + - 'README.md' - '.github/workflows/build-manager.yml' - '.github/workflows/build-lkm.yml' - '.github/workflows/ddk-lkm.yml' @@ -14,6 +15,7 @@ on: - 'manager/**' - 'kernel/**' - 'userspace/**' + - 'scripts/ksubot.py' pull_request: branches: [ "main", "dev" ] paths: @@ -27,7 +29,9 @@ on: - 'manager/**' - 'kernel/**' - 'userspace/**' + - 'scripts/ksubot.py' workflow_call: + workflow_dispatch: jobs: generate-key: @@ -102,6 +106,7 @@ jobs: matrix: include: - target: aarch64-linux-android + - target: armv7-linux-androideabi - target: x86_64-linux-android uses: ./.github/workflows/ksud.yml with: @@ -146,7 +151,7 @@ jobs: fetch-depth: 0 - name: Write key - if: ${{ ( github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' )) || github.ref_type == 'tag' }} + if: ${{ github.event_name != 'pull_request' || github.ref_type == 'tag' }} run: | if [ ! -z "${{ secrets.KEYSTORE }}" ]; then { @@ -155,7 +160,7 @@ jobs: echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' echo KEYSTORE_FILE='key.jks' } >> gradle.properties - echo ${{ secrets.KEYSTORE }} | base64 -d > key.jks + echo "${{ secrets.KEYSTORE }}" | base64 -d > key.jks fi - name: Write PR key @@ -188,13 +193,13 @@ jobs: - name: Build with Gradle run: | if [ "${{ github.event_name }}" = "pull_request" ]; then - ./gradlew clean assembleRelease -PIS_PR_BUILD=true + ./gradlew assembleRelease -PIS_PR_BUILD=true else - ./gradlew clean assembleRelease + ./gradlew assembleRelease fi - name: Upload build artifact - if: ${{ github.event_name == 'pull_request' || (github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) || github.ref_type == 'tag' }} + if: ${{ github.event_name == 'pull_request' || (github.event_name != 'pull_request') || github.ref_type == 'tag' }} uses: actions/upload-artifact@v7 with: name: manager-gradle @@ -202,7 +207,7 @@ jobs: - name: Upload mappings uses: actions/upload-artifact@v7 - if: ${{ ( github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' )) || github.ref_type == 'tag' }} + if: ${{ ( github.event_name != 'pull_request') || github.ref_type == 'tag' }} with: name: "mappings" path: "manager/app/build/outputs/mapping/release/" @@ -242,6 +247,12 @@ jobs: name: ksud-aarch64-linux-android path: artifacts/ksud-aarch64-linux-android + - name: Download arm ksud + uses: actions/download-artifact@v8 + with: + name: ksud-armv7-linux-androideabi + path: artifacts/ksud-armv7-linux-androideabi + - name: Download x86_64 ksud uses: actions/download-artifact@v8 with: @@ -256,16 +267,20 @@ jobs: cp -f "$APK" manager/app/build/outputs/apk/release/ mkdir -p target/aarch64-linux-android/release + mkdir -p target/armv7-linux-androideabi/release mkdir -p target/x86_64-linux-android/release ARM64_KSUD=$(find artifacts/ksud-aarch64-linux-android -type f -name ksud | head -n 1) + ARM_KSUD=$(find artifacts/ksud-armv7-linux-androideabi -type f -name ksud | head -n 1) X86_64_KSUD=$(find artifacts/ksud-x86_64-linux-android -type f -name ksud | head -n 1) test -n "$ARM64_KSUD" + test -n "$ARM_KSUD" test -n "$X86_64_KSUD" cp -f "$ARM64_KSUD" target/aarch64-linux-android/release/ksud + cp -f "$ARM_KSUD" target/armv7-linux-androideabi/release/ksud cp -f "$X86_64_KSUD" target/x86_64-linux-android/release/ksud - name: Prepare signing inputs - if: ${{ github.event_name == 'pull_request' || (github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) || github.ref_type == 'tag' }} + if: ${{ github.event_name == 'pull_request' || (github.event_name != 'pull_request') || github.ref_type == 'tag' }} env: PR_KEYSTORE: ${{ needs.generate-key.outputs.keystore }} PR_KEYSTORE_PASSWORD: ${{ needs.generate-key.outputs.keystore_password }} @@ -291,12 +306,13 @@ jobs: fi - name: Repack and resign - if: ${{ github.event_name == 'pull_request' || (github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) || github.ref_type == 'tag' }} + if: ${{ github.event_name == 'pull_request' || (github.event_name != 'pull_request') || github.ref_type == 'tag' }} run: | python3 repack_apk.py repack \ -b release \ -t release \ -a arm64-v8a \ + -a armeabi-v7a \ -a x86_64 \ -K "$SIGN_KEYSTORE_FILE" \ -A "$SIGN_KEY_ALIAS" \ @@ -305,7 +321,7 @@ jobs: --strip - name: Upload build artifact - if: ${{ github.event_name == 'pull_request' || (github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) || github.ref_type == 'tag' }} + if: ${{ github.event_name == 'pull_request' || (github.event_name != 'pull_request') || github.ref_type == 'tag' }} uses: actions/upload-artifact@v7 with: name: manager @@ -322,11 +338,10 @@ jobs: - name: Upload to telegram if: github.event_name != 'pull_request' && steps.need_upload.outputs.UPLOAD == 'true' env: - CHAT_ID: ${{ secrets.CHAT_ID }} + CHAT_ID: ${{ vars.CHAT_ID }} BOT_TOKEN: ${{ secrets.BOT_TOKEN }} - MESSAGE_THREAD_ID: ${{ secrets.MESSAGE_THREAD_ID }} - COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - COMMIT_URL: ${{ github.event.head_commit.url }} + MESSAGE_THREAD_ID: ${{ vars.MESSAGE_THREAD_ID }} + GITHUB_EVENT: ${{ toJson(github.event) }} RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} TITLE: Manager BRANCH: ${{ github.ref_name }} diff --git a/build.sh b/build.sh new file mode 100644 index 000000000000..0103598351aa --- /dev/null +++ b/build.sh @@ -0,0 +1,241 @@ +#!/bin/bash +set -e + +# Intercept failures and interrupts to kill all background jobs +_cleanup() { + local exit_code=$? + trap - EXIT SIGINT SIGTERM + if [ $exit_code -ne 0 ]; then + echo -e "\n\033[31mBuild failed or interrupted, cleaning up background tasks...\033[0m" + local pids=$(jobs -p) + if [ -n "$pids" ]; then + kill $pids 2>/dev/null || true + fi + pkill -P $$ 2>/dev/null || true + fi + exit $exit_code +} +trap _cleanup EXIT SIGINT SIGTERM + +# Minimal: ./build.sh ksud +# Full: ./build.sh ksuinit lkm all +# Specific: ./build.sh ksuinit lkm + +if [ ! -d "out" ]; then + mkdir out + echo "*" > out/.gitignore + echo "\033[32mTips: copy this script to out/build.sh for clean workspace, run with bash out/build.sh\033[0m" +fi + +# Signing key for manager +if [ ! -f "out/sign.properties" ]; then + echo "Error: out/sign.properties not found, please fill it with your signing information" + cat "manager/sign.example.properties" > "out/sign.properties" + exit 1 +fi +. out/sign.properties +export ORG_GRADLE_PROJECT_KEYSTORE_FILE="$KEYSTORE_FILE" +export ORG_GRADLE_PROJECT_KEYSTORE_PASSWORD="$KEYSTORE_PASSWORD" +export ORG_GRADLE_PROJECT_KEY_ALIAS="$KEY_ALIAS" +export ORG_GRADLE_PROJECT_KEY_PASSWORD="$KEY_PASSWORD" + +# Find ndk +if [ -z "$ANDROID_NDK_HOME" ]; then + SDK_PATH="$ANDROID_HOME" + [ -z "$SDK_PATH" ] && [ -d "$HOME/Library/Android/sdk" ] && SDK_PATH="$HOME/Library/Android/sdk" + [ -z "$SDK_PATH" ] && [ -d "$HOME/Android/Sdk" ] && SDK_PATH="$HOME/Android/Sdk" + [ -z "$SDK_PATH" ] && echo "Error: ANDROID_HOME is not set, please set it to your Android SDK path" && exit 1 + + [ ! -d "$SDK_PATH/ndk" ] && echo "Error: NDK not found in $SDK_PATH" && exit 1 + LATEST_NDK="$(ls -1 "$SDK_PATH/ndk" | sort -V | tail -n 1)" + [ -z "$LATEST_NDK" ] && echo "Error: No NDK found in $SDK_PATH" && exit 1 + export ANDROID_NDK_HOME="$SDK_PATH/ndk/$LATEST_NDK" +fi + +TARGET="aarch64-linux-android" +source .github/scripts/setup-rust-build.sh "$TARGET" 26 +export PATH="$LLVM_BIN:$HOME/.cargo/bin:$PATH" + +DIR="$(pwd)" +DDK_RELEASE="$(grep -oP 'ddk_release.*?\K[0-9]+' .github/workflows/build-lkm.yml)" +VALID_KMIS="$(grep android .github/workflows/build-lkm.yml | sed 's/.*- android/android/g')" + +BUILD_KSUD=0 +BUILD_KSUINIT=0 +BUILD_LKM="" + +check_kmi() { + local kmi="$1" + for valid in $VALID_KMIS; do + if [[ "$kmi" == "$valid" ]]; then + return 0 + fi + done + return 1 +} + +build_lkm() { + local kmi="$1" + local logfile="out/${kmi}.log" + + { + echo "=== Building kernelsu.ko for KMI: $kmi (DDK: $DDK_RELEASE) ===" + + docker run --rm --privileged -v "$DIR:/workspace" -w /workspace \ + ghcr.io/ylarod/ddk-min:$kmi-$DDK_RELEASE /bin/bash -c " + set -e + git config --global --add safe.directory /workspace + cd kernel + CONFIG_KSU=m CC=clang make + cp kernelsu.ko ../out/${kmi}_kernelsu.ko + cp kernelsu.ko ../userspace/ksud/bin/aarch64/${kmi}_kernelsu.ko + echo 'Built: ../out/${kmi}_kernelsu.ko' + " + } > "$logfile" 2>&1 || { + echo "FAILED: build_lkm $kmi" >&2 + cat "$logfile" >&2 + return 1 + } +} + +while [[ $# -gt 0 ]]; do + case "$1" in + clean) + rm -rf out/*.apk out/*.ko dist/ + cd manager && ./gradlew clean + cd "$DIR" + DDK_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^ghcr.io/ylarod/ddk-min:") + if [ -n "$DDK_IMAGES" ]; then + echo "$DDK_IMAGES" | xargs docker rmi + fi + exit 0 + ;; + ksud) BUILD_KSUD=1; shift;; + ksuinit) BUILD_KSUINIT=1; shift;; + lkm) + if [[ -z "$2" ]]; then + echo "Error: lkm requires a KMI version or 'all'" + echo "Usage: $0 lkm " + echo "Valid KMI versions: $VALID_KMIS" + exit 1 + fi + if [[ "$2" == "all" ]]; then + BUILD_LKM="all" + else + if ! check_kmi "$2"; then + echo "Error: Invalid KMI version '$2'" + echo "Valid KMI versions: $VALID_KMIS" + exit 1 + fi + BUILD_LKM="$2" + fi + shift 2 + ;; + + -h|--help) + echo "Usage: $0 [ksuinit] [lkm ] [ksud]" + echo "Arguments:" + echo " clean Clean build artifacts and remove DDK Docker images" + echo " ksuinit Build ksuinit static binary" + echo " ksud Build ksud userspace daemon" + echo " lkm Build kernel module for specific KMI version or 'all'" + echo "" + echo "Valid KMI versions:" + for kmi in $VALID_KMIS; do + echo " $kmi" + done + exit 0 + ;; + esac +done + +declare -A PIDS +declare -A LOGS + +wait_for_jobs() { + local fail=0 + local name pid logfile + + for name in "$@"; do + pid="${PIDS[$name]}" + logfile="${LOGS[$name]}" + [[ -z "$pid" ]] && continue + + wait "$pid" || { + echo "FAILED: $name (PID $pid)" + [[ -n "$logfile" && -f "$logfile" ]] && cat "$logfile" + fail=1 + } + unset 'PIDS[$name]' + done + + if [[ "$fail" -ne 0 ]]; then + echo "Error: One or more parallel builds failed" + exit 1 + fi +} + +# ksuinit +if [[ "$BUILD_KSUINIT" == "1" ]]; then + echo "=== Building ksuinit ===" + ( + exec > out/ksuinit.log 2>&1 + rustup target add aarch64-unknown-linux-musl + export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER="$CLANG_PATH" + RUSTFLAGS="-C link-arg=-no-pie" cargo build --package ksuinit --target=aarch64-unknown-linux-musl --release --manifest-path ./userspace/ksuinit/Cargo.toml + cp target/aarch64-unknown-linux-musl/release/ksuinit userspace/ksud/bin/aarch64/ + ) & + PIDS[ksuinit]=$! + LOGS[ksuinit]="out/ksuinit.log" +fi + +# lkm +if [[ "$BUILD_LKM" == "all" ]]; then + ( + echo "=== Building all KMIs ===" + build_lkm_all() { + export -f build_lkm + export DIR DDK_RELEASE VALID_KMIS + echo "$VALID_KMIS" | xargs -P0 -I{} bash -c 'build_lkm "$@"' _ {} + } + build_lkm_all + ) & + PIDS[lkm]=$! +elif [[ -n "$BUILD_LKM" ]]; then + ( + echo "=== Building LKM: $BUILD_LKM ===" + build_lkm "$BUILD_LKM" + ) & + PIDS[lkm]=$! + LOGS[lkm]="out/${BUILD_LKM}.log" +fi + +# manager +( + echo "=== Building manager ===" + cd "$DIR/manager" + ./gradlew aRelease +) & +PIDS[manager]=$! + +# ksud +if [[ "$BUILD_KSUD" == "1" || "$BUILD_KSUINIT" == "1" || -n "$BUILD_LKM" ]]; then + wait_for_jobs ksuinit lkm + echo "=== Building ksud ===" + { + rustup update stable + rustup target add $TARGET + cargo build --target $TARGET --release --manifest-path ./userspace/ksud/Cargo.toml + } > out/ksud.log 2>&1 || { + echo "FAILED: ksud" + cat out/ksud.log + exit 1 + } +fi + +# repack +wait_for_jobs manager +echo "=== Repacking manager APK ===" +rm -f out/*.apk dist/*.apk +python3 repack_apk.py repack +cp -f dist/*.apk out/ diff --git a/js/README.md b/js/README.md index 5c2f3f2f9560..29d480cd99a1 100644 --- a/js/README.md +++ b/js/README.md @@ -158,7 +158,7 @@ img.src = "ksu://icon/" + packageName; Get information for a list of packages. -Returns an array of `PackagesInfo` objects. +Returns an array containing `PackagesInfo` objects for packages that were resolved. If a package is missing or inaccessible, the corresponding entry contains `packageName` and `error` instead. - `packages` `` The list of package names. @@ -175,8 +175,13 @@ An object contains: - `versionName` `` Version of the application. - `versionCode` `` Version code of the application. - `appLabel` `` Display name of the application. -- `isSystem` `` Whether the application is a system app. -- `uid` `` UID of the application. +- `isSystem` `` Whether the application is a system app. +- `uid` `` UID of the application. + +If a package could not be resolved, the returned object contains: + +- `packageName` `` The requested package name. +- `error` `` Reason the package information could not be returned. ### exit @@ -186,3 +191,153 @@ Exit the current WebUI activity. import { exit } from 'kernelsu'; exit(); ``` + +### io + +The exported `io` object provides file system operations with root access. It acts as a small facade over the WebUI file APIs, exposing Java-IO-style factory methods such as `io.File()`, `io.FileInputStream()`, `io.FileOutputStream()`, and `io.RandomAccessFile()`. + +```javascript +import { io } from 'kernelsu'; +``` + +#### io.File + +Represents a file or directory path. All operations execute via root shell. + +```javascript +const file = io.File('/data/adb/modules'); + +if (file.exists()) { + console.log(file.listFiles()); +} +``` + +##### Methods + +- `exists(): boolean` — Check if path exists +- `isFile(): boolean` — Check if path is a regular file +- `isDirectory(): boolean` — Check if path is a directory +- `canRead(): boolean` — Check read permission +- `canWrite(): boolean` — Check write permission +- `canExecute(): boolean` — Check execute permission +- `createNewFile(): boolean` — Create a new empty file +- `delete(): boolean` — Delete file or empty directory +- `deleteRecursive(): boolean` — Recursively delete directory +- `mkdir(): boolean` — Create directory +- `mkdirs(): boolean` — Create directory and all parent directories +- `renameTo(destPath: string): boolean` — Rename or move file +- `list(): string[]` — List filenames in directory +- `listFiles(): string[]` — List full paths of files in directory +- `length(): number` — File size in bytes +- `lastModified(): number` — Last modified timestamp (ms) +- `setLastModified(time: number): boolean` — Set last modified time +- `getAbsolutePath(): string` — Absolute path +- `getCanonicalPath(): string` — Canonical path (resolves symlinks) +- `getParent(): string | null` — Parent directory path +- `getPath(): string` — Path string +- `getName(): string` — File/directory name +- `isHidden(): boolean` — Check if hidden +- `isBlock(): boolean` — Check if block device +- `isCharacter(): boolean` — Check if character device +- `isSymlink(): boolean` — Check if symbolic link +- `createNewSymlink(target: string): boolean` — Create symbolic link +- `createNewLink(existing: string): boolean` — Create hard link +- `clear(): boolean` — Truncate file to zero length +- `setReadOnly(): boolean` — Set read-only +- `setReadable(readable: boolean, ownerOnly: boolean): boolean` — Set read permission +- `setWritable(writable: boolean, ownerOnly: boolean): boolean` — Set write permission +- `setExecutable(executable: boolean, ownerOnly: boolean): boolean` — Set execute permission +- `getFreeSpace(): number` — Free space on partition +- `getTotalSpace(): number` — Total space on partition +- `getUsableSpace(): number` — Usable space on partition +- `newInputStream(): string` — Open input stream, returns stream ID +- `newOutputStream(append?: boolean): string` — Open output stream, returns stream ID + +#### io.FileInputStream + +Read file contents as base64-encoded chunks. + +```javascript +const reader = io.FileInputStream(); +const id = reader.open('/data/adb/ksu.log'); + +let chunk; +while ((chunk = reader.read(id)) !== '') { + console.log(atob(chunk)); +} +reader.close(id); +``` + +##### Methods + +- `open(path: string): string` — Open file for reading, returns stream ID +- `read(id: string): string` — Read chunk (up to 8KB), returns base64 string (empty on EOF) +- `read(id: string, maxBytes: number): string` — Read up to maxBytes, returns base64 string +- `available(id: string): number` — Estimated bytes available +- `close(id: string): boolean` — Close stream + +#### io.FileOutputStream + +Write file contents from base64-encoded data. + +```javascript +const writer = io.FileOutputStream(); +const id = writer.open('/data/adb/output.txt'); + +writer.write(id, btoa('Hello, World!')); +writer.close(id); +``` + +##### Methods + +- `open(path: string, append?: boolean): string` — Open file for writing, returns stream ID +- `write(id: string, base64: string): boolean` — Write base64 data. For large sequential writes, prefer large chunks (for example 1-2 MiB) to reduce WebView bridge overhead. +- `writeByte(id: string, b: number): boolean` — Write single byte +- `flush(id: string): boolean` — Flush buffer +- `close(id: string): boolean` — Close stream + +#### io.RandomAccessFile + +Random access file I/O with seek support. Uses `dd` under the hood, so each operation has overhead. Prefer `FileInputStream`/`FileOutputStream` for sequential access. + +```javascript +const raf = io.RandomAccessFile(); +const id = raf.open('/data/adb/data.bin', 'rw'); + +raf.seek(id, 1024); +raf.writeInt(id, 42); +raf.seek(id, 1024); +console.log(raf.readInt(id)); + +raf.close(id); +``` + +##### Methods + +- `open(path: string, mode: string): string` — Open file with mode (`"r"`, `"rw"`, etc.), returns file ID +- `read(id: string): number` — Read single byte (0-255, or -1 on EOF) +- `readBytes(id: string, len: number): string` — Read bytes, returns base64 string +- `readBoolean(id: string): boolean` — Read boolean +- `readByte(id: string): number` — Read signed byte +- `readInt(id: string): number` — Read 32-bit integer +- `readLong(id: string): number` — Read 64-bit integer +- `readShort(id: string): number` — Read 16-bit short +- `readFloat(id: string): number` — Read 32-bit float +- `readDouble(id: string): number` — Read 64-bit double +- `readUTF(id: string): string` — Read UTF string +- `readLine(id: string): string | null` — Read line +- `write(id: string, b: number): void` — Write single byte +- `writeBase64(id: string, data: string): void` — Write base64 data +- `writeBoolean(id: string, v: boolean): void` — Write boolean +- `writeByte(id: string, v: number): void` — Write byte +- `writeInt(id: string, v: number): void` — Write 32-bit integer +- `writeLong(id: string, v: number): void` — Write 64-bit integer +- `writeShort(id: string, v: number): void` — Write 16-bit short +- `writeFloat(id: string, v: number): void` — Write 32-bit float +- `writeDouble(id: string, v: number): void` — Write 64-bit double +- `writeUTF(id: string, str: string): void` — Write UTF string +- `seek(id: string, pos: number): boolean` — Set file pointer position +- `getFilePointer(id: string): number` — Get current file pointer position +- `length(id: string): number` — Get file length +- `setLength(id: string, newLength: number): boolean` — Truncate or extend file +- `close(id: string): boolean` — Close file diff --git a/js/index.d.ts b/js/index.d.ts index 3bb965bda4c2..3f735fcb09b3 100644 --- a/js/index.d.ts +++ b/js/index.d.ts @@ -46,16 +46,118 @@ interface PackagesInfo { versionName: string; versionCode: number; appLabel: string; - isSystem: boolean; - uid: number; + isSystem: boolean | null; + uid: number | null; +} + +interface PackageInfoError { + packageName: string; + error: string; } declare function listPackages(type: string): string[]; -declare function getPackagesInfo(packages: string[]): PackagesInfo[]; +declare function getPackagesInfo(packages: string[]): Array; declare function exit(); +interface FileInstance { + exists(): boolean; + isFile(): boolean; + isDirectory(): boolean; + canRead(): boolean; + canWrite(): boolean; + canExecute(): boolean; + createNewFile(): boolean; + delete(): boolean; + deleteRecursive(): boolean; + mkdir(): boolean; + mkdirs(): boolean; + renameTo(destPath: string): boolean; + list(): string[]; + listFiles(): string[]; + length(): number; + lastModified(): number; + setLastModified(time: number): boolean; + getAbsolutePath(): string; + getCanonicalPath(): string; + getParent(): string | null; + getPath(): string; + getName(): string; + isHidden(): boolean; + isBlock(): boolean; + isCharacter(): boolean; + isSymlink(): boolean; + createNewSymlink(target: string): boolean; + createNewLink(existing: string): boolean; + clear(): boolean; + setReadOnly(): boolean; + setReadable(readable: boolean, ownerOnly: boolean): boolean; + setWritable(writable: boolean, ownerOnly: boolean): boolean; + setExecutable(executable: boolean, ownerOnly: boolean): boolean; + getFreeSpace(): number; + getTotalSpace(): number; + getUsableSpace(): number; + newInputStream(): string; + newOutputStream(append?: boolean): string; + toString(): string; +} + +interface FileInputStreamInstance { + open(path: string): string; + read(id: string): string; + read(id: string, maxBytes: number): string; + available(id: string): number; + close(id: string): boolean; +} + +interface FileOutputStreamInstance { + open(path: string, append?: boolean): string; + write(id: string, base64: string): boolean; + writeByte(id: string, b: number): boolean; + flush(id: string): boolean; + close(id: string): boolean; +} + +interface RandomAccessFileInstance { + open(path: string, mode: string): string; + read(id: string): number; + readBytes(id: string, len: number): string; + readBoolean(id: string): boolean; + readByte(id: string): number; + readInt(id: string): number; + readLong(id: string): number; + readShort(id: string): number; + readFloat(id: string): number; + readDouble(id: string): number; + readUTF(id: string): string; + readLine(id: string): string | null; + write(id: string, b: number): void; + writeBase64(id: string, data: string): void; + writeBoolean(id: string, v: boolean): void; + writeByte(id: string, v: number): void; + writeInt(id: string, v: number): void; + writeLong(id: string, v: number): void; + writeShort(id: string, v: number): void; + writeFloat(id: string, v: number): void; + writeDouble(id: string, v: number): void; + writeUTF(id: string, str: string): void; + seek(id: string, pos: number): boolean; + getFilePointer(id: string): number; + length(id: string): number; + setLength(id: string, newLength: number): boolean; + close(id: string): boolean; +} + +interface KsuIO { + File(path: string): FileInstance; + FileInputStream(): FileInputStreamInstance; + FileOutputStream(): FileOutputStreamInstance; + RandomAccessFile(): RandomAccessFileInstance; +} + +declare const io: KsuIO; + export { exec, spawn, @@ -66,4 +168,5 @@ export { listPackages, getPackagesInfo, exit, + io, } diff --git a/js/index.js b/js/index.js index d0d700a1201f..1ac74a5d9cb8 100644 --- a/js/index.js +++ b/js/index.js @@ -74,6 +74,7 @@ function Stdio() { } else if (!(args instanceof Array)) { // allow for (command, options) signature options = args; + args = []; } if (typeof options === "undefined") { @@ -144,3 +145,63 @@ export function getPackagesInfo(packages) { export function exit() { ksu.exit(); } + +export const io = { + File(path) { + return ksu.io().File(path); + }, + + FileInputStream() { + const impl = ksu.io().FileInputStream(); + return { + open(path) { return impl.open(path); }, + read(id, maxBytes) { return impl.read(id, maxBytes); }, + available(id) { return impl.available(id); }, + close(id) { return impl.close(id); }, + }; + }, + + FileOutputStream() { + const impl = ksu.io().FileOutputStream(); + return { + open(path, append) { return impl.open(path, append); }, + write(id, data) { return impl.write(id, data); }, + writeByte(id, b) { return impl.writeByte(id, b); }, + flush(id) { return impl.flush(id); }, + close(id) { return impl.close(id); }, + }; + }, + + RandomAccessFile() { + const impl = ksu.io().RandomAccessFile(); + return { + open(path, mode) { return impl.open(path, mode); }, + read(id) { return impl.read(id); }, + readBytes(id, len) { return impl.readBytes(id, len); }, + readBoolean(id) { return impl.readBoolean(id); }, + readByte(id) { return impl.readByte(id); }, + readInt(id) { return impl.readInt(id); }, + readLong(id) { return impl.readLong(id); }, + readShort(id) { return impl.readShort(id); }, + readFloat(id) { return impl.readFloat(id); }, + readDouble(id) { return impl.readDouble(id); }, + readUTF(id) { return impl.readUTF(id); }, + readLine(id) { return impl.readLine(id); }, + write(id, b) { impl.write(id, b); }, + writeBase64(id, data) { impl.writeBase64(id, data); }, + writeBoolean(id, v) { impl.writeBoolean(id, v); }, + writeByte(id, v) { impl.writeByte(id, v); }, + writeInt(id, v) { impl.writeInt(id, v); }, + writeLong(id, v) { impl.writeLong(id, v); }, + writeShort(id, v) { impl.writeShort(id, v); }, + writeFloat(id, v) { impl.writeFloat(id, v); }, + writeDouble(id, v) { impl.writeDouble(id, v); }, + writeUTF(id, str) { impl.writeUTF(id, str); }, + seek(id, pos) { return impl.seek(id, pos); }, + getFilePointer(id) { return impl.getFilePointer(id); }, + length(id) { return impl.length(id); }, + setLength(id, newLength) { return impl.setLength(id, newLength); }, + close(id) { return impl.close(id); }, + }; + }, +}; diff --git a/kernel/Kbuild b/kernel/Kbuild index d4a07c97aa05..b7f68220a036 100644 --- a/kernel/Kbuild +++ b/kernel/Kbuild @@ -61,6 +61,8 @@ ccflags-y += -DCONFIG_KSU_DEBUG=1 endif endif +kernelsu-objs += extras.o + ccflags-y += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include ccflags-y += -I$(objtree)/security/selinux -include $(srctree)/include/uapi/asm-generic/errno.h @@ -115,11 +117,11 @@ $(info -- KSU_NEW_DCACHE_FLUSH: $(KSU_NEW_DCACHE_FLUSH)) ifndef KSU_EXPECTED_SIZE -KSU_EXPECTED_SIZE := 0x033b +KSU_EXPECTED_SIZE := 0x375 endif ifndef KSU_EXPECTED_HASH -KSU_EXPECTED_HASH := c371061b19d8c7d7d6133c6a9bafe198fa944e50c1b31c9d8daa8d7f1fc2d2d6 +KSU_EXPECTED_HASH := 484fcba6e6c43b1fb09700633bf2fb4758f13cb0b2f4457b80d075084b26c588 endif ifdef KSU_MANAGER_PACKAGE @@ -146,6 +148,6 @@ endif ccflags-y += -DKSU_NEW_DCACHE_FLUSH=$(KSU_NEW_DCACHE_FLUSH) ccflags-y += -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat -Wno-missing-prototypes -ccflags-y += -Wno-declaration-after-statement -Wno-unused-function +ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-unused-variable # Keep a new line here!! Because someone may append config diff --git a/kernel/Makefile b/kernel/Makefile index 068476e00ce0..9ffda5673506 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -7,7 +7,7 @@ $(info -- MDIR: $(MDIR)) .PHONY: all compdb clean format check-format all: check_symbol - make -C $(KDIR) M=$(MDIR) modules -j$(shell nproc) + CONFIG_KSU=m make -C $(KDIR) M=$(MDIR) modules -j$(shell nproc) ./check_symbol kernelsu.ko $(KDIR)/vmlinux compdb: diff --git a/kernel/extras.c b/kernel/extras.c new file mode 100644 index 000000000000..a7cac49aca7c --- /dev/null +++ b/kernel/extras.c @@ -0,0 +1,212 @@ +#include +#include +#include + +#include "policy/feature.h" +#include "include/klog.h" +#include "runtime/ksud_boot.h" +#include "infra/seccomp_cache.h" + +// sorry for the ifdef hell +// but im too lazy to fragment this out. +// theres only one feature so far anyway +// - xx, 20251019 + +static u32 su_sid = 0; +static u32 priv_app_sid = 0; + +// init as disabled by default +static atomic_t disable_spoof = ATOMIC_INIT(1); + +void ksu_avc_spoof_enable(); +void ksu_avc_spoof_disable(); + +static bool ksu_avc_spoof_enabled = true; +static bool boot_completed = false; + +static int avc_spoof_feature_get(u64 *value) +{ + *value = ksu_avc_spoof_enabled ? 1 : 0; + return 0; +} + +static int avc_spoof_feature_set(u64 value) +{ + bool enable = value != 0; + + if (enable == ksu_avc_spoof_enabled) { + pr_info("avc_spoof: no need to change\n"); + return 0; + } + + ksu_avc_spoof_enabled = enable; + + if (boot_completed) { + if (enable) { + ksu_avc_spoof_enable(); + } else { + ksu_avc_spoof_disable(); + } + } + + pr_info("avc_spoof: set to %d\n", enable); + + return 0; +} + +static const struct ksu_feature_handler avc_spoof_handler = { + .feature_id = KSU_FEATURE_AVC_SPOOF, + .name = "avc_spoof", + .get_handler = avc_spoof_feature_get, + .set_handler = avc_spoof_feature_set, +}; + +static int get_sid() +{ + // dont load at all if we cant get sids + int err = security_secctx_to_secid("u:r:su:s0", strlen("u:r:su:s0"), &su_sid); + if (err) { + pr_info("avc_spoof/get_sid: su_sid not found!\n"); + return -1; + } + pr_info("avc_spoof/get_sid: su_sid: %u\n", su_sid); + + err = security_secctx_to_secid("u:r:priv_app:s0:c512,c768", strlen("u:r:priv_app:s0:c512,c768"), &priv_app_sid); + if (err) { + pr_info("avc_spoof/get_sid: priv_app_sid not found!\n"); + return -1; + } + pr_info("avc_spoof/get_sid: priv_app_sid: %u\n", priv_app_sid); + return 0; +} + +int ksu_handle_slow_avc_audit(u32 *tsid) +{ + if (atomic_read(&disable_spoof)) + return 0; + + // if tsid is su, we just replace it + // unsure if its enough, but this is how it is aye? + if (*tsid == su_sid) { + pr_info("avc_spoof/slow_avc_audit: replacing su_sid: %u with priv_app_sid: %u\n", su_sid, priv_app_sid); + *tsid = priv_app_sid; + } + + return 0; +} + +#ifdef CONFIG_KPROBES +#include +#include +#include "arch.h" +static struct kprobe *slow_avc_audit_kp; +// .symbol_name = "slow_avc_audit", +// .pre_handler = slow_avc_audit_pre_handler, +static int slow_avc_audit_pre_handler(struct kprobe *p, struct pt_regs *regs) +{ + if (atomic_read(&disable_spoof)) + return 0; + + /* + * for < 4.17 int slow_avc_audit(u32 ssid, u32 tsid + * for >= 4.17 int slow_avc_audit(struct selinux_state *state, u32 ssid, u32 tsid + * for >= 6.4 int slow_avc_audit(u32 ssid, u32 tsid + * not to mention theres also DKSU_HAS_SELINUX_STATE + * since its hard to make sure this selinux state thing + * cross crossing with 4.17 ~ 6.4's where slow_avc_audit + * changes abi (tsid in arg2 vs arg3) + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) + u32 *tsid = (u32 *)&PT_REGS_PARM2(regs); + ksu_handle_slow_avc_audit(tsid); +#else + u32 *tsid = (u32 *)&PT_REGS_PARM3(regs); + ksu_handle_slow_avc_audit(tsid); +#endif + + return 0; +} + +// copied from upstream +static struct kprobe *init_kprobe(const char *name, + kprobe_pre_handler_t handler) +{ + struct kprobe *kp = kzalloc(sizeof(struct kprobe), GFP_KERNEL); + if (!kp) + return NULL; + kp->symbol_name = name; + kp->pre_handler = handler; + + int ret = register_kprobe(kp); + pr_info("sucompat: register_%s kprobe: %d\n", name, ret); + if (ret) { + kfree(kp); + return NULL; + } + + return kp; +} +static void destroy_kprobe(struct kprobe **kp_ptr) +{ + struct kprobe *kp = *kp_ptr; + if (!kp) + return; + unregister_kprobe(kp); + synchronize_rcu(); + kfree(kp); + *kp_ptr = NULL; +} +#endif // CONFIG_KPROBES + +void ksu_avc_spoof_disable(void) +{ +#ifdef CONFIG_KPROBES + pr_info("avc_spoof/exit: unregister slow_avc_audit kprobe!\n"); + destroy_kprobe(&slow_avc_audit_kp); +#endif + atomic_set(&disable_spoof, 1); + pr_info("avc_spoof/exit: slow_avc_audit spoofing disabled!\n"); +} + +void ksu_avc_spoof_enable(void) +{ + int ret = get_sid(); + if (ret) { + pr_info("avc_spoof/init: sid grab fail!\n"); + return; + } + +#ifdef CONFIG_KPROBES + pr_info("avc_spoof/init: register slow_avc_audit kprobe!\n"); + slow_avc_audit_kp = init_kprobe("slow_avc_audit", slow_avc_audit_pre_handler); +#endif + // once we get the sids, we can now enable the hook handler + atomic_set(&disable_spoof, 0); + + pr_info("avc_spoof/init: slow_avc_audit spoofing enabled!\n"); +} + +void ksu_avc_spoof_late_init() +{ + boot_completed = true; + + if (ksu_avc_spoof_enabled) { + ksu_avc_spoof_enable(); + } +} + +void __init ksu_avc_spoof_init() +{ + if (ksu_register_feature_handler(&avc_spoof_handler)) { + pr_err("Failed to register avc spoof feature handler\n"); + } +} + +void __exit ksu_avc_spoof_exit() +{ + if (ksu_avc_spoof_enabled) { + ksu_avc_spoof_disable(); + } + ksu_unregister_feature_handler(KSU_FEATURE_AVC_SPOOF); +} diff --git a/kernel/feature/sucompat.c b/kernel/feature/sucompat.c index ca4bb84ef0f9..40181a5b69dc 100644 --- a/kernel/feature/sucompat.c +++ b/kernel/feature/sucompat.c @@ -25,6 +25,8 @@ #define SU_PATH "/system/bin/su" #define SH_PATH "/system/bin/sh" +extern void write_sulog(uint8_t sym); + bool ksu_su_compat_enabled __read_mostly = true; static int su_compat_feature_get(u64 *value) @@ -84,6 +86,7 @@ int ksu_handle_faccessat(int *dfd, const char __user **filename_user, int *mode, strncpy_from_user_nofault(path, *filename_user, sizeof(path)); if (unlikely(!memcmp(path, su, sizeof(su)))) { + write_sulog('a'); pr_info("faccessat su->sh!\n"); *filename_user = sh_user_path(); } @@ -109,6 +112,7 @@ int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags) strncpy_from_user_nofault(path, *filename_user, sizeof(path)); if (unlikely(!memcmp(path, su, sizeof(su)))) { + write_sulog('s'); pr_info("newfstatat su->sh!\n"); *filename_user = sh_user_path(); } @@ -146,6 +150,7 @@ long ksu_handle_execve_sucompat(const char __user **filename_user, int orig_nr, if (likely(memcmp(path, su, sizeof(su)))) goto do_orig_execve; + write_sulog('x'); pr_info("sys_execve su found\n"); pending_sucompat = ksu_sulog_capture_sucompat(*filename_user, argv_user, GFP_KERNEL); *filename_user = ksud_user_path(); diff --git a/kernel/hook/syscall_hook_manager.c b/kernel/hook/syscall_hook_manager.c index 26ca600dfb7e..d46f1ceb269f 100644 --- a/kernel/hook/syscall_hook_manager.c +++ b/kernel/hook/syscall_hook_manager.c @@ -151,6 +151,7 @@ void __init ksu_syscall_hook_manager_init(void) ksu_setuid_hook_init(); ksu_sucompat_init(); + ksu_avc_spoof_init(); } void __exit ksu_syscall_hook_manager_exit(void) @@ -176,4 +177,5 @@ void __exit ksu_syscall_hook_manager_exit(void) ksu_sucompat_exit(); ksu_setuid_hook_exit(); + ksu_avc_spoof_exit(); } diff --git a/kernel/hook/syscall_hook_manager.h b/kernel/hook/syscall_hook_manager.h index 47fb05594129..af3ae2cf8d9b 100644 --- a/kernel/hook/syscall_hook_manager.h +++ b/kernel/hook/syscall_hook_manager.h @@ -7,4 +7,7 @@ void ksu_syscall_hook_manager_init(void); void ksu_syscall_hook_manager_exit(void); +void ksu_avc_spoof_init(void); +void ksu_avc_spoof_exit(void); + #endif diff --git a/kernel/runtime/boot_event.c b/kernel/runtime/boot_event.c index b0fd8b3cd1a9..5c6cf105e0e8 100644 --- a/kernel/runtime/boot_event.c +++ b/kernel/runtime/boot_event.c @@ -60,9 +60,11 @@ void on_module_mounted(void) ksu_module_mounted = true; } +extern void ksu_avc_spoof_late_init(); void on_boot_completed(void) { ksu_boot_completed = true; pr_info("on_boot_completed!\n"); track_throne(true); + ksu_avc_spoof_late_init(); } diff --git a/kernel/setup.sh b/kernel/setup.sh index e688dbaf3ae5..2a4f98938b55 100755 --- a/kernel/setup.sh +++ b/kernel/setup.sh @@ -39,7 +39,7 @@ perform_cleanup() { # Sets up or update KernelSU environment setup_kernelsu() { echo "[+] Setting up KernelSU..." - test -d "$GKI_ROOT/KernelSU" || git clone https://github.com/tiann/KernelSU && echo "[+] Repository cloned." + test -d "$GKI_ROOT/KernelSU" || git clone https://github.com/KOWX712/KernelSU && echo "[+] Repository cloned." cd "$GKI_ROOT/KernelSU" git stash && echo "[-] Stashed current changes." if [ "$(git status | grep -Po 'v\d+(\.\d+)*' | head -n1)" ]; then diff --git a/kernel/supercall/dispatch.c b/kernel/supercall/dispatch.c index 1990b5d146b6..680816f71137 100644 --- a/kernel/supercall/dispatch.c +++ b/kernel/supercall/dispatch.c @@ -22,6 +22,8 @@ #include "sulog/fd.h" #include "supercall/supercall.h" +extern void write_sulog(uint8_t sym); + static int do_grant_root(void __user *arg) { int ret; @@ -29,6 +31,7 @@ static int do_grant_root(void __user *arg) __u32 audit_euid = current_euid().val; // we already check uid above on allowed_for_su() + write_sulog('i'); // log ioctl escalation pr_info("allow root for: %d\n", audit_uid); ret = escape_with_root_profile(); @@ -37,6 +40,9 @@ static int do_grant_root(void __user *arg) return ret; } +uint32_t ksuver_override = 0; +uint32_t ksuflags_override = 0; + static int do_get_info(void __user *arg) { struct ksu_get_info_cmd cmd = { .version = KERNEL_SU_VERSION, .flags = 0 }; @@ -56,6 +62,12 @@ static int do_get_info(void __user *arg) #endif cmd.features = KSU_FEATURE_MAX; + if (ksuver_override) + cmd.version = ksuver_override; + + if (ksuflags_override) + cmd.flags = ksuflags_override; + if (copy_to_user(arg, &cmd, sizeof(cmd))) { pr_err("get_version: copy_to_user failed\n"); return -EFAULT; @@ -594,6 +606,59 @@ static int add_try_umount(void __user *arg) return 0; } + // this way userspace can deduce the memory it has to prepare. + case KSU_UMOUNT_GETSIZE: { + // check for pointer first + if (!cmd.arg) + return -EFAULT; + + size_t total_size = 0; // size of list in bytes + + down_read(&mount_list_lock); + list_for_each_entry(entry, &mount_list, list) { + total_size = total_size + strlen(entry->umountable) + 1; // + 1 for \0 + } + up_read(&mount_list_lock); + + // debug + // pr_info("cmd_add_try_umount: total_size: %zu\n", total_size); + + if (copy_to_user((size_t __user *)cmd.arg, &total_size, sizeof(total_size))) + return -EFAULT; + + return 0; + } + + // WARNING! this is straight up pointerwalking. + // this way we dont need to redefine the ioctl defs. + // this also avoids us needing to kmalloc + // userspace have to send pointer to memory (malloc/alloca) or pointer to a VLA. + case KSU_UMOUNT_GETLIST: { + // check for pointer first + if (!cmd.arg) + return -EFAULT; + + char *user_buf = (char *)cmd.arg; + + down_read(&mount_list_lock); + list_for_each_entry(entry, &mount_list, list) { + + //debug + //pr_info("cmd_add_try_umount: entry: %s\n", entry->umountable); + + if (copy_to_user((char __user *)user_buf, entry->umountable, strlen(entry->umountable) + 1 )) { + up_read(&mount_list_lock); + return -EFAULT; + } + + // walk it! +1 for null terminator + user_buf = user_buf + strlen(entry->umountable) + 1; + } + up_read(&mount_list_lock); + + return 0; + } + default: { pr_err("cmd_add_try_umount: invalid operation %u\n", cmd.mode); return -EINVAL; diff --git a/kernel/supercall/supercall.c b/kernel/supercall/supercall.c index ba3ad1c41c47..cf03ce82bc84 100644 --- a/kernel/supercall/supercall.c +++ b/kernel/supercall/supercall.c @@ -11,11 +11,17 @@ #include #include +#include // utsname() and uts_sem + #include "uapi/supercall.h" #include "supercall/internal.h" #include "arch.h" #include "klog.h" // IWYU pragma: keep +#include "manager/manager_identity.h" +#include "supercall/supercall.h" +#include "../tiny_sulog.c" + struct ksu_install_fd_tw { struct callback_head cb; int __user *outp; @@ -80,15 +86,25 @@ static void ksu_install_fd_tw_func(struct callback_head *cb) kfree(tw); } -static int reboot_handler_pre(struct kprobe *p, struct pt_regs *regs) +extern uint32_t ksuver_override; +extern uint32_t ksuflags_override; + +// downstream: make sure to pass arg as reference, this can allow us to extend things. +static int ksu_handle_sys_reboot(int magic1, int magic2, unsigned int cmd, void __user **arg) { - struct pt_regs *real_regs = PT_REAL_REGS(regs); - int magic1 = (int)PT_REGS_PARM1(real_regs); - int magic2 = (int)PT_REGS_PARM2(real_regs); - if (magic1 == KSU_INSTALL_MAGIC1 && magic2 == KSU_INSTALL_MAGIC2) { + if (magic1 != KSU_INSTALL_MAGIC1) + return 0; + + pr_info("sys_reboot: intercepted call! magic: 0x%x id: %d\n", magic1, magic2); + + // arg4 = (unsigned long)PT_REGS_SYSCALL_PARM4(real_regs); + // downstream: dereference arg as arg4 so we can be inline to upstream + void __user *arg4 = (void __user *)*arg; + + // Check if this is a request to install KSU fd + if (magic2 == KSU_INSTALL_MAGIC2) { struct ksu_install_fd_tw *tw; - unsigned long arg4 = (unsigned long)PT_REGS_SYSCALL_PARM4(real_regs); tw = kzalloc(sizeof(*tw), GFP_ATOMIC); if (!tw) @@ -103,9 +119,155 @@ static int reboot_handler_pre(struct kprobe *p, struct pt_regs *regs) } } + // downstream: extensions go here! + + // extensions + u64 reply = (u64)*arg; + + if (magic2 == CHANGE_MANAGER_UID) { + // only root is allowed for this command + if (current_uid().val != 0) + return 0; + + pr_info("sys_reboot: ksu_set_manager_appid to: %d\n", cmd); + ksu_set_manager_appid(cmd); + + if (cmd == ksu_get_manager_appid()) { + if (copy_to_user((void __user *)*arg, &reply, sizeof(reply))) + pr_info("sys_reboot: reply fail\n"); + } + + return 0; + } + + if (magic2 == GET_SULOG_DUMP_V2) { + // only root is allowed for this command + if (current_uid().val != 0) + return 0; + + int ret = send_sulog_dump(*arg); + if (ret) + return 0; + + if (copy_to_user((void __user *)*arg, &reply, sizeof(reply) )) + return 0; + } + + if (magic2 == CHANGE_KSUVER) { + // only root is allowed for this command + if (current_uid().val != 0) + return 0; + + pr_info("sys_reboot: ksu_change_ksuver to: %d\n", cmd); + ksuver_override = cmd; + + if (copy_to_user((void __user *)*arg, &reply, sizeof(reply) )) + return 0; + } + + // WARNING!!! triple ptr zone! *** + if (magic2 == CHANGE_SPOOF_UNAME) { + // only root is allowed for this command + if (current_uid().val != 0) + return 0; + + char release_buf[65]; + char version_buf[65]; + static char original_release_buf[65] = {0}; + static char original_version_buf[65] = {0}; + + // basically void * void __user * void __user *arg + void ***ppptr = (uintptr_t)arg; + + // user pointer storage + // init this as zero this still works on 32-on-64 LE + uint64_t u_pptr = 0; + uint64_t u_ptr = 0; + + pr_info("sys_reboot: ppptr: 0x%lx \n", (uintptr_t)ppptr); + + // arg here is ***, dereference to pull out ** + if (copy_from_user(&u_pptr, (void __user *)*ppptr, sizeof(u_pptr))) + return 0; + + pr_info("sys_reboot: u_pptr: 0x%lx \n", (uintptr_t)u_pptr); + + // now we got the __user ** + // we cannot dereference this as this is __user + // we just do another copy_from_user to get it + if (copy_from_user(&u_ptr, (void __user *)u_pptr, sizeof(u_ptr))) + return 0; + + pr_info("sys_reboot: u_ptr: 0x%lx \n", (uintptr_t)u_ptr); + + // for release + if (strncpy_from_user(release_buf, (char __user *)u_ptr, sizeof(release_buf)) < 0) + return 0; + release_buf[sizeof(release_buf) - 1] = '\0'; + + // for version + if (strncpy_from_user(version_buf, (char __user *)(u_ptr + strlen(release_buf) + 1), sizeof(version_buf)) < 0) + return 0; + version_buf[sizeof(version_buf) - 1] = '\0'; + + if (original_release_buf[0] == '\0') { + struct new_utsname *u_curr = utsname(); + // we save current version as the original before modifying + strncpy(original_release_buf, u_curr->release, sizeof(original_release_buf)); + strncpy(original_version_buf, u_curr->version, sizeof(original_version_buf)); + pr_info("sys_reboot: original uname saved: %s %s\n", original_release_buf, original_version_buf); + } + + // so user can reset + if (!strcmp(release_buf, "default")) { + memcpy(release_buf, original_release_buf, sizeof(release_buf)); + } + + if (!strcmp(version_buf, "default")) { + memcpy(version_buf, original_version_buf, sizeof(version_buf)); + } + + pr_info("sys_reboot: spoofing kernel to: %s - %s\n", release_buf, version_buf); + + struct new_utsname *u = utsname(); + + down_write(&uts_sem); + strncpy(u->release, release_buf, sizeof(u->release)); + strncpy(u->version, version_buf, sizeof(u->version)); + up_write(&uts_sem); + + // we write our confirmation on ** + if (copy_to_user((void __user *)*arg, &reply, sizeof(reply))) + return 0; + } + + if (magic2 == CHANGE_KSUFLAGS) { + // only root is allowed for this command + if (current_uid().val != 0) + return 0; + + pr_info("sys_reboot: ksu_change_ksuflags to: %d\n", cmd); + ksuflags_override = cmd; + + if (copy_to_user((void __user *)*arg, &reply, sizeof(reply) )) + return 0; + } + return 0; } +static int reboot_handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + struct pt_regs *real_regs = PT_REAL_REGS(regs); + int magic1 = (int)PT_REGS_PARM1(real_regs); + int magic2 = (int)PT_REGS_PARM2(real_regs); + int cmd = (int)PT_REGS_PARM3(real_regs); + void __user **arg = (void __user **)&PT_REGS_SYSCALL_PARM4(real_regs); + + return ksu_handle_sys_reboot(magic1, magic2, cmd, arg); + +} + static struct kprobe reboot_kp = { .symbol_name = REBOOT_SYMBOL, .pre_handler = reboot_handler_pre, @@ -117,6 +279,8 @@ void __init ksu_supercalls_init(void) ksu_supercall_dump_commands(); + sulog_init_heap(); // grab heap memory for sulog + rc = register_kprobe(&reboot_kp); if (rc) { pr_err("reboot kprobe failed: %d\n", rc); @@ -127,6 +291,11 @@ void __init ksu_supercalls_init(void) void __exit ksu_supercalls_exit(void) { + if (sulog_buf_ptr) { + memzero_explicit(sulog_buf_ptr, SULOG_BUFSIZ); + kfree(sulog_buf_ptr); + } + unregister_kprobe(&reboot_kp); ksu_supercall_cleanup_state(); } diff --git a/kernel/supercall/supercall.h b/kernel/supercall/supercall.h index fbedd11f8542..b74f43005c1b 100644 --- a/kernel/supercall/supercall.h +++ b/kernel/supercall/supercall.h @@ -21,4 +21,15 @@ int ksu_install_fd(void); void ksu_supercalls_init(void); void ksu_supercalls_exit(void); + +// extensions +#define CHANGE_MANAGER_UID 10006 +#define KSU_UMOUNT_GETSIZE 107 // get list size // shit is u8 we cant fit 10k+ on it +#define KSU_UMOUNT_GETLIST 108 // get list +#define GET_SULOG_DUMP 10009 // sulogv1 placeholder +#define GET_SULOG_DUMP_V2 10010 // get sulog dump, max, last 250 escalations +#define CHANGE_KSUVER 10011 // change ksu version +#define CHANGE_SPOOF_UNAME 10012 // spoof uname +#define CHANGE_KSUFLAGS 10013 // change ksuflags, do the bit calc on your own, 0 + 1 + 2 + 4 + 8 blah + #endif // __KSU_H_SUPERCALL diff --git a/kernel/tiny_sulog.c b/kernel/tiny_sulog.c new file mode 100644 index 000000000000..f8c0184c0b2c --- /dev/null +++ b/kernel/tiny_sulog.c @@ -0,0 +1,88 @@ +// half assed ringbuffer +// 8 bytes +struct sulog_entry { + uint32_t s_time; // uptime in seconds + uint32_t data; // uint8_t[0,1,2] = uid, basically uint24_t, uint8_t[3] = symbol +} __attribute__((packed)); + +#define SULOG_ENTRY_MAX 250 +#define SULOG_BUFSIZ SULOG_ENTRY_MAX * (sizeof (struct sulog_entry)) + +static void *sulog_buf_ptr = NULL; +static uint8_t sulog_index_next = 0; + +static DEFINE_SPINLOCK(sulog_lock); + +void sulog_init_heap() +{ + sulog_buf_ptr = kzalloc(SULOG_BUFSIZ, GFP_KERNEL); + if (!sulog_buf_ptr) + return; + + pr_info("sulog_init: allocated %lu bytes on 0x%p \n", SULOG_BUFSIZ, sulog_buf_ptr); +} + +void write_sulog(uint8_t sym) +{ + if (!sulog_buf_ptr) + return; + + unsigned int offset = sulog_index_next * sizeof(struct sulog_entry); + struct sulog_entry entry = {0}; + + // WARNING!!! this is LE only! + entry.s_time = (uint32_t)(ktime_get_boottime() / 1000000000); + entry.data = (uint32_t)current_uid().val; + *((char *)&entry.data + 3) = sym; + + // we can perform this write atomic on 64-bit, memcpy is kill + // however this still has to be locked for exclusion as there is a reader + spin_lock(&sulog_lock); + *(volatile uint64_t *)(sulog_buf_ptr + offset) = *(volatile uint64_t *)&entry; + spin_unlock(&sulog_lock); + + // move ptr for next iteration + sulog_index_next = sulog_index_next + 1; + + if (sulog_index_next >= SULOG_ENTRY_MAX) + sulog_index_next = 0; +} + +struct sulog_entry_rcv_ptr { + uint64_t index_ptr; // send index here + uint64_t buf_ptr; // send buf here + uint64_t uptime_ptr; // uptime +}; + +int send_sulog_dump(void __user *uptr) +{ + if (!sulog_buf_ptr) + return 1; + + struct sulog_entry_rcv_ptr sbuf = {0}; + + if (copy_from_user(&sbuf, uptr, sizeof(sbuf) )) + return 1; + + if (!sbuf.index_ptr || !sbuf.buf_ptr || !sbuf.uptime_ptr ) + return 1; + + // send uptime + uint32_t uptime = (uint32_t)(ktime_get_boottime() / 1000000000); + if (copy_to_user((void __user *)sbuf.uptime_ptr, &uptime, sizeof(uptime) )) + return 1; + + // send index + if (copy_to_user((void __user *)sbuf.index_ptr, &sulog_index_next, sizeof(sulog_index_next) )) + return 1; + + // send buffer data + spin_lock(&sulog_lock); + if (copy_to_user((void __user *)sbuf.buf_ptr, sulog_buf_ptr, SULOG_BUFSIZ )) { + spin_unlock(&sulog_lock); + return 1; + } + spin_unlock(&sulog_lock); + + return 0; +} diff --git a/manager/app/.gitignore b/manager/app/.gitignore index dc5ca963c57a..117b6b02e30b 100644 --- a/manager/app/.gitignore +++ b/manager/app/.gitignore @@ -1,2 +1,3 @@ /build /release/ +/src/main/resources diff --git a/manager/app/build.gradle.kts b/manager/app/build.gradle.kts index 5997eefc8b8f..c281d20f98ce 100644 --- a/manager/app/build.gradle.kts +++ b/manager/app/build.gradle.kts @@ -119,6 +119,7 @@ android { targetSdk = androidTargetSdkVersion versionCode = managerVersionCode versionName = managerVersionName + applicationId = "com.kowx712.supermanager" buildConfigField("boolean", "IS_PR_BUILD", isPrBuild.toString()) @@ -131,7 +132,7 @@ android { } ndk { - abiFilters += listOf("arm64-v8a", "x86_64") + abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64") } } @@ -148,16 +149,30 @@ android { androidComponents { onVariants(selector().withBuildType("release")) { - it.packaging.resources.excludes.addAll(listOf("META-INF/**", "kotlin/**", "org/**", "**.bin")) + it.packaging.resources.excludes.addAll(listOf("META-INF/*.version", "kotlin/**", "org/**", "**.bin")) } } base { archivesName.set( - "KernelSU_${managerVersionName}_${managerVersionCode}" + "KowSU_${managerVersionName}_${managerVersionCode}" ) } +tasks.register("mergeScripts") { + into("${project.projectDir}/src/main/resources/META-INF/com/google/android") + from(rootProject.file("scripts/update_binary.sh")) { + rename { "update-binary" } + } + from(rootProject.file("scripts/updater_script.sh")) { + rename { "updater-script" } + } +} + +tasks.named("preBuild") { + dependsOn("mergeScripts") +} + dependencies { implementation(libs.androidx.activity.compose) diff --git a/manager/app/src/main/AndroidManifest.xml b/manager/app/src/main/AndroidManifest.xml index 5d1fca43f548..78525428d781 100644 --- a/manager/app/src/main/AndroidManifest.xml +++ b/manager/app/src/main/AndroidManifest.xml @@ -4,6 +4,17 @@ + + + @@ -18,8 +29,8 @@ android:directBootAware="true" android:fullBackupContent="@xml/backup_rules" android:hasFragileUserData="true" - android:icon="@mipmap/ic_launcher" - android:label="@string/app_name" + android:icon="@mipmap/ic_launcher_kowsu" + android:label="@string/app_name_kowsu" android:networkSecurityConfig="@xml/network_security_config" android:supportsRtl="true" android:theme="@style/Theme.KernelSU" @@ -33,6 +44,14 @@ + + + @@ -43,7 +62,38 @@ android:mimeType="application/zip" android:scheme="content" /> - + + + + + + + + + + + + + + + + + + + 2&&void 0!==arguments[2]?arguments[2]:{};o(n,i);var a=n.ellipsis,s=n.separator;if(t>e.length)return e;var c=t-a.length;if(c<1)return a;var l=e.slice(0,c);if(r(s))return l+a;if(e.indexOf(s,c)!==c){var u=l.lastIndexOf(s);u>-1&&(l=l.slice(0,u))}return l+a};var i={ellipsis:"..."};e.exports=t},21:function(e,t,n){var o=n(2717),r=n(1738),i=n(9100),a=n(8178),s=new(t=o({className:"Select",initialize:function(e){return this.length=0,e?r(e)?s.find(e):void(e.nodeType&&(this[0]=e,this.length=1)):this},find:function(e){var n=new t;return this.each((function(){a(n,this.querySelectorAll(e))})),n},each:function(e){return i(this,(function(t,n){e.call(t,n,t)})),this}}))(document);e.exports=t},96:function(e,t,n){var o=n(2561);t=function(e){return o(e).toLocaleLowerCase()},e.exports=t},128:function(e,t,n){"use strict";n.d(t,{A:function(){return K}});var o=n(3029),r=n(2901),i=n(388),a=n(3954),s=n(5361),c=n(3915),l=n.n(c),u=n(6097),d=n.n(u),h=n(1738),f=n.n(h),p=n(4994),v=n.n(p),g=n(9405),m=n.n(g),b=n(5169),y=n.n(b),A=n(9548),w=n.n(A),_=n(3249),x=n.n(_),k=n(6030),C=n.n(k),S=n(5004),E=n.n(S);n(9410),n(8609);function T(e){var t="luna-".concat(e,"-");function n(e){return l()(m()(e).split(/\s+/),(function(e){return x()(e,t)?e:e.replace(/[\w-]+/,(function(e){return"".concat(t).concat(e)}))})).join(" ")}return function(e){if(/<[^>]*>/g.test(e))try{var t=w().parse(e);return N(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),w().stringify(t)}catch(t){return n(e)}return n(e)}}function N(e,t){for(var n=0,o=e.length;n2&&void 0!==arguments[2]?arguments[2]:{}).theme,u=void 0===l?"light":l;return(0,o.A)(this,t),r=function(e,t,n){return t=(0,a.A)(t),(0,i.A)(e,U()?Reflect.construct(t,n||[],(0,a.A)(e).constructor):t.apply(e,n))}(this,t),r.subComponents=[],r.theme="",r.onThemeChange=function(e){"auto"===r.options.theme&&r.setTheme(e)},r.compName=c,r.c=T(c),r.options={},r.container=e,r.$container=z()(e),r.$container.addClass(["luna-".concat(c),r.c("platform-".concat((s=E()(),"os x"===s?"mac":s)))]),r.on("changeOption",(function(e,t){if("theme"===e&&t){var n=t;"auto"===t&&(n=$().get()),r.setTheme(n),B()(r.subComponents,(function(e){return e.setOption("theme",t)}))}})),$().on("change",r.onThemeChange),r.setOption("theme",u),r}return(0,s.A)(t,e),(0,r.A)(t,[{key:"destroy",value:function(){var e=this;this.destroySubComponents();var t=this.$container,n=t.attr("class");B()(n.split(/\s+/),(function(n){Q()(n,"luna-".concat(e.compName))&&t.rmClass(n)})),t.html(""),this.emit("destroy"),this.removeAllListeners(),$().off("change",this.onThemeChange)}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,B()(r,(function(e,t){var r=o[t];o[t]=e,e!==r&&n.emit("changeOption",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){H()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){B()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};G()(e,t),R()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}},{key:"setTheme",value:function(e){var t=this.c,n=this.$container;this.theme&&n.rmClass(t("theme-".concat(this.theme))),n.addClass(t("theme-".concat(e))),this.theme=e}}])}(M());function J(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(J=function(){return!!e})()}e=n.hmd(e);var K=function(e){function t(e){var n,r,s,c,l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return(0,o.A)(this,t),r=this,s=t,c=[e,{compName:"box-model"}],s=(0,a.A)(s),(n=(0,i.A)(r,J()?Reflect.construct(s,c||[],(0,a.A)(r).constructor):s.apply(r,c))).initOptions(l),n.options.element&&n.render(),n.bindEvent(),n}return(0,s.A)(t,e),(0,r.A)(t,[{key:"bindEvent",value:function(){var e=this;this.on("changeOption",(function(t){if("element"===t)e.render()}))}},{key:"render",value:function(){var e=this,t=this.c,n=this.$container,o=this.getBoxModelData();n.html([o.position?'
'):"",o.position?'
position
').concat(o.position.top,'

').concat(o.position.left,"
"):"",'
'),'
margin
').concat(o.margin.top,'

').concat(o.margin.left,"
"),'
'),'
border
').concat(o.border.top,'

').concat(o.border.left,"
"),'
'),'
padding
').concat(o.padding.top,'

').concat(o.padding.left,"
"),'
'),"".concat(o.content.width," × ").concat(o.content.height,""),"
",'
').concat(o.padding.right,'

').concat(o.padding.bottom,"
"),"
",'
').concat(o.border.right,'

').concat(o.border.bottom,"
"),"
",'
').concat(o.margin.right,'

').concat(o.margin.bottom,"
"),"
",o.position?'
').concat(o.position.right,'

').concat(o.position.bottom,"
"):"",o.position?"
":""].join(""));var r=this.find(".margin"),i=this.find(".border"),a=this.find(".padding"),s=this.find(".content"),c=function(){r.addClass(t("highlighted")),i.addClass(t("highlighted")),a.addClass(t("highlighted")),s.addClass(t("highlighted"))};c();var l=function(n){var o;switch(e.find(".highlighted").rmClass(t("highlighted")),n){case"margin":o=r;break;case"border":o=i;break;case"padding":o=a;break;default:o=s}o.addClass(t("highlighted")),e.emit("highlight",n)},u=v()(l,this,"margin"),d=v()(l,this,"border"),h=v()(l,this,"padding"),f=v()(l,this,"content");r.on("mouseenter",u).on("mouseleave",(function(){c(),e.emit("highlight","all")})),i.on("mouseenter",d).on("mouseleave",u),a.on("mouseenter",h).on("mouseleave",d),s.on("mouseenter",f).on("mouseleave",h)}},{key:"getBoxModelData",value:function(){var e=this.options.element,t=window.getComputedStyle(e);function n(e){var n=["top","left","right","bottom"];return"position"!==e&&(n=l()(n,(function(t){return"".concat(e,"-").concat(t)}))),"border"===e&&(n=l()(n,(function(e){return"".concat(e,"-width")}))),{top:V(t[n[0]],e),left:V(t[n[1]],e),right:V(t[n[2]],e),bottom:V(t[n[3]],e)}}var o,r,i,a,s,c,u={margin:n("margin"),border:n("border"),padding:n("padding"),content:(o=e,r=window.getComputedStyle(o),i=O(r.paddingLeft)+O(r.paddingRight),a=O(r.paddingTop)+O(r.paddingBottom),s=O(r.borderLeftWidth)+O(r.borderRightWidth),c=O(r.borderTopWidth)+O(r.borderBottomWidth),{width:V(o.offsetWidth-i-s),height:V(o.offsetHeight-a-c)})};return"static"!==t.position&&(u.position=n("position")),u}}])}(W);function V(e,t){if(d()(e))return e;if(!f()(e))return"‒";var n=O(e);return isNaN(n)?e:"position"===t?n:0===n?"‒":n}(function(e,t){try{e.exports=t,e.exports.default=t}catch(e){}})(e,K)},162:function(e,t){"use strict";var n=this&&this.__values||function(e){var t="function"==typeof Symbol&&Symbol.iterator,n=t&&e[t],o=0;if(n)return n.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&o>=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},o=this&&this.__read||function(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var o,r,i=n.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(e){r={error:e}}finally{try{o&&!o.done&&(n=i.return)&&n.call(i)}finally{if(r)throw r.error}}return a},r=this&&this.__spreadArray||function(e,t,n){if(n||2===arguments.length)for(var o,r=0,i=t.length;rn&&(e=n),e},t.adoptStyleSheet=c},187:function(e,t,n){(t=n(6314)(!1)).push([e.id,'.luna-setting{min-width:320px;color:rgba(0,0,0,.88);color:var(--luna-color-text,rgba(0,0,0,.88));background-color:rgba(0,0,0,0);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-family:var(--luna-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:14px}.luna-setting .luna-setting-hidden,.luna-setting.luna-setting-hidden{display:none}.luna-setting .luna-setting-invisible,.luna-setting.luna-setting-invisible{visibility:hidden}.luna-setting *{box-sizing:border-box}.luna-setting.luna-setting-theme-dark{color-scheme:dark;color:hsla(0,0%,100%,.85);color:var(--luna-color-text-dark,rgba(255,255,255,.85));background-color:rgba(0,0,0,0)}.luna-setting-item.luna-setting-selected:focus{outline:1px solid}.luna-setting-item .luna-setting-title{line-height:1.4em;font-weight:600}.luna-setting-item .luna-setting-description,.luna-setting-item.luna-setting-item-markdown{line-height:1.4em}.luna-setting-item .luna-setting-description *,.luna-setting-item.luna-setting-item-markdown *{margin:0}.luna-setting-item .luna-setting-description strong,.luna-setting-item.luna-setting-item-markdown strong{font-weight:600}.luna-setting-item .luna-setting-description a,.luna-setting-item.luna-setting-item-markdown a{background-color:rgba(0,0,0,0);text-decoration:none}.luna-setting-item .luna-setting-control,.luna-setting-item .luna-setting-description{font-size:12px}.luna-setting-item .luna-setting-description{margin-bottom:8px}.luna-setting-item .luna-setting-control{display:flex;align-items:center}.luna-setting-item-button,.luna-setting-item-checkbox,.luna-setting-item-input,.luna-setting-item-markdown,.luna-setting-item-number,.luna-setting-item-select,.luna-setting-item-title{padding:10px}.luna-setting-item-title{font-weight:600}.luna-setting-item-title.luna-setting-level-1{font-size:18px}.luna-setting-item-title.luna-setting-level-2{font-size:16px}.luna-setting-item-title.luna-setting-level-3{font-size:14px}.luna-setting-item-input.luna-setting-disabled input{opacity:.6}.luna-setting-item-input input{-webkit-tap-highlight-color:transparent;color:rgba(0,0,0,.88);-webkit-appearance:none;-moz-appearance:none;appearance:none;border:1px solid;outline:0;padding:2px 8px;border-radius:2px;font-size:14px;width:100%}.luna-setting-item-number.luna-setting-disabled .luna-setting-range-container,.luna-setting-item-number.luna-setting-disabled input{opacity:.6}.luna-setting-item-number.luna-setting-disabled .luna-setting-range-container input{opacity:1}.luna-setting-item-number input[type=number]{-webkit-tap-highlight-color:transparent;color:rgba(0,0,0,.88);-webkit-appearance:none;-moz-appearance:none;appearance:none;border:1px solid;outline:0;padding:2px 8px;border-radius:2px;font-size:14px;width:200px;padding:2px}.luna-setting-item-number .luna-setting-range-container{flex:2;position:relative;top:1px}.luna-setting-item-number .luna-setting-range-container .luna-setting-range-track{height:4px;width:100%;padding:0 10px;position:absolute;left:0;top:4px}.luna-setting-item-number .luna-setting-range-container .luna-setting-range-track .luna-setting-range-track-bar{border-radius:2px;overflow:hidden;width:100%;height:4px}.luna-setting-item-number .luna-setting-range-container .luna-setting-range-track .luna-setting-range-track-bar .luna-setting-range-track-progress{height:100%;width:50%}.luna-setting-item-number .luna-setting-range-container input{-webkit-appearance:none;background:rgba(0,0,0,0);height:4px;width:100%;position:relative;top:-3px;margin:0 auto;outline:0;border-radius:2px}.luna-setting-item-number .luna-setting-range-container input::-webkit-slider-thumb{-webkit-appearance:none;position:relative;top:0;z-index:1;width:16px;border:none;height:16px;border-radius:10px;border:1px solid}.luna-setting-item-checkbox.luna-setting-disabled .luna-setting-control{opacity:.6}.luna-setting-item-checkbox input{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:14px;height:14px;border:1px solid;border-radius:0;position:relative;outline:0;margin-left:0;margin-right:8px;transition:background-color .1s;align-self:flex-start;flex-shrink:0}.luna-setting-item-checkbox input:checked:after{content:"";width:100%;height:100%;position:absolute;left:0;top:0;background-image:url(data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjZmZmZmZmIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgdmVyc2lvbj0iMS4xIiB4PSIwcHgiIHk9IjBweCI+PHRpdGxlPmljb25fYnlfUG9zaGx5YWtvdjEwPC90aXRsZT48ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz48ZyBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48ZyBmaWxsPSIjZmZmZmZmIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNi4wMDAwMDAsIDI2LjAwMDAwMCkiPjxwYXRoIGQ9Ik0xNy45OTk5ODc4LDMyLjQgTDEwLjk5OTk4NzgsMjUuNCBDMTAuMjI2Nzg5MSwyNC42MjY4MDE0IDguOTczMTg2NDQsMjQuNjI2ODAxNCA4LjE5OTk4Nzc5LDI1LjQgTDguMTk5OTg3NzksMjUuNCBDNy40MjY3ODkxNCwyNi4xNzMxOTg2IDcuNDI2Nzg5MTQsMjcuNDI2ODAxNCA4LjE5OTk4Nzc5LDI4LjIgTDE2LjU4NTc3NDIsMzYuNTg1Nzg2NCBDMTcuMzY2ODIyOCwzNy4zNjY4MzUgMTguNjMzMTUyOCwzNy4zNjY4MzUgMTkuNDE0MjAxNCwzNi41ODU3ODY0IEw0MC41OTk5ODc4LDE1LjQgQzQxLjM3MzE4NjQsMTQuNjI2ODAxNCA0MS4zNzMxODY0LDEzLjM3MzE5ODYgNDAuNTk5OTg3OCwxMi42IEw0MC41OTk5ODc4LDEyLjYgQzM5LjgyNjc4OTEsMTEuODI2ODAxNCAzOC41NzMxODY0LDExLjgyNjgwMTQgMzcuNzk5OTg3OCwxMi42IEwxNy45OTk5ODc4LDMyLjQgWiI+PC9wYXRoPjwvZz48L2c+PC9nPjwvc3ZnPg==);background-size:30px;background-repeat:no-repeat;background-position:center}.luna-setting-item-checkbox label{-webkit-tap-highlight-color:transparent}.luna-setting-item-checkbox label *{margin:0}.luna-setting-item-select.luna-setting-disabled .luna-setting-select{opacity:.6}.luna-setting-item-select .luna-setting-select{position:relative}.luna-setting-item-select .luna-setting-select select{margin:0;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:1px solid;padding:2px 8px;padding-right:18px;outline:0;border-radius:2px;-webkit-tap-highlight-color:transparent}.luna-setting-item-select .luna-setting-select:after{content:"";width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid;position:absolute;top:0;bottom:0;right:6px;margin:auto;pointer-events:none}.luna-setting-item-select .luna-setting-select select{width:300px}.luna-setting-item-button button{-webkit-tap-highlight-color:transparent;border:1px solid;padding:2px 8px;font-size:14px;border-radius:2px}.luna-setting-item-button button:active{border:1px solid}.luna-setting-item-separator{border-bottom:1px solid}.luna-setting-theme-light .luna-setting-item.luna-setting-selected,.luna-setting-theme-light .luna-setting-item:hover{background-color:rgba(0,0,0,.06);background-color:var(--luna-color-fill-secondary,rgba(0,0,0,.06))}.luna-setting-theme-light .luna-setting-item.luna-setting-selected:focus{outline-color:#1a73e8;outline-color:var(--luna-color-primary,#1a73e8)}.luna-setting-theme-light .luna-setting-item .luna-setting-description a,.luna-setting-theme-light .luna-setting-item.luna-setting-item-markdown a{color:#1a73e8;color:var(--luna-color-primary,#1a73e8)}.luna-setting-theme-light .luna-setting-item-separator{border-color:#d9d9d9;border-color:var(--luna-color-border,#d9d9d9)}.luna-setting-theme-light .luna-setting-item-input input{background-color:#fff;background-color:var(--luna-color-bg-container,#fff);color:rgba(0,0,0,.88);color:var(--luna-color-text,rgba(0,0,0,.88));border-color:#d9d9d9;border-color:var(--luna-color-border,#d9d9d9)}.luna-setting-theme-light .luna-setting-item-checkbox input{border-color:#d9d9d9;border-color:var(--luna-color-border,#d9d9d9)}.luna-setting-theme-light .luna-setting-item-checkbox input:checked{background-color:#1a73e8;background-color:var(--luna-color-primary,#1a73e8);border-color:#1a73e8;border-color:var(--luna-color-primary,#1a73e8)}.luna-setting-theme-light .luna-setting-item-select .luna-setting-select select{background-color:#fff;background-color:var(--luna-color-bg-container,#fff);color:rgba(0,0,0,.88);color:var(--luna-color-text,rgba(0,0,0,.88));border-color:#d9d9d9;border-color:var(--luna-color-border,#d9d9d9)}.luna-setting-theme-light .luna-setting-item-select .luna-setting-select:after{border-top-color:rgba(0,0,0,.88);border-top-color:var(--luna-color-text,rgba(0,0,0,.88))}.luna-setting-theme-light .luna-setting-item-button button{background-color:#fff;background-color:var(--luna-color-bg-container,#fff);border-color:#d9d9d9;border-color:var(--luna-color-border,#d9d9d9);color:#1a73e8;color:var(--luna-color-primary,#1a73e8)}.luna-setting-theme-light .luna-setting-item-button button:active,.luna-setting-theme-light .luna-setting-item-button button:hover{background-color:rgba(0,0,0,.06);background-color:var(--luna-color-fill-secondary,rgba(0,0,0,.06))}.luna-setting-theme-light .luna-setting-item-button button:active{border-color:#1a73e8;border-color:var(--luna-color-primary,#1a73e8)}.luna-setting-theme-light .luna-setting-item-number input[type=number]{background-color:#fff;background-color:var(--luna-color-bg-container,#fff);color:rgba(0,0,0,.88);color:var(--luna-color-text,rgba(0,0,0,.88));border-color:#d9d9d9;border-color:var(--luna-color-border,#d9d9d9)}.luna-setting-theme-light .luna-setting-item-number .luna-setting-range-container .luna-setting-range-track .luna-setting-range-track-bar{background-color:#d9d9d9;background-color:var(--luna-color-border,#d9d9d9)}.luna-setting-theme-light .luna-setting-item-number .luna-setting-range-container .luna-setting-range-track .luna-setting-range-track-bar .luna-setting-range-track-progress{background-color:#1a73e8;background-color:var(--luna-color-primary,#1a73e8)}.luna-setting-theme-light .luna-setting-item-number .luna-setting-range-container input::-webkit-slider-thumb{border-color:#d9d9d9;border-color:var(--luna-color-border,#d9d9d9);background:radial-gradient(circle at center,#eee 0,#eee 15%,#fff 22%,#fff 100%)}.luna-setting-theme-dark .luna-setting-item.luna-setting-selected,.luna-setting-theme-dark .luna-setting-item:hover{background-color:hsla(0,0%,100%,.12);background-color:var(--luna-color-fill-secondary,rgba(255,255,255,.12))}.luna-setting-theme-dark .luna-setting-item.luna-setting-selected:focus{outline-color:#1965c8;outline-color:var(--luna-color-primary,#1965c8)}.luna-setting-theme-dark .luna-setting-item .luna-setting-description a,.luna-setting-theme-dark .luna-setting-item.luna-setting-item-markdown a{color:#1965c8;color:var(--luna-color-primary,#1965c8)}.luna-setting-theme-dark .luna-setting-item-separator{border-color:#424242;border-color:var(--luna-color-border,#424242)}.luna-setting-theme-dark .luna-setting-item-input input{background-color:#141414;background-color:var(--luna-color-bg-container,#141414);color:hsla(0,0%,100%,.85);color:var(--luna-color-text,rgba(255,255,255,.85));border-color:#424242;border-color:var(--luna-color-border,#424242)}.luna-setting-theme-dark .luna-setting-item-checkbox input{border-color:#424242;border-color:var(--luna-color-border,#424242)}.luna-setting-theme-dark .luna-setting-item-checkbox input:checked{background-color:#1965c8;background-color:var(--luna-color-primary,#1965c8);border-color:#1965c8;border-color:var(--luna-color-primary,#1965c8)}.luna-setting-theme-dark .luna-setting-item-select .luna-setting-select select{background-color:#141414;background-color:var(--luna-color-bg-container,#141414);color:hsla(0,0%,100%,.85);color:var(--luna-color-text,rgba(255,255,255,.85));border-color:#424242;border-color:var(--luna-color-border,#424242)}.luna-setting-theme-dark .luna-setting-item-select .luna-setting-select:after{border-top-color:hsla(0,0%,100%,.85);border-top-color:var(--luna-color-text,rgba(255,255,255,.85))}.luna-setting-theme-dark .luna-setting-item-button button{background-color:#141414;background-color:var(--luna-color-bg-container,#141414);border-color:#424242;border-color:var(--luna-color-border,#424242);color:#1965c8;color:var(--luna-color-primary,#1965c8)}.luna-setting-theme-dark .luna-setting-item-button button:active,.luna-setting-theme-dark .luna-setting-item-button button:hover{background-color:hsla(0,0%,100%,.12);background-color:var(--luna-color-fill-secondary,rgba(255,255,255,.12))}.luna-setting-theme-dark .luna-setting-item-button button:active{border-color:#1965c8;border-color:var(--luna-color-primary,#1965c8)}.luna-setting-theme-dark .luna-setting-item-number input[type=number]{background-color:#141414;background-color:var(--luna-color-bg-container,#141414);color:hsla(0,0%,100%,.85);color:var(--luna-color-text,rgba(255,255,255,.85));border-color:#424242;border-color:var(--luna-color-border,#424242)}.luna-setting-theme-dark .luna-setting-item-number .luna-setting-range-container .luna-setting-range-track .luna-setting-range-track-bar{background-color:#424242;background-color:var(--luna-color-border,#424242)}.luna-setting-theme-dark .luna-setting-item-number .luna-setting-range-container .luna-setting-range-track .luna-setting-range-track-bar .luna-setting-range-track-progress{background-color:#1965c8;background-color:var(--luna-color-primary,#1965c8)}.luna-setting-theme-dark .luna-setting-item-number .luna-setting-range-container input::-webkit-slider-thumb{border-color:#424242;border-color:var(--luna-color-border,#424242);background:radial-gradient(circle at center,#aaa 0,#aaa 15%,#ccc 22%,#ccc 100%)}',""]),e.exports=t},199:function(e,t,n){var o=n(3089),r=n(7468);t=function(e){return e=o({},e),function(t){return r(t,e)}},e.exports=t},282:function(e,t,n){var o=n(438),r=n(9405),i=n(3915),a=n(769);t=function(e){var t=a(e.match(s));return o(i(t,(function(e){return r(e)})))};var s=/((https?)|(ftp)):\/\/[\w.]+[^ \f\n\r\t\v"\\<>[\]\u2100-\uFFFF(),]*/gi;e.exports=t},311:function(e,t,n){var o=n(3957),r=n(9993),i=n(5651),a=n(9760),s=n(7257);function c(e,t,n,r){return o(t)&&(r=n,n=t,t={}),{url:e,data:t,success:n,dataType:r}}(t=function(e){i(e,t.setting);var n,o=e.type,c=e.url,l=e.data,u=e.dataType,d=e.success,h=e.error,f=e.timeout,p=e.complete,v=e.xhr();return v.onreadystatechange=function(){if(4===v.readyState){var e;clearTimeout(n);var t=v.status;if(t>=200&&t<300||304===t){e=v.responseText,"xml"===u&&(e=v.responseXML);try{"json"===u&&(e=JSON.parse(e))}catch(e){}d(e,v)}else h(v);p(v)}},"GET"===o?(l=s.stringify(l))&&(c+=c.indexOf("?")>-1?"&"+l:"?"+l):"application/x-www-form-urlencoded"===e.contentType?a(l)&&(l=s.stringify(l)):"application/json"===e.contentType&&a(l)&&(l=JSON.stringify(l)),v.open(o,c,!0),v.setRequestHeader("Content-Type",e.contentType),f>0&&(n=setTimeout((function(){v.onreadystatechange=r,v.abort(),h(v,"timeout"),p(v)}),f)),v.send("GET"===o?null:l),v}).setting={type:"GET",success:r,error:r,complete:r,dataType:"json",contentType:"application/x-www-form-urlencoded",data:{},xhr:function(){return new XMLHttpRequest},timeout:0},t.get=function(){return t(c.apply(null,arguments))},t.post=function(){var e=c.apply(null,arguments);return e.type="POST",t(e)},e.exports=t},365:function(e,t){var n=Object.prototype.hasOwnProperty;t=function(e,t){return n.call(e,t)},e.exports=t},383:function(e,t,n){var o=n(3497),r=n(1849),i=n(1009),a=n(96);t=function(e,t){for(var n,r=[],h=e;e;){if(n=!0,o(r)&&d[o(r)]){var f=new RegExp("]*>")).exec(e);if(f){var p=e.substring(0,f.index);e=e.substring(f.index+f[0].length),p&&t.text&&t.text(p)}_("",o(r))}else{if(i(e,"\x3c!--")){var v=e.indexOf("--\x3e");v>=0&&(t.comment&&t.comment(e.substring(4,v)),e=e.substring(v+3),n=!1)}else if(i(e,"=0&&r[o]!==n;o--);else o=0;if(o>=0){for(var i=r.length-1;i>=o;i--)t.end&&t.end(r[i]);r.length=o}}_()};var s=/^\s]+))?)*)\s*(\/?)>/i,c=/^<\/([-A-Za-z0-9_]+)[^>]*>/,l=/^<([-A-Za-z0-9_]+)((?:\s+[-A-Za-z0-9_:@.]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/i,u=/([-A-Za-z0-9_:@.]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,d=r("script,style".split(","));e.exports=t},387:function(e,t,n){var o=n(6833);function r(e,t){this[t]=e.replace(/\w/,(function(e){return e.toUpperCase()}))}t=function(e){var t=o(e),n=t[0];return t.shift(),t.forEach(r,t),n+=t.join("")},e.exports=t},388:function(e,t,n){"use strict";n.d(t,{A:function(){return r}});var o=n(2284);function r(e,t){if(t&&("object"==(0,o.A)(t)||"function"==typeof t))return t;if(void 0!==t)throw new TypeError("Derived constructors may only return object or undefined");return function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(e)}},438:function(e,t,n){var o=n(2571);function r(e,t){return e===t}t=function(e,t){return t=t||r,o(e,(function(e,n,o){for(var r=o.length;++n0&&r[r.length-1])||6!==s[0]&&2!==s[0])){i=0;continue}if(3===s[0]&&(!r||s[1]>r[0]&&s[1]A&&xw,S=f-y;S=(0,c.constrainNumber)(S,m,r-p-m);var E=o.minY-g-v,T=!0;E<0?(E=Math.min(i-v,o.maxY+g),T=!1):o.minY>i&&(E=i-g-v);var N=S>=o.minX&&S+p<=o.maxX&&E>=o.minY&&E+v<=o.maxY,O=So.minX&&Eo.minY;if(O&&!N)return void(d.style.display="none");if(d.style.top=E+"px",d.style.left=S+"px",C)return;var j=(0,c.createChild)(d,"div","tooltip-arrow");j.style.clipPath=T?"polygon(0 0, 100% 0, 50% 100%)":"polygon(50% 0, 0 100%, 100% 100%)",j.style.top=(T?v-1:-g)+"px",j.style.left=f-S+"px"}(this.tooltip,e.elementInfo,e.colorFormat,t,this.canvasWidth,this.canvasHeight)),this.context.restore(),{bounds:t}},t.prototype.drawAxis=function(e,t,n){e.save();var o=this.pageZoomFactor*this.pageScaleFactor*this.emulationScaleFactor,r=this.scrollX*this.pageScaleFactor,i=this.scrollY*this.pageScaleFactor;function a(e){return Math.round(e*o)}function s(e){return Math.round(e/o)}var c=this.canvasWidth/o,l=this.canvasHeight/o,u=50;e.save(),e.fillStyle=f,n?e.fillRect(0,a(l)-15,a(c),a(l)):e.fillRect(0,0,a(c),15),e.globalCompositeOperation="destination-out",e.fillStyle="red",t?e.fillRect(a(c)-15,0,a(c),a(l)):e.fillRect(0,0,15,a(l)),e.restore(),e.fillStyle=f,t?e.fillRect(a(c)-15,0,a(c),a(l)):e.fillRect(0,0,15,a(l)),e.lineWidth=1,e.strokeStyle=h,e.fillStyle=h,e.save(),e.translate(-r,.5-i);for(var p=l+s(i),v=100;v1&&o--,r=6*o<1?l+6*(t-l)*o:2*o<1?t:3*o<2?l+(t-l)*(2/3-o)*6:l,c[u]=n(255*r);return c};var n=Math.round;e.exports=t},961:function(e,t,n){var o=n(5693);t=function(e,t,n){var r=[];t=o(t,n);for(var i=-1,a=e.length;++i-1&&this._listeners.splice(t,1)},rmAllListeners:function(){this._listeners=[]},emit:function(){var e=this,t=a(arguments),n=r(this._listeners);i(n,(function(n){return n.apply(e,t)}),this)}},{mixin:function(e){i(["addListener","rmListener","emit","rmAllListeners"],(function(n){e[n]=t.prototype[n]})),e._listeners=e._listeners||[]}}),e.exports=t},1034:function(e,t,n){var o=n(9760),r=n(3957),i=n(6214),a=n(5154);t=function(e){return i(e)?e.map((function(e){return t(e)})):o(e)&&!r(e)?a(e,(function(e){return t(e)})):e},e.exports=t},1107:function(e,t,n){(t=n(6314)(!1)).push([e.id,"@font-face{font-family:luna-text-viewer-icon;src:url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAS0AAsAAAAAB2QAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAAFQAAAB0INElr09TLzIAAAFcAAAAPQAAAFZL+0klY21hcAAAAZwAAACfAAACEAEewxRnbHlmAAACPAAAAIYAAACkNSDggmhlYWQAAALEAAAALgAAADZzrb4oaGhlYQAAAvQAAAAWAAAAJAGRANNobXR4AAADDAAAABAAAAAoAZAAAGxvY2EAAAMcAAAAEAAAABYBWgFIbWF4cAAAAywAAAAdAAAAIAEXADtuYW1lAAADTAAAASkAAAIWm5e+CnBvc3QAAAR4AAAAOwAAAFJIWdOleJxjYGRgYOBiMGCwY2BycfMJYeDLSSzJY5BiYGGAAJA8MpsxJzM9kYEDxgPKsYBpDiBWAdNMDGwMQkAWK1CGlYEZyGMCstiBMpxAUUYGZgDbGgXDeJxjYGTQYJzAwMrAwFDH0AMkZaB0AgMngzEDAxMDKzMDVhCQ5prCcIAh+SMTwwkgVwhMMjAwgggAY84IrgAAAHicvZFLCsMwDERHzsdJ6aL0HD1VQiDQRbIN9Axd9aI+QTpjq5Bdd5F4Bo1lybIBNAAq8iA1YB8YZG+qlvUKl6zXGBjf6MofMWHGEyu2FPb9oCxULCtHs3yy+J2urg1rtojo0HM/MKnFGabOGlbdYvdT+1N6/7drXl8e6Vajo3efHP3b7HAUvntBMy1OJKujMTeHNZMV9McpFBC+tLgY4QB4nGNgZACBEwzrGdgZGOwZxdnVDdXNPfKEGlhchO0KhZtZ3IQYmMFq1jCsZpBi0GLQY2AwNzGzZjQSk2UUYdNmVFID8UyVRUXYlNRMlVGlTM1FjU3tmZkTmVhYmFRBhHwoCyuzKgtTIjMzWJg3ZClIGMRlZQmVB7GhMixM0aGhQIsB52sTqgAAeJxjYGRgYADi2JNxkvH8Nl8ZuBlOAAWiOB/va0DQQHCCYT2Q5GBgAnEANJ0KnQAAeJxjYGRgYDjBwIBEMjKgAi4AOvoCZQAAeJxjYACCE1CMBwAAM7gBkXicY2AAAiGGIFQIABXIAqN4nGNgZGBg4GLQZ2BmAAEmMI8LSP4H8xkADjQBUwAAAHicZZA9bsJAFITHYEgCUoIUKSmzVQoimZ+SA0BPQZfCmLUxsr3WekGiywlyhBwhp4hyghwoY/NoYC0/fzNv3u7KAAb4hYd6ebhtar1auKE6cZv0IOyTn4U76ONFuEt/KNzDG6bCfTzinTt4/h2dAUrhFu7xIdym/ynsk7+EO3jCt3CX/o9wDyv8Cffx6g3TyBSxKdxSJ/sstGd5/q60rVJTqEkwPlsLXWgbOr1R66OqDsnUuVjF1uRqzq7OMqNKa3Y6csHWuXI2GsXiB5HJkSKCQYG4qQ5LaCTYI0MIe9W91CumLSr6tVaYIMD4KrVgqmiSIZXGhsk1jqwVDjxtStcxrfhazuSkucxq3iQjK/7vurejE9EPsG2mSsww4hNf5IPmDvk/PRFeqAAAAHicXcU7CsAgFEXBe4x/l/kQBAtt3X0KSZNpRk7X91/F8eAJRBKZQqUp2Og2va19MAadyWJzpBd4kgcWAA==') format('woff')}[class*=' luna-text-viewer-icon-'],[class^=luna-text-viewer-icon-]{display:inline-block;font-family:luna-text-viewer-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.luna-text-viewer-icon-check:before{content:'\\f101'}.luna-text-viewer-icon-copy:before{content:'\\f102'}.luna-text-viewer{color:#333;background-color:#fff;font-family:Arial,Helvetica,sans-serif;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:14px;padding:0;unicode-bidi:embed;position:relative;overflow:auto;border:1px solid #ccc}.luna-text-viewer.luna-text-viewer-platform-windows{font-family:'Segoe UI',Tahoma,sans-serif}.luna-text-viewer.luna-text-viewer-platform-linux{font-family:Roboto,Ubuntu,Arial,sans-serif}.luna-text-viewer .luna-text-viewer-hidden,.luna-text-viewer.luna-text-viewer-hidden{display:none}.luna-text-viewer .luna-text-viewer-invisible,.luna-text-viewer.luna-text-viewer-invisible{visibility:hidden}.luna-text-viewer *{box-sizing:border-box}.luna-text-viewer.luna-text-viewer-theme-dark{color:#d9d9d9;border-color:#3d3d3d;background:#242424}.luna-text-viewer:hover .luna-text-viewer-copy{opacity:1}.luna-text-viewer-table{display:table}.luna-text-viewer-table .luna-text-viewer-line-number,.luna-text-viewer-table .luna-text-viewer-line-text{padding:0}.luna-text-viewer-table-row{display:table-row}.luna-text-viewer-line-number{display:table-cell;padding:0 3px 0 8px!important;text-align:right;vertical-align:top;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-right:1px solid #ccc}.luna-text-viewer-line-text{display:table-cell;padding-left:4px!important;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.luna-text-viewer-copy{background:#fff;opacity:0;position:absolute;right:5px;top:5px;border:1px solid #ccc;border-radius:4px;width:25px;height:25px;text-align:center;line-height:25px;cursor:pointer;transition:opacity .3s,top .3s}.luna-text-viewer-copy .luna-text-viewer-icon-check{color:#188037}.luna-text-viewer-text{padding:4px;font-size:12px;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;box-sizing:border-box;white-space:pre;display:block}.luna-text-viewer-text.luna-text-viewer-line-numbers{padding:0}.luna-text-viewer-text.luna-text-viewer-wrap-long-lines{white-space:pre-wrap}.luna-text-viewer-text.luna-text-viewer-wrap-long-lines .luna-text-viewer-line-text{word-break:break-all}.luna-text-viewer-theme-dark{color-scheme:dark}.luna-text-viewer-theme-dark .luna-text-viewer-copy,.luna-text-viewer-theme-dark .luna-text-viewer-line-number{border-color:#3d3d3d}.luna-text-viewer-theme-dark .luna-text-viewer-copy .luna-text-viewer-icon-check{color:#81c995}.luna-text-viewer-theme-dark .luna-text-viewer-copy{background-color:#242424}",""]),e.exports=t},1162:function(e,t,n){"use strict";n.d(t,{Ay:function(){return ve}});var o=n(991),r=n(3029),i=n(2901),a=n(388),s=n(3954),c=n(5361),l=n(3693),u=n.n(l),d=n(5241),h=n.n(d),f=n(5902),p=n.n(f),v=n(5630),g=n.n(v),m=n(9760),b=n.n(m),y=n(5651),A=n.n(y),w=n(3915),_=n.n(w),x=n(6030),k=n.n(x),C=n(2561),S=n.n(C),E=n(3957),T=n.n(E),N=n(3497),O=n.n(N),j=n(1976),M=n.n(j),I=n(1738),z=n.n(I),D=n(9405),B=n.n(D),F=n(3249),R=n.n(F),L=n(96),G=n.n(L),P=n(4236),H=n.n(P),Y=n(9100),$=n.n(Y);var q=n(2263),Q=n.n(q),U=n(5169),W=n.n(U),J=n(9548),K=n.n(J),V=(n(6097),n(5004)),Z=n.n(V);n(9410),n(8609);function X(e){var t="luna-".concat(e,"-");function n(e){return _()(B()(e).split(/\s+/),(function(e){return R()(e,t)?e:e.replace(/[\w-]+/,(function(e){return"".concat(t).concat(e)}))})).join(" ")}return function(e){if(/<[^>]*>/g.test(e))try{var t=K().parse(e);return ee(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),K().stringify(t)}catch(t){return n(e)}return n(e)}}function ee(e,t){for(var n=0,o=e.length;n2&&void 0!==arguments[2]?arguments[2]:{}).theme,d=void 0===l?"light":l;return(0,r.A)(this,t),o=function(e,t,n){return t=(0,s.A)(t),(0,a.A)(e,le()?Reflect.construct(t,n||[],(0,s.A)(e).constructor):t.apply(e,n))}(this,t),o.subComponents=[],o.theme="",o.onThemeChange=function(e){"auto"===o.options.theme&&o.setTheme(e)},o.compName=c,o.c=X(c),o.options={},o.container=e,o.$container=u()(e),o.$container.addClass(["luna-".concat(c),o.c("platform-".concat((i=Z()(),"os x"===i?"mac":i)))]),o.on("changeOption",(function(e,t){if("theme"===e&&t){var n=t;"auto"===t&&(n=ae().get()),o.setTheme(n),$()(o.subComponents,(function(e){return e.setOption("theme",t)}))}})),ae().on("change",o.onThemeChange),o.setOption("theme",d),o}return(0,c.A)(t,e),(0,i.A)(t,[{key:"destroy",value:function(){var e=this;this.destroySubComponents();var t=this.$container,n=t.attr("class");$()(n.split(/\s+/),(function(n){ce()(n,"luna-".concat(e.compName))&&t.rmClass(n)})),t.html(""),this.emit("destroy"),this.removeAllListeners(),ae().off("change",this.onThemeChange)}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,$()(r,(function(e,t){var r=o[t];o[t]=e,e!==r&&n.emit("changeOption",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){re()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){$()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};A()(e,t),ne()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}},{key:"setTheme",value:function(e){var t=this.c,n=this.$container;this.theme&&n.rmClass(t("theme-".concat(this.theme))),n.addClass(t("theme-".concat(e))),this.theme=e}}])}(Q()),de=function(e,t,n){return((e-t)/(n-t)*100).toFixed(2)};function he(e,t,n,r){var i=(0,o.A)((0,s.A)(1&r?e.prototype:e),t,n);return 2&r&&"function"==typeof i?function(e){return i.apply(n,e)}:i}function fe(e,t,n){return t=(0,s.A)(t),(0,a.A)(e,pe()?Reflect.construct(t,n||[],(0,s.A)(e).constructor):t.apply(e,n))}function pe(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(pe=function(){return!!e})()}e=n.hmd(e);var ve=function(e){function t(e){var n,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return(0,r.A)(this,t),(n=fe(this,t,[e,{compName:"setting"},o])).items=[],n.selectedItem=null,n.initOptions(o,{separatorCollapse:!0,filter:""}),n.bindEvent(),n}return(0,c.A)(t,e),(0,i.A)(t,[{key:"appendTitle",value:function(e){var t=new me(this,e,arguments.length>1&&void 0!==arguments[1]?arguments[1]:1);return this.append(t),t}},{key:"appendSeparator",value:function(){var e=this.items,t=this.options.separatorCollapse,n=O()(e);if(t&&n instanceof ye)return n;var o=new ye(this);return this.append(o),o}},{key:"appendNumber",value:function(e,t,n,o,r){b()(o)&&(r=o,o="");var i=new we(this,e,t,n,o,r);return this.append(i),i}},{key:"appendButton",value:function(e,t,n){T()(t)&&(n=t,t="");var o=new ke(this,e,t,n);return this.append(o),o}},{key:"appendHtml",value:function(e){var t=new Ce(this,e);return this.append(t),t}},{key:"appendMarkdown",value:function(e){var t=new be(this,e);return this.append(t),t}},{key:"appendInput",value:function(e,t,n){var o=new Ae(this,e,t,n,arguments.length>3&&void 0!==arguments[3]?arguments[3]:"");return this.append(o),o}},{key:"appendCheckbox",value:function(e,t,n,o){o||(o=n,n="");var r=new _e(this,e,t,n,o);return this.append(r),r}},{key:"appendSelect",value:function(e,t,n,o,r){b()(o)&&(r=o,o="");var i=new xe(this,e,t,n,o,r);return this.append(i),i}},{key:"remove",value:function(e){var t=this.items,n=t.indexOf(e);n>-1&&(e.detach(),t.splice(n,1),e===this.selectedItem&&this.selectItem(null))}},{key:"clear",value:function(){$()(this.items,(function(e){return e.detach()})),this.items=[],this.selectItem(null)}},{key:"selectItem",value:function(e){var t;(this.selectedItem&&(this.selectedItem.deselect(),this.selectedItem=null),H()(e))||(this.selectedItem=e,null===(t=this.selectedItem)||void 0===t||t.select())}},{key:"renderSettings",value:function(){var e=this,t=this.items;$()(t,(function(e){return e.detach()})),$()(t,(function(t){e.filterItem(t)&&e.$container.append(t.container)}))}},{key:"bindEvent",value:function(){var e=this,t=this.c;this.on("changeOption",(function(t){if("filter"===t)e.renderSettings()}));var n=this;this.$container.on("click",t(".item"),(function(){n.selectItem(this.settingItem)}))}},{key:"filterItem",value:function(e){var t=this.options.filter;if(t){if(T()(t))return t(e);if(M()(t))return t.test(e.text());if(z()(t)&&(t=B()(t)))return R()(G()(e.text()),G()(t))}return!0}},{key:"append",value:function(e){this.items.push(e),this.filterItem(e)&&this.$container.append(e.container)}}])}(ue),ge=function(){return(0,i.A)((function e(t,n,o,i){(0,r.A)(this,e),this.container=h()("div",{tabindex:"0"}),this.setting=t,this.container.settingItem=this,this.$container=u()(this.container),this.$container.addClass(t.c("item")).addClass(t.c("item-".concat(i))),this.key=n,this.value=o}),[{key:"select",value:function(){this.$container.addClass(this.setting.c("selected"))}},{key:"deselect",value:function(){this.$container.rmClass(this.setting.c("selected"))}},{key:"detach",value:function(){this.$container.remove()}},{key:"disable",value:function(){this.$container.addClass(this.setting.c("disabled"))}},{key:"enable",value:function(){this.$container.rmClass(this.setting.c("disabled"))}},{key:"text",value:function(){return this.$container.text()}},{key:"onChange",value:function(e){this.value!==e&&(this.setting.emit("change",this.key,e,this.value),this.value=e)}}])}(),me=function(e){function t(e,n,o){var i;return(0,r.A)(this,t),(i=fe(this,t,[e,"","","title"])).$container.addClass(e.c("level-".concat(o))),i.$container.text(n),i}return(0,c.A)(t,e),(0,i.A)(t)}(ge),be=function(e){function t(e,n){var o;return(0,r.A)(this,t),(o=fe(this,t,[e,"","","markdown"])).$container.html(n),o}return(0,c.A)(t,e),(0,i.A)(t)}(ge),ye=function(e){function t(e){return(0,r.A)(this,t),fe(this,t,[e,"","","separator"])}return(0,c.A)(t,e),(0,i.A)(t)}(ge),Ae=function(e){function t(e,n,o,i,a){var s;(0,r.A)(this,t),s=fe(this,t,[e,n,o,"input"]);var c=e.c;s.$container.html('
').concat(p()(i),'
\n
').concat(a,'
\n
\n \n
'));var l=s.$container.find("input");return l.val(o),l.on("change",(function(){return s.onChange(l.val())})),s.$input=l,s}return(0,c.A)(t,e),(0,i.A)(t,[{key:"setValue",value:function(e){this.$input.val(e),this.value=e}},{key:"disable",value:function(){he(t,"disable",this,3)([]),this.$input.attr("disabled","")}},{key:"enable",value:function(){he(t,"enable",this,3)([]),this.$input.rmAttr("disabled")}}])}(ge),we=function(e){function t(e,n,o,i,a){var s,c=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{};(0,r.A)(this,t),(s=fe(this,t,[e,n,o,"number"])).renderRange=function(){var e=k()(s.$input.val()),t=s.options;s.$trackProgress.css("width",de(e,t.min,t.max)+"%"),s.$value.text(S()(e))},A()(c,{min:0,max:10,step:1}),s.options=c;var l=s.$container,u=e.c,d=!!c.range;delete c.range;var h=c.min,f=c.max,v='");d&&(v="".concat(h,'
\n
\n
\n
\n
\n
\n ').concat(v,'\n
').concat(o,"/").concat(f)),l.html('
').concat(p()(i),'
\n
').concat(a,'
\n
').concat(v,"
"));var g=l.find("input");return s.$value=l.find(u(".value")),s.$trackProgress=l.find(u(".range-track-progress")),g.val(S()(o)),g.on("change",(function(){var e=k()(g.val());s.onChange(e)})),g.on("input",s.renderRange),s.$input=g,s}return(0,c.A)(t,e),(0,i.A)(t,[{key:"setValue",value:function(e){this.$input.val(S()(e)),this.value=e,this.renderRange()}},{key:"disable",value:function(){he(t,"disable",this,3)([]),this.$input.attr("disabled","")}},{key:"enable",value:function(){he(t,"enable",this,3)([]),this.$input.rmAttr("disabled")}}])}(ge),_e=function(e){function t(e,n,o,i,a){var s;(0,r.A)(this,t),s=fe(this,t,[e,n,o,"checkbox"]);var c=e.c,l=g()(e.c("checkbox-"));s.$container.html('
').concat(p()(i),'
\n
\n \n \n
"));var u=s.$container.find("input"),d=u.get(0);return d.checked=o,u.on("change",(function(){return s.onChange(d.checked)})),s.$input=u,s.input=d,s}return(0,c.A)(t,e),(0,i.A)(t,[{key:"setValue",value:function(e){this.input.checked=e,this.value=e}},{key:"disable",value:function(){he(t,"disable",this,3)([]),this.$input.attr("disabled","")}},{key:"enable",value:function(){he(t,"enable",this,3)([]),this.$input.rmAttr("disabled")}}])}(ge),xe=function(e){function t(e,n,o,i,a,s){var c;(0,r.A)(this,t),c=fe(this,t,[e,n,o,"select"]);var l=e.c;c.$container.html('
').concat(p()(i),'
\n
').concat(a,'
\n
\n
\n \n
\n
'));var u=c.$container.find("select");return c.$select=u,c.setOptions(s),u.on("change",(function(){return c.onChange(u.val())})),c}return(0,c.A)(t,e),(0,i.A)(t,[{key:"setValue",value:function(e){this.$select.val(e),this.value=e}},{key:"setOptions",value:function(e){var t=this;this.$select.html(_()(e,(function(e,n){return'")})).join(""))}},{key:"disable",value:function(){he(t,"disable",this,3)([]),this.$select.attr("disabled","")}},{key:"enable",value:function(){he(t,"enable",this,3)([]),this.$select.rmAttr("disabled")}}])}(ge),ke=function(e){function t(e,n,o,i){var a;return(0,r.A)(this,t),o||(o=n,n=""),(a=fe(this,t,[e,"","","button"])).$container.html(e.c('
'.concat(p()(n),'
\n
\n \n
"))),a.$container.find("button").on("click",i),a}return(0,c.A)(t,e),(0,i.A)(t)}(ge),Ce=function(e){function t(e,n){var o;return(0,r.A)(this,t),(o=fe(this,t,[e,"","","html"])).$container.append(n),o}return(0,c.A)(t,e),(0,i.A)(t)}(ge);(function(e,t){try{e.exports=t,e.exports.default=t}catch(e){}})(e,ve)},1167:function(e,t,n){var o=n(1909),r=n(5869),i=/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i,a=/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i;t=r((function(e){return e=e||(o?navigator.userAgent:""),i.test(e)||a.test(e.substr(0,4))})),e.exports=t},1168:function(e,t,n){var o=n(3422);t=function(e){if(o(e))return"";try{return r.call(e)}catch(e){}try{return e+""}catch(e){}return""};var r=Function.prototype.toString;e.exports=t},1277:function(e,t,n){(t=n(6314)(!1)).push([e.id,'.luna-box-model{display:inline-block;text-align:center;white-space:nowrap;color:rgba(0,0,0,.88);color:var(--luna-color-text,rgba(0,0,0,.88));background-color:#fff;background-color:var(--luna-color-bg-container,#fff);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-family:var(--luna-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:14px}.luna-box-model .luna-box-model-hidden,.luna-box-model.luna-box-model-hidden{display:none}.luna-box-model .luna-box-model-invisible,.luna-box-model.luna-box-model-invisible{visibility:hidden}.luna-box-model *{box-sizing:border-box}.luna-box-model.luna-box-model-theme-dark{color-scheme:dark;color:hsla(0,0%,100%,.85);color:var(--luna-color-text-dark,rgba(255,255,255,.85));background-color:#141414;background-color:var(--luna-color-bg-container-dark,#141414)}.luna-box-model{font-size:12px}.luna-box-model-label{position:absolute;margin-left:3px;padding:0 2px}.luna-box-model-bottom,.luna-box-model-left,.luna-box-model-right,.luna-box-model-top{display:inline-block}.luna-box-model-left,.luna-box-model-right{vertical-align:middle}.luna-box-model-border,.luna-box-model-content,.luna-box-model-margin,.luna-box-model-padding,.luna-box-model-position{position:relative;display:inline-block;text-align:center;vertical-align:middle;padding:3px;margin:3px;color:rgba(0,0,0,.88);background:#fff}.luna-box-model-position{border:1px gray dotted}.luna-box-model-margin{border:1px dashed}.luna-box-model-margin.luna-box-model-highlighted{color:rgba(0,0,0,.88)!important;background:rgba(246,178,107,.66)!important}.luna-box-model-border{border:1px #000 solid}.luna-box-model-border.luna-box-model-highlighted{color:rgba(0,0,0,.88)!important;background:rgba(255,229,153,.66)!important}.luna-box-model-padding{border:1px gray dashed}.luna-box-model-padding.luna-box-model-highlighted{color:rgba(0,0,0,.88)!important;background:rgba(147,196,125,.55)!important}.luna-box-model-content{border:1px gray solid;min-width:100px}.luna-box-model-content.luna-box-model-highlighted{color:rgba(0,0,0,.88)!important;background:rgba(111,168,220,.66)!important}.luna-box-model-theme-dark .luna-box-model-border,.luna-box-model-theme-dark .luna-box-model-content,.luna-box-model-theme-dark .luna-box-model-margin,.luna-box-model-theme-dark .luna-box-model-padding,.luna-box-model-theme-dark .luna-box-model-position{color:hsla(0,0%,100%,.85);background:#141414}.luna-box-model-theme-dark .luna-box-model-border{border-color:gray}',""]),e.exports=t},1443:function(e,t,n){(t=n(6314)(!1)).push([e.id,'#_resources{overflow-y:auto;-webkit-overflow-scrolling:touch;padding:10px;font-size:14px}#_resources ._section{margin-bottom:10px;overflow:hidden;border:1px solid var(--border)}#_resources ._section._warn{border:1px solid var(--console-warn-border)}#_resources ._section._warn ._title{background:var(--console-warn-background);color:var(--console-warn-foreground)}#_resources ._section._danger{border:1px solid var(--console-error-border)}#_resources ._section._danger ._title{background:var(--console-error-background);color:var(--console-error-foreground)}#_resources ._section._cookie,#_resources ._section._local-storage,#_resources ._section._session-storage{border:none}#_resources ._section._cookie ._title,#_resources ._section._local-storage ._title,#_resources ._section._session-storage ._title{border:1px solid var(--border);border-bottom:none}#_resources ._title{padding:10px;line-height:18px;color:var(--primary);background:var(--darker-background)}#_resources ._title ._btn{margin-left:5px;float:right;color:var(--primary);width:18px;height:18px;font-size:16px;cursor:pointer;transition:color .3s}#_resources ._title ._btn._filter-text{width:auto;max-width:80px;font-size:14px;overflow:hidden;font-weight:400;text-overflow:ellipsis;display:inline-block}#_resources ._title ._btn:active{color:var(--accent)}#_resources ._title ._btn._btn-disabled{color:inherit!important;cursor:default!important;pointer-events:none;opacity:.5}#_resources ._title ._btn._btn-disabled *{pointer-events:none}#_resources ._link-list{font-size:12px;color:var(--foreground)}#_resources ._link-list li{padding:10px;word-break:break-all}#_resources ._link-list li a{color:var(--link-color)!important}#_resources ._image-list{color:var(--foreground);font-size:12px;display:flex;flex-wrap:wrap;padding-left:10px;padding-top:10px}#_resources ._image-list::after{content:"";flex-grow:1000}#_resources ._image-list li{flex-grow:1;cursor:pointer;overflow-y:hidden;margin-right:10px;margin-bottom:10px;border:1px solid var(--border)}#_resources ._image-list li._image{height:100px;font-size:0}#_resources ._image-list li img{height:100px;min-width:100%;-o-object-fit:cover;object-fit:cover}._safe-area #_resources{padding-bottom:calc(10px + env(safe-area-inset-bottom))}',""]),e.exports=t},1505:function(e,t,n){var o=n(7308),r=n(6026),i=n(9405),a=n(9100),s=n(3915),c=n(1932);t=function(){var e=o("viewport");if(!e)return 1;e=s(e.split(","),(function(e){return i(e)}));var t=.25,n=5,l=1;a(e,(function(e){var o=(e=e.split("="))[0];e=e[1],"initial-scale"===o&&(l=+e),"maximum-scale"===o&&(n=+e),"minimum-scale"===o&&(t=+e)}));var u=r(l,t,n);return c(u)?1:u},e.exports=t},1532:function(e,t,n){var o=n(1009),r=n(5169),i=n(2561);function a(e,t){if(e=i(e),t=i(t),o(e,"_")&&!o(t,"_"))return 1;if(o(t,"_")&&!o(e,"_"))return-1;for(var n,a,s,c,l=/^\d+|^\D+/;;){if(!e)return t?-1:0;if(!t)return 1;if(n=e.match(l)[0],a=t.match(l)[0],s=!r.isNaN(n),c=!r.isNaN(a),s&&!c)return-1;if(c&&!s)return 1;if(s&&c){var u=n-a;if(u)return u;if(n.length!==a.length)return+n||+a?a.length-n.length:n.length-a.length}else if(n!==a)return n=0&&e.indexOf(t,n)===n},e.exports=t},1710:function(e,t){t=function(e,t){var n="";if(t<1)return"";for(;t>0;)1&t&&(n+=e),t>>=1,e+=e;return n},e.exports=t},1714:function(e,t,n){"use strict";n.d(t,{A:function(){return ne}});var o=n(3029),r=n(2901),i=n(388),a=n(3954),s=n(991),c=n(5361),l=n(2263),u=n.n(l),d=n(3693),h=n.n(d),f=n(3915),p=n.n(f),v=n(9405),g=n.n(v),m=n(5169),b=n.n(m),y=n(9548),A=n.n(y),w=(n(6097),n(3249)),_=n.n(w),x=(n(6030),n(5004)),k=n.n(x);n(8609);function C(e){var t="luna-".concat(e,"-");function n(e){return p()(g()(e).split(/\s+/),(function(e){return _()(e,t)?e:e.replace(/[\w-]+/,(function(e){return"".concat(t).concat(e)}))})).join(" ")}return function(e){if(/<[^>]*>/g.test(e))try{var t=A().parse(e);return S(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),A().stringify(t)}catch(t){return n(e)}return n(e)}}function S(e,t){for(var n=0,o=e.length;n2&&void 0!==arguments[2]?arguments[2]:{}).theme,f=void 0===d?"light":d;return(0,o.A)(this,t),s=this,c=t,c=(0,a.A)(c),(r=(0,i.A)(s,F()?Reflect.construct(c,l||[],(0,a.A)(s).constructor):c.apply(s,l))).subComponents=[],r.compName=u,r.c=C(u),r.options={},r.container=e,r.$container=h()(e),r.$container.addClass(["luna-".concat(u),r.c("platform-".concat(T()))]),r.on("optionChange",(function(e,t,n){var o=r.c;"theme"===e&&(r.$container.rmClass(o("theme-".concat(n))).addClass(o("theme-".concat(t))),O()(r.subComponents,(function(e){return e.setOption("theme",t)})))})),r.setOption("theme",f),r}return(0,c.A)(t,e),(0,r.A)(t,[{key:"destroy",value:function(){this.destroySubComponents();var e=this.c;this.$container.rmClass("luna-".concat(this.compName)).rmClass(e("platform-".concat(T()))).rmClass(e("theme-".concat(this.options.theme))),this.$container.html(""),this.emit("destroy"),this.removeAllListeners()}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,O()(r,(function(e,t){var r=o[t];o[t]=e,n.emit("optionChange",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){B()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){O()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};z()(e,t),M()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}}])}(u()),L=n(3497),G=n.n(L),P=n(9464),H=n.n(P),Y=n(5865),$=n.n(Y),q=n(4534),Q=n.n(q),U=n(4844),W=n.n(U),J=n(5902),K=n.n(J),V=n(9389),Z=n.n(V),X=n(6948),ee=n.n(X);function te(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(te=function(){return!!e})()}e=n.hmd(e);var ne=function(e){function t(e){var n,r,s,c,l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return(0,o.A)(this,t),r=this,s=t,c=[e,{compName:"text-viewer"},l],s=(0,a.A)(s),(n=(0,i.A)(r,te()?Reflect.construct(s,c||[],(0,a.A)(r).constructor):s.apply(r,c))).lineNum=0,n.copy=function(){var e=n.c,t=n.options,o=t.text,r=t.escape;W()(r?o:Z()(ee()(o)));var i=n.$copy.find(e(".icon"));i.addClass(e("icon-check")).rmClass(e("icon-copy")),setTimeout((function(){i.rmClass(e("icon-check")).addClass(e("icon-copy"))}),1e3)},n._updateCopyPos=function(){var e=n.container;n.$copy.css({top:e.scrollTop+5,right:5-e.scrollLeft})},n.initOptions(l,{text:"",escape:!0,showLineNumbers:!0,wrapLongLines:!0,maxHeight:1/0}),n.render=$()((function(){return n._render()}),16),n.updateCopyPos=Q()((function(){return n._updateCopyPos()}),300),n.initTpl(),n.$text=n.find(".text"),n.$copy=n.find(".copy"),E&&n.$copy.css("opacity","1"),n.options.text&&n.render(),n.bindEvent(),n.updateHeight(),n}return(0,c.A)(t,e),(0,r.A)(t,[{key:"append",value:function(e){var t=this,n=this.options,o=this.$copy,r=this.c,i=this.$text,a=n.showLineNumbers;if(this.options.text+=e,!a)return this.$text.append(n.escape?K()(e):e);var s=function(e){if(0===e.length)return[];return e.split(oe)}(e);H()(s)&&(s=[" "]),g()(G()(s))||s.pop();var c="";O()(s,(function(e,o){t.lineNum+=1,c+='
').concat(t.lineNum,'
').concat(n.escape?K()(e):e||" ","
")})),i.find(r(".table")).append(c),o.hide(),i.offset().height>40&&o.show(),this.updateCopyPos()}},{key:"destroy",value:function(){var e,n,o,r,i;this.$container.off("scroll",this.updateCopyPos),(e=t,n="destroy",o=this,r=3,i=(0,s.A)((0,a.A)(1&r?e.prototype:e),n,o),2&r&&"function"==typeof i?function(e){return i.apply(o,e)}:i)([])}},{key:"updateHeight",value:function(){var e=this.options.maxHeight;e>0&&e!==1/0?this.$text.css("max-height",e):this.$text.css("max-height","none")}},{key:"initTpl",value:function(){this.$container.html(this.c('
'))}},{key:"bindEvent",value:function(){var e=this;this.on("optionChange",(function(t){if("maxHeight"===t)e.updateHeight();else e.render()})),this.$container.on("scroll",this.updateCopyPos),this.$copy.on("click",this.copy)}},{key:"_render",value:function(){var e=this.c,t=this.$text,n=this.options,o=n.text,r=n.wrapLongLines,i=n.showLineNumbers;r?t.addClass(e("wrap-long-lines")):t.rmClass(e("wrap-long-lines")),i?t.addClass(e("line-numbers")):t.rmClass(e("line-numbers")),t.html('
')),this.lineNum=0,this.options.text="",this.append(o)}}])}(R),oe=/\r\n|\r|\n/g;(function(e,t){try{e.exports=t,e.exports.default=t}catch(e){}})(e,ne)},1738:function(e,t,n){var o=n(3974);t=function(e){return"[object String]"===o(e)},e.exports=t},1751:function(e,t,n){var o=n(3974);t=function(e){return"[object Map]"===o(e)},e.exports=t},1849:function(e,t,n){var o=n(9100),r=n(8971),i=n(3957);t=function(e,t){r(t)&&(t=!0);var n=i(t),a={};return o(e,(function(e){a[e]=n?t(e):t})),a},e.exports=t},1909:function(e,t){t="object"==typeof window&&"object"==typeof document&&9===document.nodeType,e.exports=t},1931:function(e,t,n){var o=n(1947);t=function(e){var t;switch(e=e||"local"){case"local":t=window.localStorage;break;case"session":t=window.sessionStorage}try{var n="test-localStorage-"+Date.now();t.setItem(n,n);var r=t.getItem(n);if(t.removeItem(n),r!==n)throw new Error}catch(e){return o}return t},e.exports=t},1932:function(e,t,n){var o=n(6097);t=function(e){return o(e)&&e!==+e},e.exports=t},1944:function(e,t,n){"use strict";n.d(t,{A:function(){return Z}});var o=n(5458),r=n(4467),i=n(7528),a=n(3029),s=n(2901),c=n(388),l=n(3954),u=n(991),d=n(5361),h=n(2263),f=n.n(h),p=n(3693),v=n.n(p),g=n(3915),m=n.n(g),b=n(9405),y=n.n(b),A=n(5169),w=n.n(A),_=n(9548),x=n.n(_),k=(n(6097),n(3249)),C=n.n(k),S=(n(6030),n(5004)),E=n.n(S);n(9410),n(8609);function T(e){var t="luna-".concat(e,"-");function n(e){return m()(y()(e).split(/\s+/),(function(e){return C()(e,t)?e:e.replace(/[\w-]+/,(function(e){return"".concat(t).concat(e)}))})).join(" ")}return function(e){if(/<[^>]*>/g.test(e))try{var t=x().parse(e);return N(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),x().stringify(t)}catch(t){return n(e)}return n(e)}}function N(e,t){for(var n=0,o=e.length;n2&&void 0!==arguments[2]?arguments[2]:{}).theme,u=void 0===s?"light":s;return(0,a.A)(this,t),o=function(e,t,n){return t=(0,l.A)(t),(0,c.A)(e,H()?Reflect.construct(t,n||[],(0,l.A)(e).constructor):t.apply(e,n))}(this,t),o.subComponents=[],o.theme="",o.onThemeChange=function(e){"auto"===o.options.theme&&o.setTheme(e)},o.compName=i,o.c=T(i),o.options={},o.container=e,o.$container=v()(e),o.$container.addClass(["luna-".concat(i),o.c("platform-".concat((r=E()(),"os x"===r?"mac":r)))]),o.on("changeOption",(function(e,t){if("theme"===e&&t){var n=t;"auto"===t&&(n=L().get()),o.setTheme(n),j()(o.subComponents,(function(e){return e.setOption("theme",t)}))}})),L().on("change",o.onThemeChange),o.setOption("theme",u),o}return(0,d.A)(t,e),(0,s.A)(t,[{key:"destroy",value:function(){var e=this;this.destroySubComponents();var t=this.$container,n=t.attr("class");j()(n.split(/\s+/),(function(n){P()(n,"luna-".concat(e.compName))&&t.rmClass(n)})),t.html(""),this.emit("destroy"),this.removeAllListeners(),L().off("change",this.onThemeChange)}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,j()(r,(function(e,t){var r=o[t];o[t]=e,e!==r&&n.emit("changeOption",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){F()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){j()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};D()(e,t),I()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}},{key:"setTheme",value:function(e){var t=this.c,n=this.$container;this.theme&&n.rmClass(t("theme-".concat(this.theme))),n.addClass(t("theme-".concat(e))),this.theme=e}}])}(f()),q=n(5773),Q=n.n(q),U=n(5241),W=n.n(U),J=n(6741),K=n.n(J);function V(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(V=function(){return!!e})()}e=n.hmd(e);var Z=function(e){function t(e){var n,o,r,i,s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return(0,a.A)(this,t),o=this,r=t,i=[e,{compName:"modal"},s],r=(0,l.A)(r),(n=(0,c.A)(o,V()?Reflect.construct(r,i||[],(0,l.A)(o).constructor):r.apply(o,i))).render=function(){var e=n,t=e.options,o=e.c,r=e.$body;t.title?(r.rmClass(o("no-title")),n.$title.text(t.title)):r.addClass(o("no-title")),t.footer?(r.rmClass(o("no-footer")),n.$footer.html("").append(t.footer)):r.addClass(o("no-footer")),t.showClose?n.$close.show():n.$close.hide(),n.$body.css("width",t.width+"px"),n.renderContent()},n.hide(),n.initOptions(s,{title:"",content:"",footer:"",showClose:!0,width:oe()}),n.initTpl(),n.$title=n.find(".title"),n.$content=n.find(".content"),n.$body=n.find(".body"),n.$footer=n.find(".footer"),n.$close=n.find(".icon-close"),n.bindEvent(),n}return(0,d.A)(t,e),(0,s.A)(t,[{key:"show",value:function(){this.render(),this.$container.rmClass(this.c("hidden"))}},{key:"hide",value:function(){this.$container.addClass(this.c("hidden"))}},{key:"destroy",value:function(){var e,n,o,r,i;(e=t,n="destroy",o=this,r=3,i=(0,u.A)((0,l.A)(1&r?e.prototype:e),n,o),2&r&&"function"==typeof i?function(e){return i.apply(o,e)}:i)([]),this.$container.rmClass(this.c("hidden"))}},{key:"renderContent",value:function(){this.$content.html("").append(this.options.content)}},{key:"bindEvent",value:function(){var e=this;this.$body.on("click",this.c(".icon-close"),(function(){return e.hide()})),this.on("changeOption",this.render)}},{key:"initTpl",value:function(){this.$container.html(this.c(Q()(Y||(Y=(0,i.A)(['\n
\n \n
\n
\n \n
\n '])))))}}],[{key:"alert",value:function(e){return new Promise((function(n){var o=te(),i=o.c;o.setOption({title:"",content:e,width:oe(),footer:ne((0,r.A)({},t.i18n.t("ok"),{type:"primary",onclick:function(){o.hide(),n()}}),i)}),o.show()}))}},{key:"confirm",value:function(e){return new Promise((function(n){var o=te(),i=o.c;o.setOption({title:"",content:e,width:oe(),footer:ne((0,r.A)((0,r.A)({},t.i18n.t("cancel"),{type:"secondary",onclick:function(){o.hide(),n(!1)}}),t.i18n.t("ok"),{type:"primary",onclick:function(){o.hide(),n(!0)}}),i)}),o.show()}))}},{key:"prompt",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return new Promise((function(o){var i=te(),a=i.c,s=W()("input"+a(".input"),{value:n});function c(){i.hide(),o(s.value)}v()(s).on("keypress",(function(e){"Enter"===(e=e.origEvent).key&&c()})),i.setOption({title:e,content:s,width:oe(),footer:ne((0,r.A)((0,r.A)({},t.i18n.t("cancel"),{type:"secondary",onclick:function(){i.hide(),o(null)}}),t.i18n.t("ok"),{type:"primary",onclick:c}),a)}),i.show();var l=s.value.length;s.setSelectionRange(l,l),s.focus()}))}},{key:"setContainer",value:function(e){ee=e}}])}($);Z.i18n=new(K())("zh-CN"!==navigator.language?"en-US":"zh-CN",{"en-US":{ok:"OK",cancel:"Cancel"},"zh-CN":{ok:"确定",cancel:"取消"}});var X=null,ee=null;function te(){return ee||(ee=W()("div"),document.body.append(ee)),X||(X=new Z(ee,{showClose:!1})),X}function ne(e,t){var n=m()(e,(function(e,n){return W()(t(".button")+t("."+e.type),{onclick:e.onclick},n)}));return W().apply(void 0,[t(".button-group"),{}].concat((0,o.A)(n)))}function oe(){return window.innerWidth<500?window.innerWidth-32:500}(function(e,t){try{e.exports=t,e.exports.default=t}catch(e){}})(e,Z)},1947:function(e,t,n){var o=n(3145);t={getItem:function(e){return(i[e]?r[e]:this[e])||null},setItem:function(e,t){i[e]?r[e]=t:this[e]=t},removeItem:function(e){i[e]?delete r[e]:delete this[e]},key:function(e){var t=a();return e>=0&&e-1&&n[e].splice(o,1),this}},once:function(e,t){return this.on(e,s(t)),this},emit:function(e){var t=this;if(r(this._events,e)){var n=a(arguments,1),o=c(this._events[e]);return i(o,(function(e){return e.apply(t,n)}),this),this}},removeAllListeners:function(e){return e?delete this._events[e]:this._events={},this}},{mixin:function(e){i(["on","off","once","emit","removeAllListeners"],(function(n){e[n]=t.prototype[n]})),e._events=e._events||{}}}),e.exports=t},2284:function(e,t,n){"use strict";function o(e){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o(e)}n.d(t,{A:function(){return o}})},2388:function(e,t,n){"use strict";n.d(t,{A:function(){return Le}});var o=n(7528),r=n(3029),i=n(2901),a=n(388),s=n(3954),c=n(991),l=n(5361),u=n(3693),d=n.n(u),h=n(5773),f=n.n(h),p=n(2263),v=n.n(p),g=n(3915),m=n.n(g),b=n(9405),y=n.n(b),A=n(5169),w=n.n(A),_=n(9548),x=n.n(_),k=(n(6097),n(3249)),C=n.n(k),S=n(6030),E=n.n(S),T=n(5004),N=n.n(T),O=(n(9410),n(8609)),j=n.n(O);function M(e){var t="luna-".concat(e,"-");function n(e){return m()(y()(e).split(/\s+/),(function(e){return C()(e,t)?e:e.replace(/[\w-]+/,(function(e){return"".concat(t).concat(e)}))})).join(" ")}return function(e){if(/<[^>]*>/g.test(e))try{var t=x().parse(e);return I(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),x().stringify(t)}catch(t){return n(e)}return n(e)}}function I(e,t){for(var n=0,o=e.length;n2&&void 0!==arguments[2]?arguments[2]:{}).theme,u=void 0===l?"light":l;return(0,r.A)(this,t),o=function(e,t,n){return t=(0,s.A)(t),(0,a.A)(e,W()?Reflect.construct(t,n||[],(0,s.A)(e).constructor):t.apply(e,n))}(this,t),o.subComponents=[],o.theme="",o.onThemeChange=function(e){"auto"===o.options.theme&&o.setTheme(e)},o.compName=c,o.c=M(c),o.options={},o.container=e,o.$container=d()(e),o.$container.addClass(["luna-".concat(c),o.c("platform-".concat((i=N()(),"os x"===i?"mac":i)))]),o.on("changeOption",(function(e,t){if("theme"===e&&t){var n=t;"auto"===t&&(n=q().get()),o.setTheme(n),F()(o.subComponents,(function(e){return e.setOption("theme",t)}))}})),q().on("change",o.onThemeChange),o.setOption("theme",u),o}return(0,l.A)(t,e),(0,i.A)(t,[{key:"destroy",value:function(){var e=this;this.destroySubComponents();var t=this.$container,n=t.attr("class");F()(n.split(/\s+/),(function(n){U()(n,"luna-".concat(e.compName))&&t.rmClass(n)})),t.html(""),this.emit("destroy"),this.removeAllListeners(),q().off("change",this.onThemeChange)}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,F()(r,(function(e,t){var r=o[t];o[t]=e,e!==r&&n.emit("changeOption",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){Y()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){F()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};P()(e,t),L()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}},{key:"setTheme",value:function(e){var t=this.c,n=this.$container;this.theme&&n.rmClass(t("theme-".concat(this.theme))),n.addClass(t("theme-".concat(e))),this.theme=e}}])}(v()),V=n(5902),Z=n.n(V),X=n(5241),ee=n.n(X),te=n(2561),ne=n.n(te),oe=n(2708),re=n.n(oe),ie=n(8971),ae=n.n(ie),se=n(4095),ce=n.n(se),le=n(5865),ue=n.n(le),de=n(1532),he=n.n(de),fe=n(4236),pe=n.n(fe),ve=n(3957),ge=n.n(ve),me=n(1976),be=n.n(me),ye=n(6214),Ae=n.n(ye),we=n(1738),_e=n.n(we),xe=n(96),ke=n.n(xe),Ce=n(6026),Se=n.n(Ce),Ee=n(3539),Te=n.n(Ee),Ne=n(8785),Oe=n.n(Ne),je=n(6024),Me=n.n(je),Ie=n(3981),ze=n.n(Ie),De=n(5546),Be=n.n(De);function Fe(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(Fe=function(){return!!e})()}e=n.hmd(e);var Re=d()(document),Le=function(e){function t(e,n){var o,i,c,l;(0,r.A)(this,t),i=this,c=t,l=[e,{compName:"data-grid"},n],c=(0,s.A)(c),(o=(0,a.A)(i,Fe()?Reflect.construct(c,l||[],(0,s.A)(i).constructor):c.apply(i,l))).resizeIdx=0,o.resizeStartX=0,o.resizeStartLeft=0,o.resizeDeltaX=0,o.nodes=[],o.displayNodes=[],o.colWidthsInitialized=!1,o.colMap={},o.selectedNode=null,o.isAscending=!0,o.sorted=!1,o.colWidths=[],o.spaceHeight=0,o.topSpaceHeight=0,o.lastScrollTop=0,o.lastTimestamp=0,o.speedToleranceFactor=100,o.maxSpeedTolerance=2e3,o.minSpeedTolerance=100,o.scrollTimer=null,o.onResizeColMove=function(e){var t=o,n=t.resizeIdx,r=t.$resizers,i=t.colWidths,a=t.$colgroup,s=z("x",e=e.origEvent)-o.resizeStartX,c=i[n],l=i[n+1],u=Oe()(24-c,0),h=Te()(l-24,0);s=Se()(s,u,h),a.each((function(){var e=d()(this).find("col");e.eq(n).css("width",c+s+"px"),e.eq(n+1).css("width",l-s+"px")})),o.resizeDeltaX=s;var f=o.resizeStartLeft+s;r.eq(n).css("left","".concat(f,"px"))},o.onResizeColEnd=function(e){o.onResizeColMove(e);var t=o,n=t.c,r=t.colWidths,i=t.resizeIdx,a=t.resizeDeltaX,s=o.options.columns,c=s[i],l=s[i+1],u=r[i]+a,h=u+(r[i+1]-a),f=c.weight+l.weight,p=f*(u/h),v=f-p;c.weight=p,l.weight=v,o.applyColWeights(),d()(document.body).rmClass(n("resizing")),Re.off(Be()("move"),o.onResizeColMove),Re.off(Be()("up"),o.onResizeColEnd)},o.onScroll=function(){var e=o.dataContainer,t=e.scrollHeight,n=e.clientHeight,r=e.scrollTop;if(!(r<=0||n+r>t)){var i=o.lastScrollTop,a=o.lastTimestamp,s=ze()(),c=s-a,l=r-i,u=Math.abs(l/c)*o.speedToleranceFactor;c>1e3&&(u=1e3),u>o.maxSpeedTolerance&&(u=o.maxSpeedTolerance),ur+n+h||(o.renderData({topTolerance:2*d,bottomTolerance:2*h}),o.scrollTimer&&clearTimeout(o.scrollTimer),o.scrollTimer=setTimeout((function(){o.renderData()}),100))}},o.renderData=ue()((function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.topTolerance,n=void 0===t?500:t,r=e.bottomTolerance,i=void 0===r?500:r;o.sortId&&!o.sorted&&o.sortNodes(o.sortId,o.isAscending);for(var a=o,s=a.dataContainer,c=a.displayNodes,l=a.tableBody,u=s.scrollTop,d=u-n,h=u+s.clientHeight+i,f=0,p=0,v=c.length,g=[],m=0;md?(0===g.length&&Me()(m)&&(g.push(c[m-1]),f-=20),g.push(b)):p1&&void 0!==arguments[1]?arguments[1]:{};P()(t,{selectable:this.options.selectable});var n=new Ge(this,e,t);this.nodes.push(n);var o=this.filterNode(n);return o&&this.displayNodes.push(n),(this.sortId||o)&&(this.sortId&&(this.sorted=!1),this.renderData()),this.updateHeight(),n}},{key:"setData",value:function(e,t){var n=this,o=m()(e,(function(e){return Ae()(e)?(P()(e[1],{selectable:n.options.selectable}),e):[e,{selectable:n.options.selectable}]}));if(t){var r={};F()(this.nodes,(function(e){r[e.data[t]]=e}));var i=[],a=[];F()(o,(function(e){var o,s=e[0][t];r[s]?((o=r[s]).data=e[0],o.render()):o=new Ge(n,e[0],e[1]),i.push(o),n.filterNode(o)&&a.push(o)})),this.selectedNode&&!C()(i,this.selectedNode)&&this.selectNode(null),this.nodes=i,this.displayNodes=a}else this.clearData(),F()(o,(function(e){var t=new Ge(n,e[0],e[1]);n.nodes.push(t),n.filterNode(t)&&n.displayNodes.push(t)}));this.sortId&&(this.sorted=!1),this.renderData(),this.updateHeight()}},{key:"clear",value:function(){this.clearData(),this.renderData(),this.updateHeight()}},{key:"fit",value:function(){if(!j()(this.container)){var e=this.$container.parent().get(0),t=window.getComputedStyle(e),n=e.clientHeight-D(t.paddingTop)-D(t.paddingBottom);this.setOption({minHeight:n,maxHeight:n})}}},{key:"clearData",value:function(){this.nodes=[],this.displayNodes=[],this.selectNode(null)}},{key:"updateHeight",value:function(){var e=this.$fillerRow,t=this.$container,n=this.options,o=n.maxHeight,r=n.minHeight,i=this.$headerRow.offset().height+D(t.css("border-top-width"))+D(t.css("border-bottom-width"));(r-=i)<0&&(r=0),o-=i;var a=this.displayNodes.length,s=0;a>0&&(s=20*a),s>r?e.hide():e.show(),s=o&&(s=o),this.$dataContainer.css({height:s})}},{key:"selectNode",value:function(e){(pe()(e)||null!=e&&e.selectable)&&this.selectedNode!==e&&(this.selectedNode&&(this.selectedNode.deselect(),this.selectedNode=null,pe()(e)&&this.emit("deselect")),pe()(e)||(this.selectedNode=e,e.select(),this.emit("select",e)))}},{key:"onResizeColStart",value:function(e){var t=this.c,n=this.resizeIdx,o=this.$resizers;e.stopPropagation(),e.preventDefault(),e=e.origEvent,this.resizeStartX=z("x",e),this.resizeStartLeft=D(o.eq(n).css("left")),d()(document.body).addClass(t("resizing")),Re.on(Be()("move"),this.onResizeColMove),Re.on(Be()("up"),this.onResizeColEnd)}},{key:"bindEvent",value:function(){var e=this,t=this.c,n=this.$headerRow,o=this.$tableBody,r=this.$resizers,i=this.$dataContainer;this.resizeSensor.addListener(this.onResize),i.on("scroll",this.onScroll);var a=this;o.on("click",t(".node"),(function(e){var t=this;a.selectNode(this.dataGridNode),setTimeout((function(){t.hasDoubleClick||a.emit("click",e.origEvent,t.dataGridNode)}),200)})).on("dblclick",t(".node"),(function(e){var t=this;e.stopPropagation(),this.hasDoubleClick=!0,a.emit("dblclick",e.origEvent,this.dataGridNode),setTimeout((function(){t.hasDoubleClick=!1}),300)})).on("contextmenu",t(".node"),(function(e){e.preventDefault(),e.stopPropagation(),a.selectNode(this.dataGridNode),a.emit("contextmenu",e.origEvent,this.dataGridNode)})),n.on("click",t(".sortable"),(function(e){e.stopPropagation();var o=d()(this),r=o.data("id"),i="descending"!==o.data("order");o.data("order",i?"descending":"ascending"),n.find(t(".icon-caret-up")).hide(),n.find(t(".icon-caret-down")).hide();var s=o.find(t(".icon-caret-up")),c=o.find(t(".icon-caret-down"));i?s.show():c.show(),a.sortNodes(r,i),a.renderData(),n.find("th").each((function(){var e=d()(this);e.data("id")!==r&&e.rmAttr("data-order")}))})),r.on(Be()("down"),(function(e){var t=d()(this);a.resizeIdx=E()(t.data("idx")),a.onResizeColStart(e)})),this.on("changeOption",(function(t){switch(t){case"minHeight":case"maxHeight":e.updateHeight();break;case"filter":e.displayNodes=[],F()(e.nodes,(function(t){e.filterNode(t)&&e.displayNodes.push(t)})),e.selectedNode&&!e.filterNode(e.selectedNode)&&e.selectNode(null),e.renderData(),e.updateHeight()}}))}},{key:"sortNodes",value:function(e,t){var n=this.colMap[e].comparator||he().comparator;function o(o,r){var i=o.data[e],a=r.data[e];return re()(i)&&(i=i.innerText),re()(a)&&(a=a.innerText),t?n(i,a):n(a,i)}this.nodes.sort(o),this.displayNodes.sort(o),this.sorted=!0,this.sortId=e,this.isAscending=t}},{key:"updateWeights",value:function(){var e=this.container,t=this.$headerRow,n=this.options.columns,o=e.offsetWidth;if(!this.colWidthsInitialized&&o){for(var r=0,i=n.length;r'),this.colWidths[u]=h}t.html(s),this.positionResizers()}}},{key:"positionResizers",value:function(){for(var e=this.colWidths,t=[],n=e.length-1,o=0;o\n ').concat(r,'\n \n \n ')):t+="".concat(r,""),n+=""})),this.$headerRow.html(t),this.$fillerRow.html(n)}},{key:"renderResizers",value:function(){for(var e="",t=this.options.columns.length-1,n=0;n'));this.$container.append(e),this.$resizers=this.find(".resizer")}},{key:"initTpl",value:function(){this.$container.html(this.c(f()(J||(J=(0,o.A)(['\n
\n \n \n \n \n \n
\n
\n
\n
\n \n \n \n \n \n
\n
\n
\n '])))))}}])}(K),Ge=function(){return(0,i.A)((function e(t,n,o){(0,r.A)(this,e),this.container=ee()("tr"),this.selectable=!1,this.container.dataGridNode=this,this.$container=d()(this.container),this.$container.addClass(t.c("node")),this.dataGrid=t,this.data=n,o.selectable&&(this.selectable=o.selectable,this.$container.addClass(t.c("selectable"))),this.render()}),[{key:"text",value:function(){return this.$container.text()}},{key:"select",value:function(){this.$container.addClass(this.dataGrid.c("selected"))}},{key:"deselect",value:function(){this.$container.rmClass(this.dataGrid.c("selected"))}},{key:"render",value:function(){var e=this.data,t=this.$container,n=this.container,o=this.dataGrid.getOption("columns");t.html(""),F()(o,(function(t){var o=ee()("td"),r=e[t.id];ae()(r)||(re()(r)?o.appendChild(r):o.innerText=ne()(r)),n.appendChild(o)}))}}])}();(function(e,t){try{e.exports=t,e.exports.default=t}catch(e){}})(e,Le)},2455:function(e,t){t=function(e){return e},e.exports=t},2480:function(e,t,n){"use strict";var o=this&&this.__createBinding||(Object.create?function(e,t,n,o){void 0===o&&(o=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,o,r)}:function(e,t,n,o){void 0===o&&(o=n),e[o]=t[n]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)"default"!==n&&Object.prototype.hasOwnProperty.call(e,n)&&o(t,e,n);return r(t,e),t},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.enable=function(){if(x)return;var e=(0,h.default)("div",{class:"__chobitsu-hide__",style:{all:"initial"}});c=(0,d.default)(e),document.documentElement.appendChild(e);var t=null,n=null;e.attachShadow?n=e.attachShadow({mode:"open"}):e.createShadowRoot&&(n=e.createShadowRoot());if(n){var o=document.createElement("style");o.textContent=S,o.type="text/css",n.appendChild(o),t=document.createElement("div"),n.appendChild(t)}else t=document.createElement("div"),e.appendChild(t),_||((0,f.default)(S),_=!0);s=new A.default(t,{monitorResize:(0,b.default)(m.default.ResizeObserver),showInfo:k}),window.addEventListener("resize",R),x=!0},t.disable=function(){s.destroy(),c.remove(),window.removeEventListener("resize",R),x=!1},t.highlightNode=E,t.hideHighlight=T,t.setShowViewportSizeOnResize=function(e){N=e.show},t.setInspectMode=function(e){O=e.highlightConfig,j=e.mode};var s,c,l=n(9893),u=n(6192),d=a(n(3693)),h=a(n(5241)),f=a(n(3048)),p=a(n(5651)),v=a(n(8105)),g=a(n(8665)),m=a(n(5169)),b=a(n(9e3)),y=a(n(8534)),A=a(n(9196)),w=i(n(2484)),_=!1,x=!1,k=(0,y.default)("clip-path","polygon(50% 0px, 0px 100%, 100% 100%)"),C="ontouchstart"in m.default,S=n(7119).replace("/*# sourceMappingURL=luna-dom-highlighter.css.map*/","");function E(e){var t,n=e.nodeId,o=e.highlightConfig,r=e.objectId;n&&(t=(0,l.getNode)(n)),r&&(t=w.getObj(r)),1!==t.nodeType&&3!==t.nodeType||((0,p.default)(o,{contentColor:"transparent",paddingColor:"transparent",borderColor:"transparent",marginColor:"transparent"}),k||(0,v.default)(o,{showInfo:!1}),s.highlight(t,o))}function T(){s.hide()}var N=!1;var O={},j="none";function M(e){if(C){var t=e.touches[0]||e.changedTouches[0];return document.elementFromPoint(t.clientX,t.clientY)}return document.elementFromPoint(e.clientX,e.clientY)}var I=-1;function z(e){if("none"!==j){var t=M(e);if(t&&(0,l.isValidNode)(t)){var n=(0,l.getNodeId)(t);n||(n=(0,u.pushNodesToFrontend)(t)),E({nodeId:n,highlightConfig:O}),n!==I&&(g.default.trigger("Overlay.nodeHighlightRequested",{nodeId:n}),I=n)}}}function D(e){if("none"!==j){e.preventDefault(),e.stopImmediatePropagation();var t=M(e);g.default.trigger("Overlay.inspectNodeRequested",{backendNodeId:(0,l.getNodeId)(t)}),I=-1,T()}}function B(e,t){document.documentElement.addEventListener(e,t,!0)}C?(B("touchstart",z),B("touchmove",z),B("touchend",D)):(B("mousemove",z),B("mouseout",(function(){"none"!==j&&T()})),B("click",D));var F=(0,h.default)("div",{class:"__chobitsu-hide__",style:{position:"fixed",right:0,top:0,background:"#fff",fontSize:13,opacity:.5,padding:"4px 6px"}});function R(){N&&(G.text("".concat(window.innerWidth,"px × ").concat(window.innerHeight,"px")),L?clearTimeout(L):document.documentElement.appendChild(F),L=setTimeout((function(){G.remove(),L=null}),1e3))}var L,G=(0,d.default)(F)},2484:function(e,t,n){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.clear=function(){A.clear(),w.clear(),_.clear()},t.wrap=S,t.getObj=E,t.releaseObj=function(e){var t=E(e);w.delete(t),_.delete(e),A.delete(e)},t.getProperties=function(e){for(var t=e.accessorPropertiesOnly,n=e.objectId,o=e.ownProperties,i=e.generatePreview,a=[],c={prototype:!o,unenumerable:!0,symbol:!t},l=A.get(n),h=_.get(n),f=(0,v.default)(l,c),p=(0,m.default)(l),w=0,k=f.length;wT&&(a=T,o=!0);for(var s=0;sT){o=!0;break}l.push({key:N(p),value:N(e.get(p))}),s++,p=h.next().value}n.entries=l}else if((0,d.default)(e)){var v=[],g=(s=0,e.keys());for(p=g.next().value;p;){if(s>T){o=!0;break}v.push({value:N(p)}),s++,p=g.next().value}n.entries=v}return n.overflow=o,n}function O(e,t){var n=M(t);n.name=e;var o,i=n.subtype;return o="object"===n.type?"null"===i?"null":"array"===i?"Array(".concat(t.length,")"):"map"===i?"Map(".concat(t.size,")"):"set"===i?"Set(".concat(t.size,")"):(0,y.getType)(t,!1):(0,r.default)(t),n.value=o,n}function j(e,t){void 0===t&&(t=e);var n=M(e),o=n.type,i=n.subtype;return"string"===o?e:"number"===o||"symbol"===o?(0,r.default)(e):"function"===o?(0,p.default)(e):"array"===i?"Array(".concat(e.length,")"):"map"===i?"Map(".concat(t.size,")"):"set"===i?"Set(".concat(t.size,")"):"regexp"===i?(0,r.default)(e):"error"===i?e.stack:"internal#entry"===i?e.name?'{"'.concat((0,r.default)(e.name),'" => "').concat((0,r.default)(e.value),'"}'):'"'.concat((0,r.default)(e.value),'"'):(0,y.getType)(e,!1)}function M(e){var t=typeof e,n="object";if(e instanceof I)n="internal#entry";else if((0,i.default)(e))n="null";else if((0,a.default)(e))n="array";else if((0,h.default)(e))n="regexp";else if((0,l.default)(e))n="error";else if((0,u.default)(e))n="map";else if((0,d.default)(e))n="set";else try{(0,c.default)(e)&&(n="node")}catch(e){}return{type:t,subtype:n}}var I=function(e,t){t&&(this.name=t),this.value=e};function z(e){return e instanceof I||!!(e[0]&&e[0]instanceof I)}},2508:function(e,t,n){var o=n(6186),r=n(2561),i=/{{(.*?)}}/g;t=function(e,t){return e.replace(i,(function(e,n){return r(o(t,n))}))},e.exports=t},2510:function(e,t){t=function(e,t){return t=null==t?e.length-1:+t,function(){var n,o=Math.max(arguments.length-t,0),r=new Array(o);for(n=0;n]*>/g.test(e))try{var t=C().parse(e);return j(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),C().stringify(t)}catch(t){return n(e)}return n(e)}}function j(e,t){for(var n=0,o=e.length;n2&&void 0!==arguments[2]?arguments[2]:{}).theme,d=void 0===u?"light":u;return(0,o.A)(this,t),r=function(e,t,n){return t=(0,a.A)(t),(0,i.A)(e,$()?Reflect.construct(t,n||[],(0,a.A)(e).constructor):t.apply(e,n))}(this,t),r.subComponents=[],r.theme="",r.onThemeChange=function(e){"auto"===r.options.theme&&r.setTheme(e)},r.compName=c,r.c=O(c),r.options={},r.container=e,r.$container=l()(e),r.$container.addClass(["luna-".concat(c),r.c("platform-".concat((s=N()(),"os x"===s?"mac":s)))]),r.on("changeOption",(function(e,t){if("theme"===e&&t){var n=t;"auto"===t&&(n=P().get()),r.setTheme(n),I()(r.subComponents,(function(e){return e.setOption("theme",t)}))}})),P().on("change",r.onThemeChange),r.setOption("theme",d),r}return(0,s.A)(t,e),(0,r.A)(t,[{key:"destroy",value:function(){var e=this;this.destroySubComponents();var t=this.$container,n=t.attr("class");I()(n.split(/\s+/),(function(n){Y()(n,"luna-".concat(e.compName))&&t.rmClass(n)})),t.html(""),this.emit("destroy"),this.removeAllListeners(),P().off("change",this.onThemeChange)}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,I()(r,(function(e,t){var r=o[t];o[t]=e,e!==r&&n.emit("changeOption",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){L()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){I()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};F()(e,t),D()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}},{key:"setTheme",value:function(e){var t=this.c,n=this.$container;this.theme&&n.rmClass(t("theme-".concat(this.theme))),n.addClass(t("theme-".concat(e))),this.theme=e}}])}(m()),Q=n(8971),U=n.n(Q);function W(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(W=function(){return!!e})()}e=n.hmd(e);var J=function(e){function t(e){var n,r,s,c,l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return(0,o.A)(this,t),r=this,s=t,c=[e,{compName:"notification"},l],s=(0,a.A)(s),(n=(0,i.A)(r,W()?Reflect.construct(s,c||[],(0,a.A)(r).constructor):s.apply(r,c))).notifications=[],n.initOptions(l,{position:{x:"right",y:"bottom"},inline:!1,duration:2e3}),n.options.inline||n.$container.addClass(n.c("full")),n.initTpl(),n}return(0,s.A)(t,e),(0,r.A)(t,[{key:"notify",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};U()(n.duration)&&(n.duration=this.options.duration);var o=new K(this,e,{icon:n.icon||"none"});this.notifications.push(o),this.add(o),setTimeout((function(){return t.remove(o.id)}),n.duration)}},{key:"dismissAll",value:function(){for(var e=this.notifications,t=e[0];t;)this.remove(t.id),t=e[0]}},{key:"add",value:function(e){this.container.appendChild(e.container)}},{key:"remove",value:function(e){var t=this.notifications,n=f()(t,(function(t){return t.id===e}));if(n){n.destroy();var o=t.indexOf(n);t.splice(o,1)}}},{key:"initTpl",value:function(){var e=this.$container,t=this.options.position,n=t.x,o=t.y,r="flex-end",i="flex-end";switch(n){case"center":i="center";break;case"left":i="flex-start"}"top"===o&&(r="flex-start"),e.attr("style","justify-content: ".concat(r,"; align-items: ").concat(i))}}])}(q),K=function(){return(0,r.A)((function e(t,n,r){(0,o.A)(this,e),this.container=v()("div"),this.$container=l()(this.container),this.notification=t,this.content=n,this.id=d()("luna-notification-"),this.$container.attr({id:this.id,class:t.c("item ".concat("bottom"===t.getOption("position").y?"lower":"upper"))}),this.initTpl(r.icon)}),[{key:"destroy",value:function(){this.$container.remove()}},{key:"initTpl",value:function(e){var t=e;"success"===e?t="check":"warning"===e&&(t="warn");var n="none"===e?"":'
');this.$container.html(this.notification.c("".concat(n,'
').concat(this.content,"
")))}}])}();(function(e,t){try{e.exports=t,e.exports.default=t}catch(e){}})(e,J)},2561:function(e,t){t=function(e){return null==e?"":e.toString()},e.exports=t},2571:function(e,t,n){var o=n(5693),r=n(9100);t=function(e,t,n){var i=[];return t=o(t,n),r(e,(function(e,n,o){t(e,n,o)&&i.push(e)})),i},e.exports=t},2627:function(e,t,n){"use strict";var o=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.setGlobal=function(e,t){u[e]=t},t.default=function(e){var t;(0,l.default)(u,(function(e,t){window[t]||(window[t]=e)}));try{t=eval.call(window,"(".concat(e,")"))}catch(n){t=eval.call(window,e)}return function(){(0,l.default)(u,(function(e,t){window[t]&&window[t]===e&&delete window[t]}))}(),t};var r=o(n(1738)),i=o(n(4844)),a=o(n(769)),s=o(n(3145)),c=o(n(8862)),l=o(n(9100)),u={copy:function(e){(0,r.default)(e)||(e=JSON.stringify(e,null,2)),(0,i.default)(e)},$:function(e){return document.querySelector(e)},$$:function(e){return(0,a.default)(document.querySelectorAll(e))},$x:function(e){return(0,c.default)(e)},keys:s.default}},2650:function(e,t,n){var o=n(3974);t=function(e){switch(o(e)){case"[object Error]":case"[object DOMException]":return!0;default:return e instanceof Error}},e.exports=t},2693:function(e,t,n){(t=n(6314)(!1)).push([e.id,'._container a,._container abbr,._container acronym,._container address,._container applet,._container article,._container aside,._container audio,._container b,._container big,._container blockquote,._container canvas,._container caption,._container center,._container cite,._container code,._container dd,._container del,._container details,._container dfn,._container dl,._container dt,._container em,._container embed,._container fieldset,._container figcaption,._container figure,._container footer,._container form,._container h1,._container h2,._container h3,._container h4,._container h5,._container h6,._container header,._container hgroup,._container i,._container iframe,._container img,._container ins,._container kbd,._container label,._container legend,._container li,._container mark,._container menu,._container nav,._container object,._container ol,._container output,._container p,._container pre,._container q,._container ruby,._container s,._container samp,._container section,._container small,._container span,._container strike,._container strong,._container sub,._container summary,._container sup,._container table,._container tbody,._container td,._container tfoot,._container th,._container thead,._container time,._container tr,._container tt,._container u,._container ul,._container var,._container video{margin:0;padding:0;border:0;font-size:100%}._container article,._container aside,._container details,._container figcaption,._container figure,._container footer,._container header,._container hgroup,._container menu,._container nav,._container section{display:block}._container body{line-height:1}._container ol,._container ul{list-style:none}._container blockquote,._container q{quotes:none}._container blockquote:after,._container blockquote:before,._container q:after,._container q:before{content:"";content:none}._container table{border-collapse:collapse;border-spacing:0;color:inherit;font-size:1em;font-style:inherit;font-variant:inherit;font-weight:inherit;line-height:inherit;text-decoration:inherit;white-space:inherit}',""]),e.exports=t},2708:function(e,t){t=function(e){return!(!e||1!==e.nodeType)},e.exports=t},2717:function(e,t,n){var o=n(8105),r=n(769),i=n(8009),a=n(6186),s=n(4460);var c=(t=function(e,t){return c.extend(e,t)}).Base=function e(t,n,c){c=c||{};var l=n.className||a(n,"initialize.name")||"";delete n.className;var u=function(){var e=r(arguments);return this.initialize&&this.initialize.apply(this,e)||this};if(!s)try{u=new Function("toArr","return function "+l+"(){var args = toArr(arguments);return this.initialize ? this.initialize.apply(this, args) || this : this;};")(r)}catch(e){}return i(u,t),u.prototype.constructor=u,u.extend=function(t,n){return e(u,t,n)},u.inherits=function(e){i(u,e)},u.methods=function(e){return o(u.prototype,e),u},u.statics=function(e){return o(u,e),u},u.methods(n).statics(c),u}(Object,{className:"Base",callSuper:function(e,t,n){return e.prototype[t].apply(this,n)},toString:function(){return this.constructor.name}});e.exports=t},2767:function(e,t,n){var o=n(1738),r=n(5282);t=function(e){return o(e)?i[e]:u[e]};for(var i={backspace:8,tab:9,enter:13,shift:16,ctrl:17,alt:18,"pause/break":19,"caps lock":20,esc:27,space:32,"page up":33,"page down":34,end:35,home:36,left:37,up:38,right:39,down:40,insert:45,delete:46,windows:91,"right windows":92,"windows menu":93,"numpad *":106,"numpad +":107,"numpad -":109,"numpad .":110,"numpad /":111,"num lock":144,"scroll lock":145,";":186,"=":187,",":188,"-":189,".":190,"/":191,"`":192,"[":219,"\\":220,"]":221,"'":222},a=97;a<123;a++)i[String.fromCharCode(a)]=a-32;for(var s=48;s<58;s++)i[s-48]=s;for(var c=1;c<13;c++)i["f"+c]=c+111;for(var l=0;l<10;l++)i["numpad "+l]=l+96;var u=r(i);e.exports=t},2797:function(e,t,n){var o=n(5693),r=n(5793),i=n(3145);t=function(e,t,n){t=o(t,n);for(var a=!r(e)&&i(e),s=(a||e).length,c=0;c1&&void 0!==arguments[1])||arguments[1];return null===e&&(t="Null"),void 0===e&&(t="Undefined"),r(e)&&(t="NaN"),a(e)&&(t="Buffer"),t||(t=o(e).match(s))&&(t=t[1]),t?n?i(t):t:""};var s=/^\[object\s+(.*?)]$/;e.exports=t},2990:function(e,t){t={encode:function(e){var t,n,r=[],i=e.length,a=i%3;i-=a;for(var s=0;s>18&63]+o[t>>12&63]+o[t>>6&63]+o[63&t]));return i=e.length,1===a?(n=e[i-1],r.push(o[n>>2]),r.push(o[n<<4&63]),r.push("==")):2===a&&(n=(e[i-2]<<8)+e[i-1],r.push(o[n>>10]),r.push(o[n>>4&63]),r.push(o[n<<2&63]),r.push("=")),r.join("")},decode:function(e){var t=e.length,o=0;"="===e[t-2]?o=2:"="===e[t-1]&&(o=1);var r,i,a,s,c,l,u,d=new Array(3*t/4-o);for(t=o>0?t-4:t,r=0,i=0;r>16&255,d[i++]=h>>8&255,d[i++]=255&h}return 2===o?(u=n[e.charCodeAt(r)]<<2|n[e.charCodeAt(r+1)]>>4,d[i++]=255&u):1===o&&(u=n[e.charCodeAt(r)]<<10|n[e.charCodeAt(r+1)]<<4|n[e.charCodeAt(r+2)]>>2,d[i++]=u>>8&255,d[i++]=255&u),d}};for(var n=[],o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",r=0,i=o.length;r-1:(i(e)||(e=a(e)),o(e,t)>=0)},e.exports=t},3270:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return g}});var o={a:7,c:6,h:1,l:2,m:2,q:4,s:4,t:2,v:1,z:0},r=/([astvzqmhlc])([^astvzqmhlc]*)/gi,i=/-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/gi;var a=function(e){var t=[],n=String(e).trim();return"M"!==n[0]&&"m"!==n[0]||n.replace(r,(function(e,n,r){var a=n.toLowerCase(),s=function(e){var t=e.match(i);return t?t.map(Number):[]}(r),c=n;if("m"===a&&s.length>2&&(t.push([c].concat(s.splice(0,2))),a="l",c="m"===c?"l":"L"),s.length=o[a]&&s.length&&o[a];)t.push([c].concat(s.splice(0,o[a])));return""})),t};function s(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,o=new Array(t);n1&&(y*=l=Math.sqrt(l),A*=l),u=y*y*A*A,f=y*y*s.y*s.y+A*A*s.x*s.x,h(k={x:y*s.y/A,y:-A*s.x/y},i!==r?Math.sqrt((u-f)/f)||0:-Math.sqrt((u-f)/f)||0),o=Math.atan2((s.y-k.y)/A,(s.x-k.x)/y),n=Math.atan2(-(s.y+k.y)/A,-(s.x+k.x)/y),d(k,c),O=k,j=(a.x+z.x)/2,M=(a.y+z.y)/2,O.x+=j,O.y+=M,e.save(),e.translate(k.x,k.y),e.rotate(c),e.scale(y,A),e.arc(0,0,1,o,n,!i),e.restore();break;case"C":C=B[3],S=B[4],p=B[5],g=B[6],e.bezierCurveTo(B[1],B[2],C,S,p,g);break;case"c":e.bezierCurveTo(B[1]+p,B[2]+g,B[3]+p,B[4]+g,B[5]+p,B[6]+g),C=B[3]+p,S=B[4]+g,p+=B[5],g+=B[6];break;case"S":null!==C&&null!==S||(C=p,S=g),e.bezierCurveTo(2*p-C,2*g-S,B[1],B[2],B[3],B[4]),C=B[1],S=B[2],p=B[3],g=B[4];break;case"s":null!==C&&null!==S||(C=p,S=g),e.bezierCurveTo(2*p-C,2*g-S,B[1]+p,B[2]+g,B[3]+p,B[4]+g),C=B[1]+p,S=B[2]+g,p+=B[3],g+=B[4];break;case"Q":E=B[1],T=B[2],p=B[3],g=B[4],e.quadraticCurveTo(E,T,p,g);break;case"q":E=B[1]+p,T=B[2]+g,p+=B[3],g+=B[4],e.quadraticCurveTo(E,T,p,g);break;case"T":null!==E&&null!==T||(E=p,T=g),E=2*p-E,T=2*g-T,p=B[1],g=B[2],e.quadraticCurveTo(E,T,p,g);break;case"t":null!==E&&null!==T||(E=p,T=g),E=2*p-E,T=2*g-T,p+=B[1],g+=B[2],e.quadraticCurveTo(E,T,p,g);break;case"z":case"Z":p=I.x,g=I.y,I=void 0,e.closePath();break;case"AC":p=B[1],g=B[2],b=B[3],o=B[4],n=B[5],N=B[6],e.arc(p,g,b,o,n,N);break;case"AT":v=B[1],m=B[2],p=B[3],g=B[4],b=B[5],e.arcTo(v,m,p,g,b);break;case"E":p=B[1],g=B[2],y=B[3],A=B[4],c=B[5],o=B[6],n=B[7],N=B[8],e.save(),e.translate(p,g),e.rotate(c),e.scale(y,A),e.arc(0,0,1,o,n,N),e.restore();break;case"R":p=B[1],g=B[2],w=B[3],_=B[4],I={x:p,y:g},e.rect(p,g,w,_)}z.x=p,z.y=g}}},p=a,v=f;"undefined"!=typeof window&&v(window);var g={path2dPolyfill:v,parsePath:p}},3277:function(e,t,n){(t=n(6314)(!1)).push([e.id,'@font-face{font-family:luna-data-grid-icon;src:url(\'data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAScAAsAAAAAB4wAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAAFwAAACGIRYl5k9TLzIAAAFkAAAAPQAAAFZLxUkYY21hcAAAAaQAAADLAAACXsU3J5xnbHlmAAACcAAAACUAAAAwNxN2HmhlYWQAAAKYAAAALgAAADZzjr4QaGhlYQAAAsgAAAAYAAAAJAFyANhobXR4AAAC4AAAABAAAAA8AZAAAGxvY2EAAALwAAAAEAAAACAAnACobWF4cAAAAwAAAAAfAAAAIAEaAA9uYW1lAAADIAAAASkAAAIWm5e+CnBvc3QAAARMAAAATQAAAG/8EX8xeJxjYGRgYOBiMGCwY2BycfMJYeDLSSzJY5BiYGGAAJA8MpsxJzM9kYEDxgPKsYBpDiA2A9NMDGwMMkAWF1CGFchmB4pxAnncDDxAOQ4kUV4GPqA6RgZmAE91Bj94nGNgZJBmnMDAysDAUMfQAyRloHQCAyeDMQMDEwMrMwNWEJDmmsJwgEH3IxPDCSBXCEwyMDCCCABbKQhrAAAAeJzNkksKwjAQhr+kvqpVxIUL8Qh6KFG3KtLidVx5Bq/VE+g/ySCIILhzhq+Qv8lkHgG6QCFWogPhRsDsKjUkvWCY9A611jOmUiJrNuw5cabh0sbHQ/9M23KQVksLSXu3oPPmcxbypRwGilxQ0qPSTRNl1GfMSHujDvQ+Yny3wY/7SXUX5eueaphSsAz+xar0vftqgnU6Y9VuHE1P3c/YRHdOKfaOVXlwLOrR0YQ1y4zFPzv2OmqnLxpnLC6O+tSGjL2YNmaITyYUHqgAeJxjYGQAgZUM0xmYGBjMlcVXNjtO9wCKoImbA8X9geIAqRwH2QAAAHicY2BkYGAA4hwJ4Yp4fpuvDNwMJ4ACUZyP9zUgaCBYyTAdSHIwMIE4ABioCdgAAHicY2BkYGA4wcAAJ1cyMDKgAn4AOLICS3icY2AAghNQTCIAAFMMAZF4nGNgAAIeBglcEAARPAFFeJxjYGRgYOBnYGYA0QwMTEDMBYQMDP/BfAYACkEBKgB4nGWQPW7CQBSEx2BIAlKCFCkps1UKIpmfkgNAT0GXwpi1MbK91npBossJcoQcIaeIcoIcKGPzaGAtP38zb97uygAG+IWHenm4bWq9WrihOnGb9CDsk5+FO+jjRbhLfyjcwxumwn084p07eP4dnQFK4Rbu8SHcpv8p7JO/hDt4wrdwl/6PcA8r/An38eoN08gUsSncUif7LLRnef6utK1SU6hJMD5bC11oGzq9Ueujqg7J1LlYxdbkas6uzjKjSmt2OnLB1rlyNhrF4geRyZEigkGBuKkOS2gk2CNDCHvVvdQrpi0q+rVWmCDA+Cq1YKpokiGVxobJNY6sFQ48bUrXMa34Ws7kpLnMat4kIyv+77q3oxPRD7BtpkrMMOITX+SD5g75Pz0RXqgAAAB4nF3GOQ6AIBQA0T+44YoX4VAEaNEYCNe3IDa+ZkaUNF//DIqOnoGRCc3MwsrGzoHhlMW7J2Ybrpp023LjcTxEMpbARSVRuEVebe8MtgAAAA==\') format(\'woff\')}[class*=\' luna-data-grid-icon-\'],[class^=luna-data-grid-icon-]{display:inline-block;font-family:luna-data-grid-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.luna-data-grid-icon-caret-down:before{content:\'\\f101\'}.luna-data-grid-icon-caret-up:before{content:\'\\f102\'}.luna-data-grid{position:relative;border:1px solid;overflow:hidden;outline:0;color:rgba(0,0,0,.88);color:var(--luna-color-text,rgba(0,0,0,.88));background-color:#fff;background-color:var(--luna-color-bg-container,#fff);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-family:var(--luna-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:14px}.luna-data-grid .luna-data-grid-hidden,.luna-data-grid.luna-data-grid-hidden{display:none}.luna-data-grid .luna-data-grid-invisible,.luna-data-grid.luna-data-grid-invisible{visibility:hidden}.luna-data-grid *{box-sizing:border-box}.luna-data-grid.luna-data-grid-theme-dark{color-scheme:dark;color:hsla(0,0%,100%,.85);color:var(--luna-color-text-dark,rgba(255,255,255,.85));background-color:#141414;background-color:var(--luna-color-bg-container-dark,#141414)}.luna-data-grid{font-size:12px}.luna-data-grid table{width:100%;min-height:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.luna-data-grid td,.luna-data-grid th{padding:1px 4px;border-left:1px solid;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.luna-data-grid td:first-child,.luna-data-grid th:first-child{border-left:none}.luna-data-grid th{font-weight:400;border-bottom:1px solid;text-align:left;position:relative}.luna-data-grid th.luna-data-grid-sortable{padding-right:12px}.luna-data-grid th .luna-data-grid-icon-caret-down,.luna-data-grid th .luna-data-grid-icon-caret-up{font-size:12px;position:absolute;display:none;top:6px;right:2px}.luna-data-grid td{height:20px;cursor:default;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.luna-data-grid:focus .luna-data-grid-node.luna-data-grid-selectable.luna-data-grid-selected{color:#fff}.luna-data-grid-data-container,.luna-data-grid-header-container{overflow:hidden}.luna-data-grid-header-container{height:21px}.luna-data-grid-data-container{overflow-y:auto;position:relative}.luna-data-grid-data-space{min-height:100%}.luna-data-grid-data{position:absolute;left:0;top:0}.luna-data-grid-filler-row td{height:auto}.luna-data-grid-resizer{position:absolute;top:0;bottom:0;width:5px;z-index:500;touch-action:none;cursor:col-resize}.luna-data-grid-resizing{cursor:col-resize!important}.luna-data-grid-resizing .luna-data-grid *{cursor:col-resize!important}.luna-data-grid-theme-light{border-color:#d9d9d9;border-color:var(--luna-color-border,#d9d9d9)}.luna-data-grid-theme-light td,.luna-data-grid-theme-light th{border-color:#d9d9d9;border-color:var(--luna-color-border,#d9d9d9)}.luna-data-grid-theme-light th{background-color:rgba(0,0,0,.06);background-color:var(--luna-color-fill-secondary,rgba(0,0,0,.06))}.luna-data-grid-theme-light th.luna-data-grid-sortable:hover{background-color:rgba(0,0,0,.15);background-color:var(--luna-color-fill,rgba(0,0,0,.15))}.luna-data-grid-theme-light .luna-data-grid-data-container .luna-data-grid-node.luna-data-grid-selectable:hover,.luna-data-grid-theme-light .luna-data-grid-data-container .luna-data-grid-node.luna-data-grid-selected{background-color:#ddd}.luna-data-grid-theme-light .luna-data-grid-data-container tr:nth-child(even){background-color:#f2f7fd}.luna-data-grid-theme-light:focus .luna-data-grid-node.luna-data-grid-selectable.luna-data-grid-selected{background-color:#1a73e8;background-color:var(--luna-color-primary,#1a73e8)}.luna-data-grid-theme-dark{border-color:#424242;border-color:var(--luna-color-border,#424242)}.luna-data-grid-theme-dark td,.luna-data-grid-theme-dark th{border-color:#424242;border-color:var(--luna-color-border,#424242)}.luna-data-grid-theme-dark th{background-color:hsla(0,0%,100%,.12);background-color:var(--luna-color-fill-secondary,rgba(255,255,255,.12))}.luna-data-grid-theme-dark th.luna-data-grid-sortable:hover{background-color:hsla(0,0%,100%,.18);background-color:var(--luna-color-fill,rgba(255,255,255,.18))}.luna-data-grid-theme-dark .luna-data-grid-data-container .luna-data-grid-node.luna-data-grid-selectable:hover,.luna-data-grid-theme-dark .luna-data-grid-data-container .luna-data-grid-node.luna-data-grid-selected{background-color:#393939}.luna-data-grid-theme-dark .luna-data-grid-data-container tr:nth-child(even){background-color:#0b2544}.luna-data-grid-theme-dark:focus .luna-data-grid-node.luna-data-grid-selectable.luna-data-grid-selected{background-color:#1965c8;background-color:var(--luna-color-primary,#1965c8)}',""]),e.exports=t},3290:function(e,t,n){var o=n(975);t=function(e){var t,n=window.location,r=n.hostname,i=n.pathname,a=r.split("."),s=i.split("/"),c="",l=s.length;if(!p())for(var u=a.length-1;u>=0;u--){var d=a[u];if(""!==d){if(p({domain:c=""===c?d:d+"."+c,path:t="/"})||p({domain:c}))return;for(var h=0;h-1&&(t=(0,d.default)(t.split("?")[0])),""===t)&&(t=new l.default(e).hostname);return t}function S(e){if(!e)return{type:"unknown",subType:"unknown"};var t=e.split(";")[0].split("/");return{type:t[0],subType:(0,c.default)(t)}}var E=window.location.origin;function T(e){var t=encodeURIComponent(e).match(/%[89ABab]/g);return e.length+(t?t.length:0)}},3422:function(e,t){t=function(e){return null==e},e.exports=t},3497:function(e,t){t=function(e){var t=e?e.length:0;if(t)return e[t-1]},e.exports=t},3539:function(e,t){t=function(){for(var e=arguments,t=e[0],n=1,o=e.length;nt&&(t=e[n]);return t},e.exports=t},3578:function(e,t,n){"use strict";n.d(t,{A:function(){return on}});var o=n(7528);var r=n(7800);function i(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var o,r,i,a,s=[],c=!0,l=!1;try{if(i=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;c=!1}else for(;!(c=(o=i.call(n)).done)&&(s.push(o.value),s.length!==t);c=!0);}catch(e){l=!0,r=e}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(e,t)||(0,r.A)(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}var a=n(3029),s=n(2901),c=n(388),l=n(3954),u=n(991),d=n(5361),h=n(5902),f=n.n(h),p=n(2561),v=n.n(p),g=n(3249),m=n.n(g),b=n(1009),y=n.n(b),A=n(4950),w=n.n(A),_=n(9100),x=n.n(_),k=n(1580),C=n.n(k),S=n(9464),E=n.n(S),T=n(15),N=n.n(T),O=n(9931),j=n.n(O);function M(e){return e.constructor&&e.constructor.name?e.constructor.name:j()({}.toString.call(e).replace(/(\[object )|]/g,""))}var I=n(3915),z=n.n(I),D=n(9405),B=n.n(D),F=n(5169),R=n.n(F),L=n(9548),G=n.n(L),P=n(6097),H=n.n(P),Y=n(6030),$=n.n(Y),q=n(5004),Q=n.n(q),U=(n(9410),n(8609)),W=n.n(U);function J(e){var t="luna-".concat(e,"-");function n(e){return z()(B()(e).split(/\s+/),(function(e){return m()(e,t)?e:e.replace(/[\w-]+/,(function(e){return"".concat(t).concat(e)}))})).join(" ")}return function(e){if(/<[^>]*>/g.test(e))try{var t=G().parse(e);return K(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),G().stringify(t)}catch(t){return n(e)}return n(e)}}function K(e,t){for(var n=0,o=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=n.topObj,r=n.level,i=void 0===r?0:r,a=n.getterVal,s=void 0!==a&&a,c=n.unenumerable,l=void 0===c||c,u="",d="",h=[],p=[],g="";o=o||e;var b={getterVal:s,unenumerable:l,level:i+1},A=0===i,w=''),_=''),k=''),S=''),E=''),T=''),O=function(e){return f()(e).replace(/\\n/g,"↵").replace(/\\f|\\r|\\t/g,"").replace(/\\/g,"")},j="";function I(e){return e=v()(e),m()(ee,e)||y()(e,"Array[")?T+O(e)+j:(e.length>100&&(e=N()(e,100,{separator:" ",ellipsis:"…"})),S+O('"'.concat(e,'"'))+j)}function z(n){if(t>5)g=", …";else{var r=function(e){return w+O(e)+j}(ne(n));if(!s){var i=Object.getOwnPropertyDescriptor(e,n);if(i&&i.get)return h.push("".concat(r,": ").concat(I("(...)"))),void t++}h.push("".concat(r,": ").concat(X(o[n],b))),t++}}try{d={}.toString.call(e)}catch(e){d="[object Object]"}var D,B="[object Array]"==d,F="[object Object]"==d,R="[object Number]"==d,L="[object RegExp]"==d,G="[object Symbol]"==d,P="[object Function]"==d,H="[object Boolean]"==d;if("[object String]"==d)u=I(ne(e));else if(L)D=ne(e.toString()),u=S+D+j;else if(P)u=I("ƒ");else if(B)if(A){u="[";var Y=e.length,$="";Y>100&&(Y=100,$=", …");for(var q=0;q0&&void 0!==arguments[0])||arguments[0],t=this.container.getBoundingClientRect(),n=t.width,o=t.height-1;this.height!==o&&(this.height=o,e||this.emit("updateHeight")),this.width!==n&&(this.width=n)}},{key:"html",value:function(){return this.container.outerHTML}},{key:"text",value:function(){return this.content.textContent||""}},{key:"select",value:function(){this.$container.addClass(this.console.c("selected"))}},{key:"deselect",value:function(){this.$container.rmClass(this.console.c("selected"))}},{key:"copy",value:function(){var e=this.args,t="";x()(e,(function(e,n){0!==n&&(t+=" "),ue()(e)?t+=Ze()(e):t+=v()(e)})),et()(t)}},{key:"bindEvent",value:function(){var e=this,t=this.console.c,n=this;this.resizeSensor.addListener(this.onResize),this.$container.on("click",t(".dom-viewer"),(function(e){return e.stopPropagation()})).on("click",t(".preview"),(function(e){if(e.stopPropagation(),!V(this)){var o=$e()(this).find(t(".preview-icon-container")).find(t(".icon")),r="caret-down";o.hasClass(t("icon-caret-down"))&&(r="caret-right"),o.rmAttr("class").addClass([t("icon"),t("icon-".concat(r))]),n.renderObjectViewer(this)}})).on("click",(function(){return e.click()}))}},{key:"renderEl",value:function(){var e=this.elements,t=this.console.c,n=this;this.$container.find(t(".dom-viewer")).each((function(){var t=$e()(this).data("id");new ae.A(this,{node:e[t],theme:n.console.getOption("theme")})}))}},{key:"renderObjectViewer",value:function(e){var t=this.console,n=this.unenumerable,o=this.accessGetter,r=this.lazyEvaluation,i=t.c,a=$e()(e),s=a.data("id");if(s){var c=this.objects[s],l=a.find(i(".json"));if(l.hasClass(i("hidden"))){if("true"!==l.data("init")){if(r){var u=new re.A(l.get(0),{unenumerable:n,accessGetter:o});u.setOption("theme",t.getOption("theme")),u.set(c)}else{var d=new re.j(l.get(0));d.setOption("theme",t.getOption("theme")),d.set(c)}l.data("init","true")}l.rmClass(i("hidden"))}else l.addClass(i("hidden"))}}},{key:"renderTable",value:function(e){var t=this,n="__LunaConsoleValue",o=this.columns,r=this.$container,i=this.console,a=i.c,s=r.find(a(".data-grid")),c=e[0],l=new ie.A(s.get(0),{columns:ke()([{id:"(index)",title:"(index)",sortable:!0}],z()(o,(function(e){return{id:e,title:e===n?"Value":e,sortable:!0}}))),theme:i.getOption("theme")});x()(c,(function(e,r){var i={"(index)":v()(r)};o.forEach((function(o){ue()(e)?i[o]=o===n?"":t.formatTableVal(e[o]):ge()(e)&&(i[o]=o===n?t.formatTableVal(e):"")})),l.append(i)}))}},{key:"extractObj",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0,o=this.accessGetter,r=this.unenumerable;be()(t,{accessGetter:o,unenumerable:r,symbol:r,timeout:1e3}),function(e,t,n){var o=nt()(e,t);rt()((function(){return n(o)}))}(e,t,(function(e){return n(JSON.parse(e))}))}},{key:"click",value:function(){var e=this.type,t=this.$container,n=this.console,o=n.c;switch(e){case"log":case"warn":case"info":case"debug":case"output":case"table":case"dir":break;case"group":case"groupCollapsed":V(this.container)||n.toggleGroup(this);break;case"error":V(this.container)||t.find(o(".stack")).toggleClass(o("hidden"))}}},{key:"formatMsg",value:function(){var e=this.args,t=this.type,n=this.id,o=this.header,r=this.group,i=this.console.c;e=Re()(e);var a,s,c="";switch("group"!==t&&"groupCollapsed"!==t||0===e.length&&(e=["console.group"]),t){case"log":case"info":case"debug":c=this.formatCommon(e);break;case"dir":c=this.formatDir(e);break;case"warn":a="warn",c=this.formatCommon(e);break;case"error":he()(e[0])&&1!==e.length&&(e=this.substituteStr(e)),s=e[0],a="error",s=pe()(s)?s:new Error(this.formatCommon(e)),c=this.formatErr(s);break;case"table":c=this.formatTable(e);break;case"html":c=e[0];break;case"input":c=this.formatJs(e[0]),a="input";break;case"output":c=this.formatCommon(e),a="output";break;case"groupCollapsed":c=this.formatCommon(e),a="caret-right";break;case"group":c=this.formatCommon(e),a="caret-down"}if(m()(["log","debug","warn"],t)&&this.isSimple()&&(c=at()(c,(function(e){return'').concat(e,"")}))),c=this.render({msg:c,type:t,icon:a,id:n,header:o,group:r}),this.$container.addClass("".concat(i("log-container"))).html(c),"table"===t)E()(this.columns)||this.renderTable(e);E()(this.elements)||this.renderEl(),this.$content=this.$container.find(i(".log-content")),this.content=this.$content.get(0)}},{key:"render",value:function(e){var t=this.console.c,n="",r="";if(e.group)for(var i=e.group.indentLevel,a=0;a');e.header&&(n+=ht()(oe||(oe=(0,o.A)(['\n
\n ','\n
\n '," ","\n
\n
"])),t("header"),r,t("time-from-container"),e.header.time,e.header.from));var s="";return e.icon&&(s='
')),n+='\n
\n ').concat(r,"\n ").concat(s,'\n
\n
\n
\n
\n
').concat(e.msg,"
\n
\n
")}},{key:"formatTable",value:function(e){var t=e[0],n=e[1],o=[];return he()(n)&&(n=Me()(n)),ze()(n)||(n=null),ue()(t)?(x()(t,(function(e){ge()(e)?o.push("__LunaConsoleValue"):ue()(e)&&(o=o.concat(He()(e)))})),(o=Be()(o)).sort(),n&&(o=o.filter((function(e){return m()(n,e)}))),o.length>20&&(o=o.slice(0,20)),E()(o)?this.formatCommon(e):(this.columns=o,this.console.c('
')+this.formatPreview(t))):this.formatCommon(e)}},{key:"formatErr",value:function(e){var t=e.stack?e.stack.split("\n"):[],n=e.name?"".concat(e.name,": "):"";return n+="".concat(e.message||t[0],"
"),t=t.map((function(e){return f()(e)})),n+'
').concat(t.slice(1).join("
"),"
").replace(kt,(function(e){return'').concat(e,"")}))}},{key:"formatCommon",value:function(e){var t=this.console.c,n=he()(e[0])&&1!==e.length;n&&(e=this.substituteStr(e));for(var o=0,r=e.length;o').concat(f()(v()(i)),"
"):ue()(i)?e[o]=this.formatPreview(i):Te()(i)?e[o]='undefined'):Se()(i)?e[o]='null'):H()(i)?e[o]='').concat(v()(i),""):"bigint"==typeof i?e[o]='').concat(v()(i),"n"):bt()(i)?e[o]='').concat(v()(i),""):At()(i)?e[o]='').concat(f()(v()(i)),""):(i=v()(i),0===o&&n||(i=f()(i)),i.length>5e3&&(i=N()(i,5e3,{separator:" ",ellipsis:"…"})),e[o]=i)}return e.join(" ")}},{key:"formatDir",value:function(e){return ue()(e[0])?this.formatPreview(e[0]):this.formatCommon(e)}},{key:"formatTableVal",value:function(e){var t=this.console.c;return ue()(e)?"{…}":ge()(e)?pt()('
').concat(X(e),"
")):v()(e)}},{key:"formatPreview",value:function(e){var t=this,n=this.console.c,o=gt()();this.lazyEvaluation?this.objects[o]=e:this.extractObj(e,{},(function(e){t.objects[o]=e}));var r=m()(["dir","table"],this.type),i=M(e);return"Array"===i&&e.length>1?(i="(".concat(e.length,")"),r&&(i="Array".concat(i))):"RegExp"===i?i=v()(e):Ae()(e)&&(i=this.formatElName(e)),'
')+'
')+'
')+'')+'').concat(f()(i)," ")+'').concat(r?"":X(e,{getterVal:this.accessGetter,unenumerable:!1}),"")+"
"+'
')}},{key:"substituteStr",value:function(e){var t=f()(e[0]),n=!1,o="";e.shift();for(var r=0,i=t.length;r"),n=!0,o+='');break;default:r--,e.unshift(s),o+=a}}else o+=a}return n&&(o+=""),e.unshift(o),e}},{key:"formatJs",value:function(e){var t=ct()(e,"js",Ct);return t!==e&&(t=this.console.c(t)),'
').concat(t,"
")}},{key:"formatFn",value:function(e){return'
'.concat(this.formatJs(e.toString()),"
")}},{key:"formatElName",value:function(e){var t=e.id,n=e.className,o=e.tagName.toLowerCase();if(""!==t&&(o+="#".concat(t)),he()(n)){var r="";x()(n.split(/\s+/g),(function(e){""!==e.trim()&&(r+=".".concat(e))})),o+=r}return o}},{key:"formatEl",value:function(e){var t=gt()();return this.elements[t]=e,this.console.c('
'))}}])}(We());function Et(e){var t=(e=Ge()(e)).split(";"),n={};x()(t,(function(e){if(m()(e,":")){var t=i(e.split(":"),2),o=t[0],r=t[1];n[B()(o)]=B()(r)}})),n.display="inline-block",n["max-width"]="100%",delete n.width,delete n.height;var o="";return x()(n,(function(e,t){o+="".concat(t,":").concat(e,";")})),o}var Tt=n(5820),Nt=n.n(Tt),Ot=n(3981),jt=n.n(Ot),Mt=n(8105),It=n.n(Mt),zt=n(7005),Dt=n.n(zt),Bt=n(3497),Ft=n.n(Bt),Rt=n(5865),Lt=n.n(Rt),Gt=n(8862),Pt=n.n(Gt),Ht=n(7030),Yt=n.n(Ht),$t=n(961),qt=n.n($t),Qt=n(7e3),Ut=n.n(Qt);function Wt(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(Wt=function(){return!!e})()}var Jt,Kt=function(e){function t(e,n){var o,r,i=n.compName,s=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).theme,u=void 0===s?"light":s;return(0,a.A)(this,t),o=function(e,t,n){return t=(0,l.A)(t),(0,c.A)(e,Wt()?Reflect.construct(t,n||[],(0,l.A)(e).constructor):t.apply(e,n))}(this,t),o.subComponents=[],o.theme="",o.onThemeChange=function(e){"auto"===o.options.theme&&o.setTheme(e)},o.compName=i,o.c=J(i),o.options={},o.container=e,o.$container=$e()(e),o.$container.addClass(["luna-".concat(i),o.c("platform-".concat((r=Q()(),"os x"===r?"mac":r)))]),o.on("changeOption",(function(e,t){if("theme"===e&&t){var n=t;"auto"===t&&(n=Ut().get()),o.setTheme(n),x()(o.subComponents,(function(e){return e.setOption("theme",t)}))}})),Ut().on("change",o.onThemeChange),o.setOption("theme",u),o}return(0,d.A)(t,e),(0,s.A)(t,[{key:"destroy",value:function(){var e=this;this.destroySubComponents();var t=this.$container,n=t.attr("class");x()(n.split(/\s+/),(function(n){y()(n,"luna-".concat(e.compName))&&t.rmClass(n)})),t.html(""),this.emit("destroy"),this.removeAllListeners(),Ut().off("change",this.onThemeChange)}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,x()(r,(function(e,t){var r=o[t];o[t]=e,e!==r&&n.emit("changeOption",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){qt()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){x()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};be()(e,t),It()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}},{key:"setTheme",value:function(e){var t=this.c,n=this.$container;this.theme&&n.rmClass(t("theme-".concat(this.theme))),n.addClass(t("theme-".concat(e))),this.theme=e}}])}(We()),Vt=n(2228),Zt=n.n(Vt);function Xt(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(Xt=function(){return!!e})()}e=n.hmd(e);var en=navigator.userAgent,tn=en.indexOf("Android")>-1||en.indexOf("Adr")>-1,nn=0,on=function(e){function t(e){var n,o,r,i,s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return(0,a.A)(this,t),o=this,r=t,i=[e,{compName:"console"},s],r=(0,l.A)(r),(n=(0,c.A)(o,Xt()?Reflect.construct(r,i||[],(0,l.A)(o).constructor):r.apply(o,i))).spaceHeight=0,n.topSpaceHeight=0,n.bottomSpaceHeight=0,n.lastScrollTop=0,n.lastTimestamp=0,n.speedToleranceFactor=100,n.maxSpeedTolerance=2e3,n.minSpeedTolerance=100,n.logs=[],n.displayLogs=[],n.timer={},n.counter={},n.asyncList=[],n.asyncTimer=null,n.isAtBottom=!0,n.groupStack=new(Dt()),n.selectedLog=null,n.onScroll=function(){var e=n.container,t=e.scrollHeight,o=e.offsetHeight,r=e.scrollTop;if(!(r<=0||o+r>t)){var i=!1;(t===o||Math.abs(t-o-r)<1)&&(i=!0),n.isAtBottom=i;var a=n.lastScrollTop,s=n.lastTimestamp,c=jt()(),l=c-s,u=r-a,d=Math.abs(u/l)*n.speedToleranceFactor;l>1e3&&(d=1e3),d>n.maxSpeedTolerance&&(d=n.maxSpeedTolerance),dr+o+f||n.renderViewport({topTolerance:2*h,bottomTolerance:2*f})}},n.initTpl(),n.initOptions(s,{maxNum:0,asyncRender:!0,showHeader:!1,filter:"",level:["verbose","info","warning","error"],accessGetter:!1,unenumerable:!0,lazyEvaluation:!0}),n.$el=n.find(".logs"),n.el=n.$el.get(0),n.$fakeEl=n.find(".fake-logs"),n.fakeEl=n.$fakeEl.get(0),n.$space=n.find(".logs-space"),n.space=n.$space.get(0),tn&&(n.speedToleranceFactor=800,n.maxSpeedTolerance=3e3,n.minSpeedTolerance=800),n.resizeSensor=new(ce())(e),n.renderViewport=Lt()((function(e){n._renderViewport(e)}),16),n.global={copy:function(e){he()(e)||(e=JSON.stringify(e,null,2)),et()(e)},$:function(e){return document.querySelector(e)},$$:function(e){return Me()(document.querySelectorAll(e))},$x:function(e){return Pt()(e)},clear:function(){n.clear()},dir:function(e){n.dir(e)},table:function(e,t){n.table(e,t)},keys:He()},n.bindEvent(),n}return(0,d.A)(t,e),(0,s.A)(t,[{key:"setGlobal",value:function(e,t){this.global[e]=t}},{key:"destroy",value:function(){var e,n,o,r,i;this.$container.off("scroll",this.onScroll),this.resizeSensor.destroy(),(e=t,n="destroy",o=this,r=3,i=(0,u.A)((0,l.A)(1&r?e.prototype:e),n,o),2&r&&"function"==typeof i?function(e){return i.apply(o,e)}:i)([])}},{key:"count",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"default",t=this.counter;Te()(t[e])?t[e]=1:t[e]++,this.info("".concat(e,": ").concat(t[e]))}},{key:"countReset",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"default";this.counter[e]=0}},{key:"assert",value:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&void 0!==arguments[0]?arguments[0]:"default";if(this.timer[e])return this.insert("warn",["Timer '".concat(e,"' already exists")]);this.timer[e]=Nt()()}},{key:"timeLog",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"default",t=this.timer[e];if(!t)return this.insert("warn",["Timer '".concat(e,"' does not exist")]);this.info("".concat(e,": ").concat(Nt()()-t,"ms"))}},{key:"timeEnd",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"default";this.timeLog(e),delete this.timer[e]}},{key:"clear",value:function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.logs=[],this.displayLogs=[],this.selectLog(null),this.lastLog=void 0,this.counter={},this.timer={},this.groupStack=new(Dt()),this.asyncList=[],this.asyncTimer&&(clearTimeout(this.asyncTimer),this.asyncTimer=null),e?this.render():this.insert("log",["%cConsole was cleared","color:#808080;font-style:italic;"])}},{key:"info",value:function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&(o.group=a.peek()),It()(o,{id:++nn,accessGetter:l,unenumerable:u,lazyEvaluation:d}),"group"===o.type||"groupCollapsed"===o.type){var h={id:gt()("group"),collapsed:!1,parent:a.peek(),indentLevel:a.size+1};"groupCollapsed"===o.type&&(h.collapsed=!0),o.targetGroup=h,a.push(h)}var f=new St(this,o);f.on("updateHeight",(function(){r.isAtBottom=!1,r.renderViewport()}));var p=this.lastLog;if(p&&!m()(["html","group","groupCollapsed"],f.type)&&p.type===f.type&&f.isSimple()&&p.text()===f.text()?(p.addCount(),f.header&&p.updateTime(f.header.time),f=p,this.detachLog(p)):(i.push(f),this.lastLog=f),0!==c&&i.length>c){var v=i[0];this.detachLog(v),i.shift()}this.attachLog(f),this.emit("insert",f)}},{key:"updateTopSpace",value:function(e){this.topSpaceHeight=e,this.el.style.top=e+"px"}},{key:"updateBottomSpace",value:function(e){this.bottomSpaceHeight=e}},{key:"updateSpace",value:function(e){this.spaceHeight!==e&&(this.spaceHeight=e,this.space.style.height=e+"px")}},{key:"detachLog",value:function(e){var t=this.displayLogs,n=t.indexOf(e);n>-1&&(t.splice(n,1),this.renderViewport())}},{key:"attachLog",value:function(e){if(this.filterLog(e)&&!e.collapsed){var t=this.displayLogs;if(0===t.length)return t.push(e),void this.renderViewport();var n=Ft()(t);if(e.id>n.id)return t.push(e),void this.renderViewport();for(var o,r=0,i=t.length-1,a=0;r<=i;){if((o=t[a=r+Math.floor((i-r)/2)]).id===e.id)return;o.id0&&void 0!==arguments[0]?arguments[0]:20,n=this.asyncList;this.asyncTimer||(this.asyncTimer=setTimeout((function(){e.asyncTimer=null;var t,o,r=!1,a=n.length;a<1e3?(o=200,t=400):a<5e3?(o=500,t=800):a<1e4?(o=800,t=1e3):a<25e3?(o=1e3,t=1200):a<5e4?(o=1500,t=1500):(o=2e3,t=2500),o>a&&(o=a,r=!0);for(var s=0;s0&&o.length>n&&(e.logs=o.slice(o.length-n),e.render());break;case"filter":e.render();break;case"level":e.options.level=Me()(n),e.render()}})),this.$container.on("scroll",this.onScroll)}},{key:"_renderViewport",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.topTolerance,n=void 0===t?500:t,o=e.bottomTolerance,r=void 0===o?500:o,i=this.el,a=this.container,s=this.space;if(!W()(a)){for(var c=a.scrollTop,l=a.offsetHeight,u=s.getBoundingClientRect().width,d=c-n,h=c+l+r,f=this.displayLogs,p=0,v=0,g=0,m=f.length,b=this.fakeEl,y=document.createDocumentFragment(),A=[],w=0;w0){b.appendChild(y);for(var k=0,C=A.length;kh?v+=O:g+O>d?S.appendChild(N):g\n
\n
\n \n '])))))}}])}(Kt),rn=function(){return Yt()("HH:MM:ss ")};function an(){for(var e=new Error,t="",n=e.stack?e.stack.split("\n"):"",o=0,r=n.length;o-1&&o0)&&!(o=i.next()).done;)a.push(o.value)}catch(e){r={error:e}}finally{try{o&&!o.done&&(n=i.return)&&n.call(i)}finally{if(r)throw r.error}}return a},o=this&&this.__values||function(e){var t="function"==typeof Symbol&&Symbol.iterator,n=t&&e[t],o=0;if(n)return n.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&o>=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")};function r(e,t){var n=e[3];return[(1-n)*t[0]+n*e[0],(1-n)*t[1]+n*e[1],(1-n)*t[2]+n*e[2],n+t[3]*(1-n)]}function i(e){var t=n(e,3),o=t[0],r=t[1],i=t[2];return.2126*(o<=.03928?o/12.92:Math.pow((o+.055)/1.055,2.4))+.7152*(r<=.03928?r/12.92:Math.pow((r+.055)/1.055,2.4))+.0722*(i<=.03928?i/12.92:Math.pow((i+.055)/1.055,2.4))}Object.defineProperty(t,"__esModule",{value:!0}),t.getContrastThreshold=t.isLargeFont=t.getAPCAThreshold=t.desiredLuminanceAPCA=t.contrastRatioByLuminanceAPCA=t.contrastRatioAPCA=t.luminanceAPCA=t.contrastRatio=t.luminance=t.rgbaToHsla=t.blendColors=void 0,t.blendColors=r,t.rgbaToHsla=function(e){var t=n(e,4),o=t[0],r=t[1],i=t[2],a=t[3],s=Math.max(o,r,i),c=Math.min(o,r,i),l=s-c,u=s+c,d=.5*u;return[c===s?0:o===s?(1/6*(r-i)/l+1)%1:r===s?1/6*(i-o)/l+1/3:1/6*(o-r)/l+2/3,0===d||1===d?0:d<=.5?l/u:l/(2-u),d,a]},t.luminance=i,t.contrastRatio=function(e,t){var n=i(r(e,t)),o=i(t);return(Math.max(n,o)+.05)/(Math.min(n,o)+.05)};var a=12.82051282051282,s=.06;function c(e){var t=n(e,3),o=t[0],r=t[1],i=t[2];return.2126729*Math.pow(o,2.4)+.7151522*Math.pow(r,2.4)+.072175*Math.pow(i,2.4)}function l(e){return e>.03?e:e+Math.pow(.03-e,1.45)}function u(e,t){if(e=l(e),t=l(t),Math.abs(e-t)<5e-4)return 0;var n=0;return 100*(n=t>=e?(n=1.25*(Math.pow(t,.55)-Math.pow(e,.58)))<.001?0:n<.078?n-n*a*s:n-s:(n=1.25*(Math.pow(t,.62)-Math.pow(e,.57)))>-.001?0:n>-.078?n-n*a*s:n+s)}t.luminanceAPCA=c,t.contrastRatioAPCA=function(e,t){return u(c(e),c(t))},t.contrastRatioByLuminanceAPCA=u,t.desiredLuminanceAPCA=function(e,t,n){function o(){return n?Math.pow(Math.abs(Math.pow(e,.62)-(-t-s)/1.25),1/.57):Math.pow(Math.abs(Math.pow(e,.55)-(t+s)/1.25),1/.58)}e=l(e),t/=100;var r=o();return(r<0||r>1)&&(n=!n,r=o()),r};var d=[[12,-1,-1,-1,-1,100,90,80,-1,-1],[14,-1,-1,-1,100,90,80,60,60,-1],[16,-1,-1,100,90,80,60,55,50,50],[18,-1,-1,90,80,60,55,50,40,40],[24,-1,100,80,60,55,50,40,38,35],[30,-1,90,70,55,50,40,38,35,40],[36,-1,80,60,50,40,38,35,30,25],[48,100,70,55,40,38,35,30,25,20],[60,90,60,50,38,35,30,25,20,20],[72,80,55,40,35,30,25,20,20,20],[96,70,50,35,30,25,20,20,20,20],[120,60,40,30,25,20,20,20,20,20]];function h(e,t){var n=72*parseFloat(e.replace("px",""))/96;return-1!==["bold","bolder","600","700","800","900"].indexOf(t)?n>=14:n>=18}d.reverse(),t.getAPCAThreshold=function(e,t){var r,i,a,s,c=parseFloat(e.replace("px","")),l=parseFloat(t);try{for(var u=o(d),h=u.next();!h.done;h=u.next()){var f=n(h.value),p=f[0],v=f.slice(1);if(c>=p)try{for(var g=(a=void 0,o([900,800,700,600,500,400,300,200,100].entries())),m=g.next();!m.done;m=g.next()){var b=n(m.value,2),y=b[0];if(l>=b[1]){var A=v[v.length-1-y];return-1===A?null:A}}}catch(e){a={error:e}}finally{try{m&&!m.done&&(s=g.return)&&s.call(g)}finally{if(a)throw a.error}}}}catch(e){r={error:e}}finally{try{h&&!h.done&&(i=u.return)&&i.call(u)}finally{if(r)throw r.error}}return null},t.isLargeFont=h;var f={aa:3,aaa:4.5},p={aa:4.5,aaa:7};t.getContrastThreshold=function(e,t){return h(e,t)?f:p}},3722:function(e,t,n){var o=n(3145);t=function(e){return Object.freeze?Object.freeze(e):(o(e).forEach((function(t){Object.getOwnPropertyDescriptor(e,t).configurable&&Object.defineProperty(e,t,{writable:!1,configurable:!1})})),e)},e.exports=t},3737:function(e,t,n){var o=n(2263);t=o.extend({className:"MediaQuery",initialize:function(e){var t=this;this.callSuper(o,"initialize"),this._listener=function(){t.emit(t.isMatch()?"match":"unmatch")},this.setQuery(e)},setQuery:function(e){this._mql&&this._mql.removeListener(this._listener),this._mql=window.matchMedia(e),this._mql.addListener(this._listener)},isMatch:function(){return this._mql.matches}}),e.exports=t},3750:function(e,t,n){var o=n(3974);t=function(e){return"[object Blob]"===o(e)},e.exports=t},3752:function(e,t,n){var o=n(2510),r=n(769);t=o((function(e,t){return function(){var n=[];return n=(n=n.concat(t)).concat(r(arguments)),e.apply(this,n)}})),e.exports=t},3793:function(e,t,n){var o=n(8966),r=n(8971),i=n(3612),a=n(9100);function s(e){return function(t,n,s,c){t=i(t),r(c)&&(c=s,s=void 0),a(t,(function(t){o[e](t,n,s,c)}))}}t={on:s("add"),off:s("remove")},e.exports=t},3805:function(e,t,n){var o=n(2561);t=function(e){return o(e).toLocaleUpperCase()},e.exports=t},3915:function(e,t,n){var o=n(5693),r=n(3145),i=n(5793);t=function(e,t,n){t=o(t,n);for(var a=!i(e)&&r(e),s=(a||e).length,c=Array(s),l=0;l=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},r=this&&this.__read||function(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var o,r,i=n.call(e),a=[];try{for(;(void 0===t||t-- >0)&&!(o=i.next()).done;)a.push(o.value)}catch(e){r={error:e}}finally{try{o&&!o.done&&(n=i.return)&&n.call(i)}finally{if(r)throw r.error}}return a},i=this&&this.__spreadArray||function(e,t,n){if(n||2===arguments.length)for(var o,r=0,i=t.length;r]*>/g.test(e))try{var t=Oe().parse(e);return De(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=Be(e.attrs.class))})),Oe().stringify(t)}catch(t){return Be(e)}return Be(e)}function De(e,t){for(var n=0,o=e.length;n3||Math.abs(a)>3)&&(r._isClick=!1);var s=r._oldX+i,c=r._oldY+a;s<0?s=0:s>n-t&&(s=n-t),c<0?c=0:c>o-t&&(c=o-t),r._$el.css({left:s,top:c})})),(0,c.A)(r,"_onDragEnd",(function(e){var t=r._$el;r._isClick&&r.emit("click"),r._onDragMove(e),Ge.off(pe()("move"),r._onDragMove),Ge.off(pe()("up"),r._onDragEnd);var n=r.config;n.get("rememberPos")&&n.set("pos",{x:Me(t.css("left")),y:Me(t.css("top"))}),t.rmClass("eruda-active")})),r._style=re(n(6717)),r._$container=e,r._initTpl(),r._bindEvent(),r._registerListener(),r}return(0,s.A)(t,e),(0,r.A)(t,[{key:"hide",value:function(){this._$el.hide()}},{key:"show",value:function(){this._$el.show()}},{key:"setPos",value:function(e){this._isOutOfRange(e)&&(e=this._getDefPos()),this._$el.css({left:e.x,top:e.y}),this.config.set("pos",e)}},{key:"getPos",value:function(){return this.config.get("pos")}},{key:"destroy",value:function(){re.remove(this._style),this._unregisterListener(),this._$el.remove()}},{key:"_isOutOfRange",value:function(e){e=e||this.config.get("pos");var t=this._getDefPos();return e.x>t.x+10||e.x<0||e.y<0||e.y>t.y+10}},{key:"_registerListener",value:function(){var e=this;this._scaleListener=function(){return ue()((function(){e._isOutOfRange()&&e._resetPos()}))},h.on(h.SCALE,this._scaleListener)}},{key:"_unregisterListener",value:function(){h.off(h.SCALE,this._scaleListener)}},{key:"_initTpl",value:function(){var e=this._$container;e.append(ze('
')),this._$el=e.find(".eruda-entry-btn")}},{key:"_resetPos",value:function(e){var t=this.config,n=t.get("pos"),o=this._getDefPos();t.get("rememberPos")&&!e||(n=o),this.setPos(n)}},{key:"_bindEvent",value:function(){var e=this;this._$el.on(pe()("down"),this._onDragStart),he().on("change",(function(){return e._resetPos(!0)})),window.addEventListener("resize",(function(){return e._resetPos()}))}},{key:"initCfg",value:function(e){var t=this.config=ce.createCfg("entry-button",{rememberPos:!0,pos:this._getDefPos()});e.switch(t,"rememberPos","Remember Entry Button Position"),this._resetPos()}},{key:"_getDefPos",value:function(){var e=this._$el.get(0).offsetWidth+10;return{x:window.innerWidth-e,y:window.innerHeight-e}}}])}(u()),He=n(5458),Ye=n(7622),$e=Le=new(n.n(Ye)())("[Eruda]","warn");Le.formatter=function(e,t){return t.unshift(this.name),t};var qe=n(6097),Qe=n.n(qe),Ue=n(7e3),We=n.n(Ue),Je=n(9931),Ke=n.n(Je),Ve=n(1009),Ze=n.n(Ve),Xe=n(5570),et=n.n(Xe),tt=n(2556),nt=n(1944),ot=n(8052);function rt(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(rt=function(){return!!e})()}var it=function(e){function t(e){var r,s,l,u,d=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},h=d.defaults,f=void 0===h?{}:h,p=d.inline,v=void 0!==p&&p;return(0,o.A)(this,t),s=this,l=t,l=(0,a.A)(l),r=(0,i.A)(s,rt()?Reflect.construct(l,u||[],(0,a.A)(s).constructor):l.apply(s,u)),(0,c.A)(r,"_checkSafeArea",(function(){var e=r.$container;!function(){var e=!1,t=document.createElement("div");if(CSS.supports("padding-bottom: env(safe-area-inset-bottom)")?(t.style.paddingBottom="env(safe-area-inset-bottom)",e=!0):CSS.supports("padding-bottom: constant(safe-area-inset-bottom)")&&(t.style.paddingBottom="constant(safe-area-inset-bottom)",e=!0),e){document.body.appendChild(t);var n=parseInt(window.getComputedStyle(t).paddingBottom);if(document.body.removeChild(t),n>0)return!0}return!1}()?e.rmClass(ze("safe-area")):e.addClass(ze("safe-area"))})),(0,c.A)(r,"_updateTabHeight",(function(e){r._tab.setOption("height",40*e),ue()((function(){r._tab.updateSlider()}))})),r._defCfg=P()({transparency:1,displaySize:80,theme:"System preference"},f),r._style=re(n(541)),r.$container=e,r._isShow=!1,r._opacity=1,r._tools={},r._isResizing=!1,r._resizeTimer=null,r._resizeStartY=0,r._resizeStartSize=0,r._inline=v,r._initTpl(),r._initTab(),r._initNotification(),r._initModal(),et()((function(){return r._checkSafeArea()})),r._bindEvent(),r}return(0,s.A)(t,e),(0,r.A)(t,[{key:"show",value:function(){var e=this;return this._isShow=!0,this._$el.show(),this._tab.updateSlider(),setTimeout((function(){e._$el.css("opacity",e._opacity)}),50),this.emit("show"),this}},{key:"hide",value:function(){var e=this;if(!this._inline)return this._isShow=!1,this.emit("hide"),this._$el.css({opacity:0}),setTimeout((function(){return e._$el.hide()}),300),this}},{key:"toggle",value:function(){return this._isShow?this.hide():this.show()}},{key:"add",value:function(e){var t=this._tab;if(!(e instanceof v)){var n=new v,o=n.init,r=n.show,i=n.hide,a=n.destroy;L()(e,{init:o,show:r,hide:i,destroy:a})}var s=e.name;if(!s)return $e.error("You must specify a name for a tool");if(this._tools[s])return $e.warn("Tool ".concat(s," already exists"));var c=s.replace(/\s+/g,"-");return this._$tools.prepend('
')),e.init(this._$tools.find(".".concat(ze(c),".").concat(ze("tool"))),this),e.active=!1,this._tools[s]=e,"settings"===s?t.append({id:s,title:s}):t.insert(t.length-1,{id:s,title:s}),this}},{key:"remove",value:function(e){var t=this._tools;if(!t[e])return $e.warn("Tool ".concat(e," doesn't exist"));this._tab.remove(e);var n=t[e];if(delete t[e],n.active){var o=D()(t);o.length>0&&this.showTool(t[Ae()(o)].name)}return n.destroy(),this}},{key:"removeAll",value:function(){var e=this;return x()(this._tools,(function(t){return e.remove(t.name)})),this}},{key:"get",value:function(e){var t=this._tools[e];if(t)return t}},{key:"showTool",value:function(e){if(this._curTool===e)return this;this._curTool=e;var t=this._tools,n=t[e];if(n){var o={};return x()(t,(function(e){e.active&&(o=e,e.active=!1,e.hide())})),n.active=!0,n.show(),this._tab.select(e),this.emit("showTool",e,o),this}}},{key:"initCfg",value:function(e){var t=this,n=this.config=ce.createCfg("dev-tools",this._defCfg);this._setTransparency(n.get("transparency")),this._setDisplaySize(n.get("displaySize")),this._setTheme(n.get("theme")),n.on("change",(function(e,n){switch(e){case"transparency":return t._setTransparency(n);case"displaySize":return t._setDisplaySize(n);case"theme":return t._setTheme(n)}})),e.separator().select(n,"theme","Theme",["System preference"].concat((0,He.A)(D()(re.getThemes())))),this._inline||e.range(n,"transparency","Transparency",{min:.2,max:1,step:.01}).range(n,"displaySize","Display Size",{min:40,max:100,step:1}),e.button("Restore defaults and reload",(function(){var e=je("local"),t=JSON.parse(JSON.stringify(e));x()(t,(function(t,n){E()(t)&&Ze()(n,"eruda")&&e.removeItem(n)})),window.location.reload()})).separator()}},{key:"notify",value:function(e,t){this._notification.notify(e,t)}},{key:"destroy",value:function(){re.remove(this._style),this.removeAll(),this._tab.destroy(),this._$el.remove(),window.removeEventListener("resize",this._checkSafeArea),h.off(h.SCALE,this._updateTabHeight)}},{key:"_setTheme",value:function(e){var t=this.$container;"System preference"===e&&(e=Ke()(We().get())),K(e)?t.addClass(ze("dark")):t.rmClass(ze("dark")),re.setTheme(e)}},{key:"_setTransparency",value:function(e){Qe()(e)&&(this._opacity=e,this._isShow&&this._$el.css({opacity:e}))}},{key:"_setDisplaySize",value:function(e){this._inline&&(e=100),Qe()(e)&&this._$el.css({height:e+"%"})}},{key:"_initTpl",value:function(){var e=this.$container;e.append(ze('\n
\n
\n
\n
\n
\n \n
\n ')),this._$el=e.find(ze(".dev-tools")),this._$tools=this._$el.find(ze(".tools"))}},{key:"_initTab",value:function(){var e=this;this._tab=new ot.A(this._$el.find(ze(".tab")).get(0),{height:40}),this._tab.on("select",(function(t){return e.showTool(t)}))}},{key:"_initNotification",value:function(){this._notification=new tt.A(this._$el.find(ze(".notification")).get(0),{position:{x:"center",y:"top"}})}},{key:"_initModal",value:function(){nt.A.setContainer(this._$el.find(ze(".modal")).get(0))}},{key:"_bindEvent",value:function(){var e=this,t=this._$el.find(ze(".resizer")),n=this._$el.find(ze(".nav-bar")),o=m()(document);this._inline&&t.hide();var r=function(t){if(e._isResizing){t.preventDefault(),t.stopPropagation(),t=t.origEvent;var n=(e._resizeStartY-Fe("y",t))/window.innerHeight*100,o=e._resizeStartSize+n;o<40?o=40:o>100&&(o=100),e.config.set("displaySize",Se()(o.toFixed(2)))}},i=function(){clearTimeout(e._resizeTimer),e._isResizing=!1,t.css("height",10),o.off(pe()("move"),r),o.off(pe()("up"),i)};t.css("height",10),t.on(pe()("down"),(function(n){n.preventDefault(),n.stopPropagation(),n=n.origEvent,e._isResizing=!0,e._resizeStartSize=e.config.get("displaySize"),e._resizeStartY=Fe("y",n),t.css("height","100%"),o.on(pe()("move"),r),o.on(pe()("up"),i)})),n.on("contextmenu",(function(e){return e.preventDefault()})),this.$container.on("click",(function(e){return e.stopPropagation()})),window.addEventListener("resize",this._checkSafeArea),h.on(h.SCALE,this._updateTabHeight),We().on("change",(function(){var t=e.config.get("theme");"System preference"===t&&e._setTheme(t)}))}}])}(u()),at=n(9993),st=n.n(at),ct=n(3957),lt=n.n(ct),ut=n(1976),dt=n.n(ut),ht=n(6962),ft=n.n(ht),pt=n(8609),vt=n.n(pt),gt=n(4236),mt=n.n(gt),bt=n(3578);function yt(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(yt=function(){return!!e})()}function At(e,t,n,o){var r=(0,f.A)((0,a.A)(1&o?e.prototype:e),t,n);return 2&o&&"function"==typeof r?function(e){return r.apply(n,e)}:r}ft().start();var wt=function(e){function t(){var e,n,r,s,l=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).name,d=void 0===l?"console":l;return(0,o.A)(this,t),n=this,r=t,r=(0,a.A)(r),e=(0,i.A)(n,yt()?Reflect.construct(r,s||[],(0,a.A)(n).constructor):r.apply(n,s)),(0,c.A)(e,"_handleShow",(function(){vt()(e._$el.get(0))||e._logger.renderViewport()})),(0,c.A)(e,"_handleErr",(function(t){e._logger.error(t)})),u().mixin(e),e.name=d,e._selectedLog=null,e}return(0,s.A)(t,e),(0,r.A)(t,[{key:"init",value:function(e,n){At(t,"init",this,3)([e]),this._container=n,this._appendTpl(),this._initCfg(),this._initLogger(),this._exposeLogger(),this._bindEvent()}},{key:"show",value:function(){At(t,"show",this,3)([]),this._handleShow()}},{key:"overrideConsole",value:function(){var e=this,t=this._origConsole={},n=window.console;return _t.forEach((function(o){var r=t[o]=st();n[o]&&(r=t[o]=n[o].bind(n)),n[o]=function(){e[o].apply(e,arguments),r.apply(void 0,arguments)}})),this}},{key:"setGlobal",value:function(e,t){this._logger.setGlobal(e,t)}},{key:"restoreConsole",value:function(){var e=this;return this._origConsole?(_t.forEach((function(t){return window.console[t]=e._origConsole[t]})),delete this._origConsole,this):this}},{key:"catchGlobalErr",value:function(){return ft().addListener(this._handleErr),this}},{key:"ignoreGlobalErr",value:function(){return ft().rmListener(this._handleErr),this}},{key:"filter",value:function(e){var t=this._$filterText,n=this._logger;E()(e)?(t.text(e),n.setOption("filter",Te()(e))):dt()(e)?(t.text(I()(e)),n.setOption("filter",e)):lt()(e)&&(t.text("ƒ"),n.setOption("filter",e))}},{key:"destroy",value:function(){this._logger.destroy(),At(t,"destroy",this,3)([]),this._container.off("show",this._handleShow),this._style&&re.remove(this._style),this.ignoreGlobalErr(),this.restoreConsole(),this._rmCfg()}},{key:"_enableJsExecution",value:function(e){var t=this._$el,n=t.find(ze(".js-input"));e?(n.show(),t.rmClass(ze("js-input-hidden"))):(n.hide(),t.addClass(ze("js-input-hidden")))}},{key:"_appendTpl",value:function(){var e=this._$el;this._style=re(n(6567)),e.append(ze('\n
\n \n All\n Info\n Warning\n Error\n \n \n \n
\n
\n
\n
\n
Cancel
\n
Execute
\n
\n \n \n
\n '));var t=e.find(ze(".js-input")),o=t.find("textarea"),r=t.find(ze(".buttons"));P()(this,{_$control:e.find(ze(".control")),_$logs:e.find(ze(".logs-container")),_$inputContainer:t,_$input:o,_$inputBtns:r,_$filterText:e.find(ze(".filter-text"))})}},{key:"_initLogger",value:function(){var e=this.config,t=e.get("maxLogNum");t="infinite"===t?0:+t;var n=this._$control.find(ze(".level")),o=new bt.A(this._$logs.get(0),{asyncRender:e.get("asyncRender"),maxNum:t,showHeader:e.get("displayExtraInfo"),unenumerable:e.get("displayUnenumerable"),accessGetter:e.get("displayGetterVal"),lazyEvaluation:e.get("lazyEvaluation")});o.on("optionChange",(function(e,t){if("level"===e)n.each((function(){var e=m()(this),n=e.data("level");e[n===t||"all"===n&&Y()(t)?"addClass":"rmClass"](ze("active"))}))})),e.get("overrideConsole")&&this.overrideConsole(),this._logger=o}},{key:"_exposeLogger",value:function(){var e=this,t=this._logger;["html"].concat(_t).forEach((function(n){return e[n]=function(){for(var o=arguments.length,r=new Array(o),i=0;i').concat(Tt()(e.data),""));var n="Empty";e.reqHeaders&&(n=_e()(e.reqHeaders,(function(e,t){return'\n ').concat(Tt()(t),"\n ").concat(Tt()(e),"\n ")})).join(""));var o="Empty";e.resHeaders&&(o=_e()(e.resHeaders,(function(e,t){return'\n ').concat(Tt()(t),"\n ").concat(Tt()(e),"\n ")})).join(""));var r="";if(e.resTxt){var i=e.resTxt;i.length>Ft&&(i=zt()(i,Ft)),r='
').concat(Tt()(i),"
")}var a='
\n \n \n ').concat(Tt()(e.url),'\n \n
\n
\n ').concat(t,'\n
\n

Response Headers

\n \n \n ').concat(o,'\n \n
\n
\n
\n

Request Headers

\n \n \n ').concat(n,"\n \n
\n
\n ").concat(r,"\n
");this._$container.html(a).show(),this._detailData=e}},{key:"hide",value:function(){this._$container.hide(),this.emit("hide")}},{key:"_bindEvent",value:function(){var e=this,t=this._devtools;this._$container.on("click",ze(".back"),(function(){return e.hide()})).on("click",ze(".copy-res"),this._copyRes).on("click",ze(".http .response"),(function(){var t=e._detailData,o=t.resTxt;if(Mt()(o))return n("object",o);switch(t.subType){case"css":return n("css",o);case"html":return n("html",o);case"javascript":return n("js",o);case"json":return n("object",o)}return"image"===t.type?n("img",t.url):void 0}));var n=function(e,n){var o=t.get("sources");o&&(o.set(e,n),t.showTool("sources"))}}}])}(u()),Ft=1e5,Rt=n(5865),Lt=n.n(Rt),Gt=n(6476),Pt=n.n(Gt),Ht=n(5334),Yt=n(2480),$t=n(6192),qt=n(5689);function Qt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function Ut(e){for(var t=1;t=300)&&(n.hasErr=!0),i&&(n.resHeaders=i,e._updateType(n)),n.render()}})),(0,c.A)(e,"_loadingFinished",(function(t){var n=e._requests[t.requestId];if(e._isRecording&&n){var o=1e3*t.timestamp;n.time=o-n.startTime,n.displayTime=kt()(n.time),n.size=t.encodedDataLength,n.done=!0,n.resTxt=Jt.domain("Network").getResponseBody({requestId:t.requestId}).body,n.render()}})),(0,c.A)(e,"_loadingFailed",(function(t){var n=e._requests[t.requestId];if(e._isRecording&&n){var o=1e3*t.timestamp;n.time=o-n.startTime,n.displayTime=kt()(n.time),n.hasErr=!0,n.status=0,n.done=!0,n.render()}})),(0,c.A)(e,"_copyCurl",(function(){var t=e._selectedRequest;Ot()(function(e){var t=nn()();"windows"===t&&(t="win");var n=[],o=rn()(["accept-encoding","host","method","path","scheme","version"]),r="win"===t?function(e){var t=/[\r\n]/.test(e)?'^"':'"';return t+e.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/[^a-zA-Z0-9\s_\-:=+~'/.',?;()*`&]/g,"^$&").replace(/%(?=[a-zA-Z0-9_])/g,"%^").replace(/\r?\n/g,"^\n\n")+t}:function(e){return/[\0-\x1F\x7F-\x9F!]|'/.test(e)?"$'"+e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/[\0-\x1F\x7F-\x9F!]/g,(function(e){for(var t=e.charCodeAt(0).toString(16);t.length<4;)t="0"+t;return"\\u"+t}))+"'":"'"+e+"'"};n.push(r(e.url()).replace(/[[{}\]]/g,"\\$&"));var i="GET",a=[],s=e.requestFormData();s&&(a.push("--data-raw "+r(s)),o["content-length"]=!0,i="POST"),e.requestMethod!==i&&n.push("-X "+r(e.requestMethod));for(var c=e.requestHeaders(),l=0;l=3?"win"===t?" ^\n ":" \\\n ":" ")}({requestMethod:t.method,url:function(){return t.url},requestFormData:function(){return t.data},requestHeaders:function(){var e=t.reqHeaders||{};return P()(e,{"User-Agent":navigator.userAgent,Referer:location.href}),_e()(e,(function(e,t){return{name:t,value:e}}))}})),e._container.notify("Copied",{icon:"success"})})),(0,c.A)(e,"_toggleRecording",(function(){e._$control.find(ze(".record")).toggleClass(ze("recording")),e._isRecording=!e._isRecording})),(0,c.A)(e,"_showDetail",(function(){e._selectedRequest&&(e._splitMode&&e._$network.css("width","50%"),e._detail.show(e._selectedRequest))})),(0,c.A)(e,"_updateScale",(function(t){e._splitMediaQuery.setQuery("screen and (min-width: ".concat(680*t,"px)"))})),e._style=re(n(8239)),e.name="network",e._requests={},e._selectedRequest=null,e._isRecording=!0,e}return(0,s.A)(t,e),(0,r.A)(t,[{key:"init",value:function(e,n){sn(t,"init",this,3)([e]),this._container=n,this._initTpl(),this._detail=new Bt(this._$detail,n),this._splitMediaQuery=new(en())("screen and (min-width: 680px)"),this._splitMode=this._splitMediaQuery.isMatch(),this._requestDataGrid=new Kt.A(this._$requests.get(0),{columns:[{id:"name",title:"Name",sortable:!0,weight:30},{id:"method",title:"Method",sortable:!0,weight:14},{id:"status",title:"Status",sortable:!0,weight:14},{id:"type",title:"Type",sortable:!0,weight:14},{id:"size",title:"Size",sortable:!0,weight:14},{id:"time",title:"Time",sortable:!0,weight:14}]}),this._resizeSensor=new(Zt())(e.get(0)),this._bindEvent()}},{key:"show",value:function(){sn(t,"show",this,3)([]),this._updateDataGridHeight()}},{key:"clear",value:function(){this._requests={},this._requestDataGrid.clear()}},{key:"requests",value:function(){var e=[];return x()(this._requests,(function(t){e.push(t)})),e}},{key:"_updateDataGridHeight",value:function(){this._requestDataGrid.fit()}},{key:"_updateType",value:function(e){var t=function(e){if(!e)return"unknown";var t=e.split(";")[0].split("/");return{type:t[0],subType:Ae()(t)}}(e.resHeaders["content-type"]||""),n=t.type,o=t.subType;e.type=n,e.subType=o}},{key:"_updateButtons",value:function(){var e=this._$control,t=e.find(ze(".show-detail")),n=e.find(ze(".copy-curl")),o=ze("icon-disabled");t.addClass(o),n.addClass(o),this._selectedRequest&&(t.rmClass(o),n.rmClass(o))}},{key:"_bindEvent",value:function(){var e=this,t=this._$control,n=this._$filterText,o=this._requestDataGrid,r=this;t.on("click",ze(".clear-request"),(function(){return e.clear()})).on("click",ze(".show-detail"),this._showDetail).on("click",ze(".copy-curl"),this._copyCurl).on("click",ze(".record"),this._toggleRecording).on("click",ze(".filter"),(function(){nt.A.prompt("Filter").then((function(e){mt()(e)||(n.text(e),o.setOption("filter",Te()(e)))}))})),o.on("select",(function(t){var n=m()(t.container).data("id"),o=r._requests[n];e._selectedRequest=o,e._updateButtons(),e._splitMode&&e._showDetail()})),o.on("deselect",(function(){e._selectedRequest=null,e._updateButtons(),e._detail.hide()})),this._resizeSensor.addListener(Lt()((function(){return e._updateDataGridHeight()}),15)),this._splitMediaQuery.on("match",(function(){e._detail.hide(),e._splitMode=!0})),this._splitMediaQuery.on("unmatch",(function(){e._detail.hide(),e._splitMode=!1})),this._detail.on("hide",(function(){e._splitMode&&e._$network.css("width","100%")})),Jt.domain("Network").enable();var i=Jt.domain("Network");i.on("requestWillBeSent",this._reqWillBeSent),i.on("responseReceivedExtraInfo",this._resReceivedExtraInfo),i.on("responseReceived",this._resReceived),i.on("loadingFinished",this._loadingFinished),i.on("loadingFailed",this._loadingFailed),h.on(h.SCALE,this._updateScale)}},{key:"destroy",value:function(){sn(t,"destroy",this,3)([]),this._resizeSensor.destroy(),re.remove(this._style),this._splitMediaQuery.removeAllListeners();var e=Jt.domain("Network");e.off("requestWillBeSent",this._reqWillBeSent),e.off("responseReceivedExtraInfo",this._resReceivedExtraInfo),e.off("responseReceived",this._resReceived),e.off("loadingFinished",this._loadingFinished),h.off(h.SCALE,this._updateScale)}},{key:"_initTpl",value:function(){var e=this._$el;e.html(ze('
\n
\n \n \n \n \n \n \n
\n
\n
\n
')),this._$network=e.find(ze(".network")),this._$detail=e.find(ze(".detail")),this._$requests=e.find(ze(".requests")),this._$control=e.find(ze(".control")),this._$filterText=e.find(ze(".filter-text"))}}])}(v),ln=n(2708),un=n.n(ln),dn=n(1167),hn=n.n(dn),fn=n(7181),pn=n.n(fn),vn=n(5784),gn=n(96),mn=n.n(gn),bn=n(896),yn=n.n(bn),An=n(438),wn=n.n(An),_n=n(6493),xn=n.n(_n),kn=n(6186),Cn=n.n(kn),Sn=n(5241),En=n.n(Sn),Tn=n(2208),Nn=n.n(Tn),On=n(5145),jn=n.n(On);function Mn(e){for(var t={},n=0,o=e.length;no?o:n,i=0;io?1:n(t=Fn(t))?1:e1&&void 0!==arguments[1]?arguments[1]:{}).noAttr,n=void 0!==t&&t;if(e.nodeType===Node.TEXT_NODE)return'(text)');if(e.nodeType===Node.COMMENT_NODE)return'\x3c!--\x3e');if(pn()(e))return'#shadow-root');var o=e.id,r=e.className,i=e.attributes,a=''.concat(e.tagName.toLowerCase(),"");if(""!==o&&(a+='#'.concat(o,"")),E()(r)){var s="";x()(r.split(/\s+/g),(function(e){""!==e.trim()&&(s+=".".concat(e))})),a+=''.concat(s,"")}return n||x()(i,(function(e){var t=e.name;"id"!==t&&"class"!==t&&"style"!==t&&(a+=' '.concat(t,'="').concat(e.value,'"'))})),a}var Gn=function(){return(0,r.A)((function e(t,n){var r=this;(0,o.A)(this,e),(0,c.A)(this,"hide",(function(){r._$container.hide(),r._disableObserver(),Jt.domain("Overlay").hideHighlight()})),(0,c.A)(this,"_highlight",(function(e){var t=r._curEl,n={showInfo:!1};e&&"all"!==e?"margin"===e?n.marginColor="rgba(246, 178, 107, .66)":"border"===e?n.borderColor="rgba(255, 229, 153, .66)":"padding"===e?n.paddingColor="rgba(147, 196, 125, .55)":"content"===e&&(n.contentColor="rgba(111, 168, 220, .66)"):P()(n,{showInfo:!0,contentColor:"rgba(111, 168, 220, .66)",paddingColor:"rgba(147, 196, 125, .55)",borderColor:"rgba(255, 229, 153, .66)",marginColor:"rgba(246, 178, 107, .66)"});var o=Jt.domain("DOM").getNodeId({node:t}).nodeId;Jt.domain("Overlay").highlightNode({nodeId:o,highlightConfig:n})})),this._$container=t,this._devtools=n,this._curEl=document.documentElement,this._initObserver(),this._initCfg(),this._initTpl(),this._bindEvent()}),[{key:"show",value:function(e){this._curEl=e,this._rmDefComputedStyle=!0,this._computedStyleSearchKeyword="",this._enableObserver(),this._render(),this._highlight()}},{key:"destroy",value:function(){this._disableObserver(),this.restoreEventTarget(),this._rmCfg()}},{key:"overrideEventTarget",value:function(){var e=Jn(),t=this._origAddEvent=e.addEventListener,n=this._origRmEvent=e.removeEventListener;e.addEventListener=function(e,n,o){!function(e,t,n){var o=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(!un()(e)||!lt()(n)||!xn()(o))return;var r=e.erudaEvents=e.erudaEvents||{};r[t]=r[t]||[],r[t].push({listener:n,listenerStr:n.toString(),useCapture:o})}(this,e,n,o),t.apply(this,arguments)},e.removeEventListener=function(e,t,o){!function(e,t,n){var o=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(!un()(e)||!lt()(n)||!xn()(o))return;var r=e.erudaEvents;if(!r||!r[t])return;for(var i=r[t],a=0,s=i.length;a\n \n \n \n \n
\n
\n
\n
\n
\n
');e.html(t),this._$elementName=e.find(ze(".element-name")),this._$attributes=e.find(ze(".attributes")),this._$styles=e.find(ze(".styles")),this._$listeners=e.find(ze(".listeners")),this._$computedStyle=e.find(ze(".computed-style"));var n=En()("div");this._$boxModel=m()(n),this._boxModel=new Rn.A(n)}},{key:"_toggleAllComputedStyle",value:function(){this._rmDefComputedStyle=!this._rmDefComputedStyle,this._render()}},{key:"_render",value:function(){var e=this._getData(this._curEl),t=this._$attributes,n=this._$elementName,o=this._$styles,r=this._$computedStyle,i=this._$listeners;n.html(e.name);var a="Empty";St()(e.attributes)||(a=_e()(e.attributes,(function(e){var t=e.name,n=e.value;return'\n ').concat(Tt()(t),'\n ').concat(n,"\n ")})).join("")),a='

Attributes

\n
\n \n \n ').concat(a," \n \n
\n
"),t.html(a);var s="";if(St()(e.styles))o.hide();else{var c=_e()(e.styles,(function(e){var t=e.selectorText,n=e.style;return n=_e()(n,(function(e,t){return'
').concat(Tt()(t),": ").concat(e,";
")})).join(""),'
\n
').concat(Tt()(t)," {
\n ").concat(n,"\n
}
\n
")})).join("");s='

Styles

\n
\n ').concat(c,"\n
"),o.html(s).show()}var l="";if(e.computedStyle){var u=ze('
\n \n
');e.rmDefComputedStyle&&(u=ze('
\n \n
')),l="

\n Computed Style\n ".concat(u,'\n
\n \n
\n ').concat(e.computedStyleSearchKeyword?'
').concat(Tt()(e.computedStyleSearchKeyword),"
"):"",'\n

\n
\n
\n \n \n ').concat(_e()(e.computedStyle,(function(e,t){return'\n \n \n ")})).join(""),"\n \n
').concat(Tt()(t),"").concat(e,"
\n
"),r.html(l).show(),this._boxModel.setOption("element",this._curEl),r.find(ze(".box-model")).append(this._$boxModel.get(0))}else r.text("").hide();var d="";e.listeners?(d=_e()(e.listeners,(function(e,t){return e=_e()(e,(function(e){var t=e.useCapture,n=e.listenerStr;return"
  • ").concat(Tt()(n),"
  • ")})).join(""),'
    \n
    ').concat(Tt()(t),'
    \n
      \n ').concat(e,"\n
    \n
    ")})).join(""),d='

    Event Listeners

    \n
    \n ').concat(d," \n
    "),i.html(d).show()):i.hide(),this._$container.show()}},{key:"_getData",value:function(e){var t={},n=new Dn(e),o=e.className,r=e.id,i=e.attributes,a=e.tagName;t.computedStyleSearchKeyword=this._computedStyleSearchKeyword,t.attributes=Hn(i),t.name=Ln({tagName:a,id:r,className:o,attributes:i});var s=e.erudaEvents;if(s&&0!==D()(s).length&&(t.listeners=s),Un(a))return t;var c=n.getComputedStyle(),l=n.getMatchedCSSRules();l.unshift(function(e){for(var t={selectorText:"element.style",style:{}},n=0,o=e.length;n
    $&').replace($n,(function(e,t){return'url("'.concat(Wn(t),'")')}))}var Qn=["script","style","meta","title","link","head"],Un=function(e){Qn.indexOf(e.toLowerCase())},Wn=function(e){return'').concat(e,"")};var Jn=function(){return Cn()(window,"EventTarget.prototype")||window.Node.prototype};function Kn(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(Kn=function(){return!!e})()}function Vn(e,t,n,o){var r=(0,f.A)((0,a.A)(1&o?e.prototype:e),t,n);return 2&o&&"function"==typeof r?function(e){return r.apply(n,e)}:r}var Zn=function(e){function t(){var e,r,s,l;return(0,o.A)(this,t),r=this,s=t,s=(0,a.A)(s),e=(0,i.A)(r,Kn()?Reflect.construct(s,l||[],(0,a.A)(r).constructor):s.apply(r,l)),(0,c.A)(e,"_showDetail",(function(){e._isShow&&e._curNode&&(e._curNode.nodeType===Node.ELEMENT_NODE?e._detail.show(e._curNode):e._detail.show(e._curNode.parentNode||e._curNode.host))})),(0,c.A)(e,"_back",(function(){if(e._curNode!==e._htmlEl){for(var t=e._curParentQueue,n=t.shift();!Xn(n);)n=t.shift();e.set(n)}})),(0,c.A)(e,"_updateScale",(function(t){e._splitMediaQuery.setQuery("screen and (min-width: ".concat(680*t,"px)"))})),(0,c.A)(e,"_deleteNode",(function(){var t=e._curNode;t.parentNode&&t.parentNode.removeChild(t)})),(0,c.A)(e,"_copyNode",(function(){var t=e._curNode;t.nodeType===Node.ELEMENT_NODE?Ot()(t.outerHTML):Ot()(t.nodeValue),e._container.notify("Copied",{icon:"success"})})),(0,c.A)(e,"_toggleSelect",(function(){e._$el.find(ze(".select")).toggleClass(ze("active")),e._selectElement=!e._selectElement,e._selectElement?(Jt.domain("Overlay").setInspectMode({mode:"searchForNode",highlightConfig:{showInfo:!hn()(),showRulers:!1,showAccessibilityInfo:!hn()(),showExtensionLines:!1,contrastAlgorithm:"aa",contentColor:"rgba(111, 168, 220, .66)",paddingColor:"rgba(147, 196, 125, .55)",borderColor:"rgba(255, 229, 153, .66)",marginColor:"rgba(246, 178, 107, .66)"}}),e._container.hide()):(Jt.domain("Overlay").setInspectMode({mode:"none"}),Jt.domain("Overlay").hideHighlight())})),(0,c.A)(e,"_inspectNodeRequested",(function(t){var n=t.backendNodeId;e._container.show(),e._toggleSelect();try{var o=Jt.domain("DOM").getNode({nodeId:n}).node;e.select(o)}catch(e){}})),(0,c.A)(e,"_setNode",(function(t){if(t!==e._curNode){e._curNode=t,e._renderCrumbs();for(var n=[],o=t.parentNode;o;)n.push(o),o=o.parentNode;e._curParentQueue=n,e._splitMode&&e._showDetail(),e._updateButtons(),e._updateHistory()}})),e._style=re(n(9111)),e.name="elements",e._selectElement=!1,e._observeElement=!0,e._history=[],u().mixin(e),e}return(0,s.A)(t,e),(0,r.A)(t,[{key:"init",value:function(e,n){var o=this;Vn(t,"init",this,3)([e]),this._container=n,this._initTpl(),this._htmlEl=document.documentElement,this._detail=new Gn(this._$detail,n),this.config=this._detail.config,this._splitMediaQuery=new(en())("screen and (min-width: 680px)"),this._splitMode=this._splitMediaQuery.isMatch(),this._domViewer=new vn.A(this._$domViewer.get(0),{node:this._htmlEl,ignore:function(e){return Ie(e)||function(e){for(;e;){var t="";if(e.getAttribute&&(t=e.getAttribute("class")||""),N()(t,"__chobitsu-hide__"))return!0;e=e.parentNode}return!1}(e)}}),this._domViewer.expand(),this._bindEvent(),Jt.domain("Overlay").enable(),ue()((function(){return o._updateHistory()}))}},{key:"show",value:function(){Vn(t,"show",this,3)([]),this._isShow=!0,this._curNode?this._splitMode&&this._showDetail():this.select(document.body)}},{key:"hide",value:function(){Vn(t,"hide",this,3)([]),this._isShow=!1,Jt.domain("Overlay").hideHighlight()}},{key:"select",value:function(e){return this._domViewer.select(e),this._setNode(e),this.emit("change",e),this}},{key:"destroy",value:function(){Vn(t,"destroy",this,3)([]),h.off(h.SCALE,this._updateScale),re.remove(this._style),this._detail.destroy(),Jt.domain("Overlay").off("inspectNodeRequested",this._inspectNodeRequested),Jt.domain("Overlay").disable(),this._splitMediaQuery.removeAllListeners()}},{key:"_updateButtons",value:function(){var e=this._$control,t=e.find(ze(".show-detail")),n=e.find(ze(".copy-node")),o=e.find(ze(".delete-node")),r=ze("icon-disabled");t.addClass(r),n.addClass(r),o.addClass(r);var i=this._curNode;i&&!pn()(i)&&(i!==document.documentElement&&i!==document.body&&o.rmClass(r),n.rmClass(r),i.nodeType===Node.ELEMENT_NODE&&t.rmClass(r))}},{key:"_initTpl",value:function(){var e=this._$el;e.html(ze('
    \n
    \n \n \n \n \n
    \n
    \n
    \n
    \n
    \n
    \n
    ')),this._$detail=e.find(ze(".detail")),this._$domViewer=e.find(ze(".dom-viewer")),this._$control=e.find(ze(".control")),this._$crumbs=e.find(ze(".crumbs"))}},{key:"_renderCrumbs",value:function(){var e=function(e){var t=[],n=0;for(;e;)t.push({text:Ln(e,{noAttr:!0}),idx:n++}),pn()(e)&&(e=e.host),e=!e.parentElement&&pn()(e.parentNode)?e.parentNode:e.parentElement;return t.reverse()}(this._curNode),t="";St()(e)||(t=_e()(e,(function(e){var t=e.text,n=e.idx;return'
  • ').concat(t,"
  • ")})).join("")),this._$crumbs.html(t)}},{key:"_bindEvent",value:function(){var e=this,t=this;this._$el.on("click",ze(".crumb"),(function(){for(var e=Se()(m()(this).data("idx")),n=t._curNode;e--&&n.parentElement;)n=n.parentElement;Xn(n)&&t.select(n)})),this._$control.on("click",ze(".select"),this._toggleSelect).on("click",ze(".show-detail"),this._showDetail).on("click",ze(".copy-node"),this._copyNode).on("click",ze(".delete-node"),this._deleteNode),this._domViewer.on("select",this._setNode).on("deselect",this._back),Jt.domain("Overlay").on("inspectNodeRequested",this._inspectNodeRequested),this._splitMediaQuery.on("match",(function(){e._splitMode=!0,e._showDetail()})),this._splitMediaQuery.on("unmatch",(function(){e._splitMode=!1,e._detail.hide()})),h.on(h.SCALE,this._updateScale)}},{key:"_updateHistory",value:function(){var e=this._container.get("console");if(e){var t=this._history;t.unshift(this._curNode),t.length>5&&t.pop();for(var n=0;n<5;n++)e.setGlobal("$".concat(n),t[n])}}}])}(v),Xn=function(e){return un()(e)&&e.parentNode};var eo=n(3981),to=n.n(eo),no=n(4866),oo=n.n(no),ro=null,io=[{name:"Border All",fn:function(){if(ro)return re.remove(ro),void(ro=null);ro=re("* { outline: 2px dashed #707d8b; outline-offset: -3px; }",document.head)},desc:"Add color borders to all elements"},{name:"Refresh Page",fn:function(){var e=new(ge());e.setQuery("timestamp",to()()),window.location.replace(e.toString())},desc:"Add timestamp to url and refresh"},{name:"Search Text",fn:function(){nt.A.prompt("Enter the text").then((function(e){var t,n,o;e&&""!==Te()(e)&&(t=e,n=document.body,o=new RegExp(t,"ig"),ao(n,(function(e){var t=m()(e);if(t.hasClass("eruda-search-highlight-block"))return document.createTextNode(t.text())})),ao(n,(function(e){if(3===e.nodeType){var t=e.nodeValue;if((t=t.replace(o,(function(e){return''.concat(e,"")})))!==e.nodeValue){var n=m()(document.createElement("div"));return n.html(t),n.addClass("eruda-search-highlight-block"),n.get(0)}}})))}))},desc:"Highlight given text on page"},{name:"Edit Page",fn:function(){var e=document.body;e.contentEditable="true"!==e.contentEditable},desc:"Toggle body contentEditable"},{name:"Fit Screen",fn:function(){var e=document.body,t=document.documentElement,n=m()(e);if(n.data("scaled"))window.scrollTo(0,+n.data("scaled")),n.rmAttr("data-scaled"),n.css("transform","none");else{var o=Math.max(e.scrollHeight,e.offsetHeight,t.clientHeight,t.scrollHeight,t.offsetHeight),r=Math.max(document.documentElement.clientHeight,window.innerHeight||0),i=r/o;n.css("transform","scale(".concat(i,")")),n.data("scaled",window.scrollY),window.scrollTo(0,o/2-r/2)}},desc:"Scale down the whole page to fit screen"},{name:"Load Vue Plugin",fn:function(){so("vue")},desc:"Vue devtools"},{name:"Load Monitor Plugin",fn:function(){so("monitor")},desc:"Display page fps, memory and dom nodes"},{name:"Load Features Plugin",fn:function(){so("features")},desc:"Browser feature detections"},{name:"Load Timing Plugin",fn:function(){so("timing")},desc:"Show performance and resource timing"},{name:"Load Code Plugin",fn:function(){so("code")},desc:"Edit and run JavaScript"},{name:"Load Benchmark Plugin",fn:function(){so("benchmark")},desc:"Run JavaScript benchmarks"},{name:"Load Geolocation Plugin",fn:function(){so("geolocation")},desc:"Test geolocation"},{name:"Load Orientation Plugin",fn:function(){so("orientation")},desc:"Test orientation api"},{name:"Load Touches Plugin",fn:function(){so("touches")},desc:"Visualize screen touches"}];function ao(e,t){var n=e.childNodes;if(!Ie(e)){for(var o=0,r=n.length;o\n

    ').concat(Tt()(e.name),'\n
    \n \n
    \n

    \n
    \n ').concat(Tt()(e.desc),"\n
    \n ")})).join("");this._renderHtml(e)}},{key:"_renderHtml",value:function(e){e!==this._lastHtml&&(this._lastHtml=e,this._$el.html(e))}}])}(v),vo=n(4497),go=n.n(vo),mo=n(311),bo=n.n(mo),yo=n(769),Ao=n.n(yo),wo=n(4069),_o=n.n(wo),xo=function(){return(0,r.A)((function e(t,n,r,i){var a=this;(0,o.A)(this,e),(0,c.A)(this,"_updateGridHeight",(function(e){a._dataGrid.setOption({minHeight:60*e,maxHeight:223*e})})),this._type=i,this._$container=t,this._devtools=n,this._resources=r,this._selectedItem=null,this._storeData=[],this._initTpl(),this._dataGrid=new Kt.A(this._$dataGrid.get(0),{columns:[{id:"key",title:"Key",weight:30},{id:"value",title:"Value",weight:90}],minHeight:60,maxHeight:223}),this._bindEvent()}),[{key:"destroy",value:function(){h.off(h.SCALE,this._updateGridHeight)}},{key:"refresh",value:function(){var e=this._dataGrid;this._refreshStorage(),e.clear(),x()(this._storeData,(function(t){var n=t.key,o=t.val;e.append({key:n,value:o},{selectable:!0})}))}},{key:"_refreshStorage",value:function(){var e=this._resources,t=je(this._type,!1);if(t){var n=[];t=JSON.parse(JSON.stringify(t)),x()(t,(function(t,o){E()(t)&&(e.config.get("hideErudaSetting")&&(Ze()(o,"eruda")||"active-eruda"===o)||n.push({key:o,val:zt()(t,200)}))})),this._storeData=n}}},{key:"_updateButtons",value:function(){var e=this._$container,t=e.find(ze(".show-detail")),n=e.find(ze(".delete-storage")),o=e.find(ze(".copy-storage")),r=ze("btn-disabled");t.addClass(r),n.addClass(r),o.addClass(r),this._selectedItem&&(t.rmClass(r),n.rmClass(r),o.rmClass(r))}},{key:"_initTpl",value:function(){var e=this._$container,t=this._type;e.html(ze('

    \n '.concat("local"===t?"Local":"Session",' Storage\n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n \n
    \n
    \n

    \n
    '))),this._$dataGrid=e.find(ze(".data-grid")),this._$filterText=e.find(ze(".filter-text"))}},{key:"_getVal",value:function(e){return"local"===this._type?localStorage.getItem(e):sessionStorage.getItem(e)}},{key:"_bindEvent",value:function(){var e=this,t=this._type,n=this._devtools;function o(e,t){var o=n.get("sources");if(o)return o.set(e,t),n.showTool("sources"),!0}this._$container.on("click",ze(".refresh-storage"),(function(){n.notify("Refreshed",{icon:"success"}),e.refresh()})).on("click",ze(".clear-storage"),(function(){x()(e._storeData,(function(e){"local"===t?localStorage.removeItem(e.key):sessionStorage.removeItem(e.key)})),e.refresh()})).on("click",ze(".show-detail"),(function(){var t=e._selectedItem,n=e._getVal(t);try{o("object",JSON.parse(n))}catch(e){o("raw",n)}})).on("click",ze(".copy-storage"),(function(){var t=e._selectedItem;Ot()(e._getVal(t)),n.notify("Copied",{icon:"success"})})).on("click",ze(".filter"),(function(){nt.A.prompt("Filter").then((function(t){mt()(t)||(t=Te()(t),e._$filterText.text(t),e._dataGrid.setOption("filter",t))}))})).on("click",ze(".delete-storage"),(function(){var n=e._selectedItem;"local"===t?localStorage.removeItem(n):sessionStorage.removeItem(n),e.refresh()})),this._dataGrid.on("select",(function(t){e._selectedItem=t.data.key,e._updateButtons()})).on("deselect",(function(){e._selectedItem=null,e._updateButtons()})),h.on(h.SCALE,this._updateGridHeight)}}])}();function ko(e,t){e.rmClass(ze("ok")).rmClass(ze("danger")).rmClass(ze("warn")).addClass(ze(t))}function Co(e,t){if(0===t)return"";var n=0,o=0;switch(e){case"cookie":n=30,o=60;break;case"script":n=5,o=10;break;case"stylesheet":n=4,o=8;break;case"image":n=50,o=100}return t>=o?"danger":t>=n?"warn":"ok"}var So=function(){return(0,r.A)((function e(t,n){(0,o.A)(this,e),this._$container=t,this._devtools=n,this._selectedItem=null,this._initTpl(),this._dataGrid=new Kt.A(this._$dataGrid.get(0),{columns:[{id:"key",title:"Key",weight:30},{id:"value",title:"Value",weight:90}],minHeight:60,maxHeight:223}),this._bindEvent()}),[{key:"refresh",value:function(){var e=this._$container,t=this._dataGrid,n=Jt.domain("Network").getCookies().cookies,o=_e()(n,(function(e){return{key:e.name,val:e.value}}));t.clear(),x()(o,(function(e){var n=e.key,o=e.val;t.append({key:n,value:o},{selectable:!0})})),ko(e,Co("cookie",o.length))}},{key:"_initTpl",value:function(){var e=this._$container;e.html(ze('

    \n Cookie\n \n
    \n \n
    \n \n \n \n
    \n \n
    \n
    \n

    \n
    ')),this._$dataGrid=e.find(ze(".data-grid")),this._$filterText=e.find(ze(".filter-text"))}},{key:"_updateButtons",value:function(){var e=this._$container,t=e.find(ze(".show-detail")),n=e.find(ze(".delete-cookie")),o=e.find(ze(".copy-cookie")),r=ze("btn-disabled");t.addClass(r),n.addClass(r),o.addClass(r),this._selectedItem&&(t.rmClass(r),n.rmClass(r),o.rmClass(r))}},{key:"_getVal",value:function(e){for(var t=Jt.domain("Network").getCookies().cookies,n=0,o=t.length;n=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(e){throw e},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,a=!0,s=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){s=!0,i=e},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw i}}}}function To(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,o=Array(t);nEmpty";St()(e)||(n=_e()(e,(function(e){return e=Tt()(e),'
  • ').concat(e,"
  • ")})).join(""));var o='

    \n Script\n
    \n \n
    \n

    \n
      \n ').concat(n,"\n
    "),r=this._$script;return ko(r,t),r.html(o),this}},{key:"refreshStylesheet",value:function(){var e=[];m()("link").each((function(){"stylesheet"===this.rel&&e.push(this.href)}));var t=Co("stylesheet",(e=wn()(e)).length),n="
  • Empty
  • ";St()(e)||(n=_e()(e,(function(e){return e=Tt()(e),'
  • ').concat(e,"
  • ")})).join(""));var o='

    \n Stylesheet\n
    \n \n
    \n

    \n
      \n ').concat(n,"\n
    "),r=this._$stylesheet;return ko(r,t),r.html(o),this}},{key:"refreshIframe",value:function(){var e=[];m()("iframe").each((function(){var t=m()(this).attr("src");t&&e.push(t)})),e=wn()(e);var t="
  • Empty
  • ";St()(e)||(t=_e()(e,(function(e){return e=Tt()(e),'
  • ').concat(e,"
  • ")})).join(""));var n='

    \n Iframe\n
    \n \n
    \n

    \n
      \n ').concat(t,"\n
    ");return this._$iframe.html(n),this}},{key:"refreshLocalStorage",value:function(){return this._localStorage.refresh(),this}},{key:"refreshSessionStorage",value:function(){return this._sessionStorage.refresh(),this}},{key:"refreshCookie",value:function(){return this._cookie.refresh(),this}},{key:"refreshImage",value:function(){var e=[],t=this._performance=window.webkitPerformance||window.performance;t&&t.getEntries?this._performance.getEntries().forEach((function(t){if("img"===t.initiatorType||Io(t.name)){if(N()(t.name,"exclude=true"))return;e.push(t.name)}})):m()("img").each((function(){var t=m()(this),n=t.attr("src");"true"!==t.data("exclude")&&e.push(n)}));(e=wn()(e)).sort();var n=Co("image",e.length),o="
  • Empty
  • ";St()(e)||(o=_e()(e,(function(e){return'
  • \n \n
  • ')})).join(""));var r='

    \n Image\n
    \n \n
    \n

    \n
      \n ').concat(o,"\n
    "),i=this._$image;return ko(i,n),i.html(r),this}},{key:"show",value:function(){return Oo(t,"show",this,3)([]),this._observeElement&&this._enableObserver(),this.refresh()}},{key:"hide",value:function(){return this._disableObserver(),Oo(t,"hide",this,3)([])}},{key:"_initTpl",value:function(){var e=this._$el;e.html(ze('
    \n
    \n \n
    \n
    \n
    \n
    ')),this._$localStorage=e.find(ze(".local-storage")),this._$sessionStorage=e.find(ze(".session-storage")),this._$cookie=e.find(ze(".cookie")),this._$script=e.find(ze(".script")),this._$stylesheet=e.find(ze(".stylesheet")),this._$iframe=e.find(ze(".iframe")),this._$image=e.find(ze(".image"))}},{key:"_bindEvent",value:function(){var e=this,t=this._$el,n=this._container;function o(e,t){var o=n.get("sources");if(o)return o.set(e,t),n.showTool("sources"),!0}function r(e){return function(t){if(n.get("sources")){t.preventDefault();var r=m()(this).attr("href");"iframe"!==e&&go()(location.href,r)?bo()({url:r,success:function(t){o(e,t)},dataType:"raw"}):o("iframe",r)}}}t.on("click",".eruda-refresh-script",(function(){n.notify("Refreshed",{icon:"success"}),e.refreshScript()})).on("click",".eruda-refresh-stylesheet",(function(){n.notify("Refreshed",{icon:"success"}),e.refreshStylesheet()})).on("click",".eruda-refresh-iframe",(function(){n.notify("Refreshed",{icon:"success"}),e.refreshIframe()})).on("click",".eruda-refresh-image",(function(){n.notify("Refreshed",{icon:"success"}),e.refreshImage()})).on("click",".eruda-img-link",(function(){o("img",m()(this).attr("src"))})).on("click",".eruda-css-link",r("css")).on("click",".eruda-js-link",r("js")).on("click",".eruda-iframe-link",r("iframe"))}},{key:"_rmCfg",value:function(){var e=this.config,t=this._container.get("settings");t&&t.remove(e,"hideErudaSetting").remove(e,"observeElement").remove("Resources")}},{key:"_initCfg",value:function(){var e=this,t=this.config=ce.createCfg("resources",{hideErudaSetting:!0,observeElement:!0});t.get("hideErudaSetting")&&(this._hideErudaSetting=!0),t.get("observeElement")||(this._observeElement=!1),t.on("change",(function(t,n){switch(t){case"hideErudaSetting":return void(e._hideErudaSetting=n);case"observeElement":return e._observeElement=n,n?e._enableObserver():e._disableObserver()}})),this._container.get("settings").text("Resources").switch(t,"hideErudaSetting","Hide Eruda Setting").switch(t,"observeElement","Auto Refresh Elements").separator()}},{key:"_initObserver",value:function(){var e=this;this._observer=new(Nn())((function(t){x()(t,(function(t){e._handleMutation(t)}))}))}},{key:"_handleMutation",value:function(e){var t=this;if(!Ie(e.target)){var n=function(e){var n=function(e){return e.tagName?e.tagName.toLowerCase():""}(e);switch(n){case"script":t.refreshScript();break;case"img":t.refreshImage();break;case"link":t.refreshStylesheet()}};if("attributes"===e.type)n(e.target);else if("childList"===e.type){n(e.target);var o,r=Ao()(e.addedNodes),i=Eo(r=_o()(r,Ao()(e.removedNodes)));try{for(i.s();!(o=i.n()).done;){n(o.value)}}catch(e){i.e(e)}finally{i.f()}}}}},{key:"_enableObserver",value:function(){this._observer.observe(document.documentElement,{attributes:!0,childList:!0,subtree:!0})}},{key:"_disableObserver",value:function(){this._observer.disconnect()}}])}(v);var Mo=/\.(jpeg|jpg|gif|png)$/,Io=function(e){return Mo.test(e)},zo=n(6620),Do=n.n(zo),Bo=Do()(),Fo=[{name:"Location",val:function(){return Tt()(location.href)}},{name:"User Agent",val:navigator.userAgent},{name:"Device",val:["",'"),""),""),"
    screen'.concat(screen.width," * ").concat(screen.height,"
    viewport".concat(window.innerWidth," * ").concat(window.innerHeight,"
    pixel ratio".concat(window.devicePixelRatio,"
    "].join("")},{name:"System",val:["",'"),""),"
    os'.concat(nn()(),"
    browser".concat(Bo.name+" "+Bo.version,"
    "].join("")},{name:"Sponsor this Project",val:function(){return""+_e()([{name:"Open Collective",link:"https://opencollective.com/eruda"},{name:"Ko-fi",link:"https://ko-fi.com/surunzi"},{name:"Wechat Pay",link:"https://surunzi.com/wechatpay.html"}],(function(e){return"")})).join(" ")+"
    ".concat(e.name,'').concat(e.link.replace("https://",""),"
    "}},{name:"About",val:'Eruda v3.4.3'}],Ro=n(1034),Lo=n.n(Ro);function Go(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(Go=function(){return!!e})()}function Po(e,t,n,o){var r=(0,f.A)((0,a.A)(1&o?e.prototype:e),t,n);return 2&o&&"function"==typeof r?function(e){return r.apply(n,e)}:r}var Ho=function(e){function t(){var e,r,s,c;return(0,o.A)(this,t),r=this,s=t,s=(0,a.A)(s),(e=(0,i.A)(r,Go()?Reflect.construct(s,c||[],(0,a.A)(r).constructor):s.apply(r,c)))._style=re(n(4657)),e.name="info",e._infos=[],e}return(0,s.A)(t,e),(0,r.A)(t,[{key:"init",value:function(e,n){Po(t,"init",this,3)([e]),this._container=n,this._addDefInfo(),this._bindEvent()}},{key:"destroy",value:function(){Po(t,"destroy",this,3)([]),re.remove(this._style)}},{key:"add",value:function(e,t){var n=this._infos,o=!1;return x()(n,(function(n){e===n.name&&(n.val=t,o=!0)})),o||n.push({name:e,val:t}),this._render(),this}},{key:"get",value:function(e){var t,n=this._infos;return be()(e)?Lo()(n):(x()(n,(function(n){e===n.name&&(t=n.val)})),t)}},{key:"remove",value:function(e){for(var t=this._infos,n=t.length-1;n>=0;n--)t[n].name===e&&t.splice(n,1);return this._render(),this}},{key:"clear",value:function(){return this._infos=[],this._render(),this}},{key:"_addDefInfo",value:function(){var e=this;x()(Fo,(function(t){return e.add(t.name,t.val)}))}},{key:"_render",value:function(){var e=[];x()(this._infos,(function(t){var n=t.name,o=t.val;lt()(o)&&(o=o()),e.push({name:n,val:o})}));var t="
      ".concat(_e()(e,(function(e){return'
    • ').concat(Tt()(e.name),'

      ').concat(e.val,"
    • ")})).join(""),"
    ");this._renderHtml(t)}},{key:"_bindEvent",value:function(){var e=this._container;this._$el.on("click",ze(".copy"),(function(){var t=m()(this).parent().parent(),n=t.find(ze(".title")).text(),o=t.find(ze(".content")).text();Ot()("".concat(n,": ").concat(o)),e.notify("Copied",{icon:"success"})}))}},{key:"_renderHtml",value:function(e){e!==this._lastHtml&&(this._lastHtml=e,this._$el.html(e))}}])}(v),Yo=n(6911),$o=n(894),qo=n.n($o),Qo=n(4249),Uo=n.n(Qo),Wo=n(1714);function Jo(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(Jo=function(){return!!e})()}function Ko(e,t,n,o){var r=(0,f.A)((0,a.A)(1&o?e.prototype:e),t,n);return 2&o&&"function"==typeof r?function(e){return r.apply(n,e)}:r}var Vo=function(e){function t(){var e,r,s,c;return(0,o.A)(this,t),r=this,s=t,s=(0,a.A)(s),(e=(0,i.A)(r,Jo()?Reflect.construct(s,c||[],(0,a.A)(r).constructor):s.apply(r,c)))._style=re(n(4831)),e.name="sources",e._showLineNum=!0,e}return(0,s.A)(t,e),(0,r.A)(t,[{key:"init",value:function(e,n){Ko(t,"init",this,3)([e]),this._container=n,this._bindEvent(),this._initCfg()}},{key:"destroy",value:function(){Ko(t,"destroy",this,3)([]),re.remove(this._style),this._rmCfg()}},{key:"set",value:function(e,t){if("img"===e){this._isFetchingData=!0;var n=new Image,o=this;return n.onload=function(){o._isFetchingData=!1,o._data={type:"img",val:{width:this.width,height:this.height,src:t}},o._render()},n.onerror=function(){o._isFetchingData=!1},void(n.src=t)}return this._data={type:e,val:t},this._render(),this}},{key:"show",value:function(){return Ko(t,"show",this,3)([]),this._data||this._isFetchingData||this._renderDef(),this}},{key:"_renderDef",value:function(){var e=this;if(this._html)return this._data={type:"html",val:this._html},this._render();this._isGettingHtml||(this._isGettingHtml=!0,bo()({url:location.href,success:function(t){return e._html=t},error:function(){return e._html="Sorry, unable to fetch source code:("},complete:function(){e._isGettingHtml=!1,e._renderDef()},dataType:"raw"}))}},{key:"_bindEvent",value:function(){var e=this;this._container.on("showTool",(function(t,n){t!==e.name&&n.name===e.name&&delete e._data}))}},{key:"_rmCfg",value:function(){var e=this.config,t=this._container.get("settings");t&&t.remove(e,"showLineNum").remove("Sources")}},{key:"_initCfg",value:function(){var e=this,t=this.config=ce.createCfg("sources",{showLineNum:!0});t.get("showLineNum")||(this._showLineNum=!1),t.on("change",(function(t,n){"showLineNum"!==t||(e._showLineNum=n)})),this._container.get("settings").text("Sources").switch(t,"showLineNum","Show Line Numbers").separator()}},{key:"_render",value:function(){switch(this._isInit=!0,this._data.type){case"html":case"js":case"css":return this._renderCode();case"img":return this._renderImg();case"object":return this._renderObj();case"raw":return this._renderRaw();case"iframe":return this._renderIframe()}}},{key:"_renderImg",value:function(){var e=this._data.val,t=e.width,n=e.height,o=e.src;this._renderHtml('
    \n
    ').concat(Tt()(o),'
    \n
    \n \n
    \n
    ').concat(Tt()(t)," × ").concat(Tt()(n),"
    \n
    "))}},{key:"_renderCode",value:function(){var e=this._data;this._renderHtml('
    '),!1);var t=e.val,n=e.val.length;n>er&&(t=zt()(t,er)),n'),!1);var e=this._data.val;try{E()(e)&&(e=JSON.parse(e))}catch(e){}new Yo.A(this._$el.find(".eruda-json").get(0),{unenumerable:!0,accessGetter:!0,prototype:!1}).set(e)}},{key:"_renderRaw",value:function(){var e=this._data;this._renderHtml('
    \n
    \n
    '));var t=e.val,n=this._$el.find(ze(".raw")).get(0);t.length>er&&(t=zt()(t,er)),new Wo.A(n,{text:t,wrapLongLines:!0,showLineNumbers:t.length'))}},{key:"_renderHtml",value:function(e){var t=this;(!(arguments.length>1&&void 0!==arguments[1])||arguments[1])&&e===this._lastHtml||(this._lastHtml=e,this._$el.html(e),setTimeout((function(){return t._$el.get(0).scrollTop=0}),0))}}])}(v),Zo=3e4,Xo=8e4,er=1e5,tr=n(9760),nr=n.n(tr),or=n(1505),rr=n.n(or),ir=n(5701),ar=n.n(ir),sr={init:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.container,n=e.tool,o=e.autoScale,r=void 0===o||o,i=e.useShadowDom,a=void 0===i||i,s=e.inline,c=void 0!==s&&s,l=e.defaults,u=void 0===l?{}:l;this._isInit||(this._isInit=!0,this._scale=1,this._initContainer(t,a),this._initStyle(),this._initDevTools(u,c),this._initEntryBtn(),this._initSettings(),this._initTools(n),this._registerListener(),r&&this._autoScale(),c&&(this._entryBtn.hide(),this._$el.addClass("eruda-inline"),this.show()))},_isInit:!1,version:"3.4.3",util:{isErudaEl:Ie,evalCss:re,isDarkTheme:function(e){return e||(e=this.getTheme()),K(e)},getTheme:function(){var e=re.getCurTheme(),t="Light";return x()(V,(function(n,o){ar()(n,e)&&(t=o)})),t}},chobitsu:Jt,Tool:v,Console:wt,Elements:Zn,Network:cn,Sources:Vo,Resources:jo,Info:Ho,Snippets:po,Settings:ce,get:function(e){if(this._checkInit()){if("entryBtn"===e)return this._entryBtn;var t=this._devTools;return e?t.get(e):t}},add:function(e){if(this._checkInit())return lt()(e)&&(e=e(this)),this._devTools.add(e),this},remove:function(e){return this._devTools.remove(e),this},show:function(e){if(this._checkInit()){var t=this._devTools;return e?t.showTool(e):t.show(),this}},hide:function(){if(this._checkInit())return this._devTools.hide(),this},destroy:function(){this._devTools.destroy(),delete this._devTools,this._entryBtn.destroy(),delete this._entryBtn,this._unregisterListener(),m()(this._container).remove(),re.clear(),this._isInit=!1,this._container=null,this._shadowRoot=null},scale:function(e){return Qe()(e)?(this._scale=e,h.emit(h.SCALE,e),this):this._scale},position:function(e){var t=this._entryBtn;return nr()(e)?(t.setPos(e),this):t.getPos()},_autoScale:function(){hn()()&&this.scale(1/rr()())},_registerListener:function(){var e=this;this._addListener=function(){return e.add.apply(e,arguments)},this._showListener=function(){return e.show.apply(e,arguments)},h.on(h.ADD,this._addListener),h.on(h.SHOW,this._showListener),h.on(h.SCALE,re.setScale)},_unregisterListener:function(){h.off(h.ADD,this._addListener),h.off(h.SHOW,this._showListener),h.off(h.SCALE,re.setScale)},_checkInit:function(){return this._isInit||$e.error('Please call "eruda.init()" first'),this._isInit},_initContainer:function(e,t){var o,r;e||(e=document.createElement("div"),document.documentElement.appendChild(e)),e.id="eruda",e.style.all="initial",this._container=e,t&&(e.attachShadow?o=e.attachShadow({mode:"open"}):e.createShadowRoot&&(o=e.createShadowRoot()),o&&(re.container=document.head,re(n(6793)+n(7853)+n(9907)+n(879)+n(1107)+n(5259)),r=document.createElement("div"),o.appendChild(r),this._shadowRoot=o)),this._shadowRoot||(r=document.createElement("div"),e.appendChild(r)),P()(r,{className:"eruda-container __chobitsu-hide__",contentEditable:!1}),"ios"===Do()().name&&r.setAttribute("ontouchstart",""),this._$el=m()(r)},_initDevTools:function(e,t){this._devTools=new it(this._$el,{defaults:e,inline:t})},_initStyle:function(){var e="eruda-style-container",t=this._$el;this._shadowRoot?(re.container=this._shadowRoot,re(":host { all: initial }")):(t.append('
    ')),re.container=t.find(".".concat(e)).get(0)),re(n(2693)+n(9907)+n(7853)+n(5259)+n(3277)+n(879)+n(4393)+n(7253)+n(1107)+n(187)+n(1277)+n(8687)+n(6793))},_initEntryBtn:function(){var e=this;this._entryBtn=new Pe(this._$el),this._entryBtn.on("click",(function(){return e._devTools.toggle()}))},_initSettings:function(){var e=this._devTools,t=new ce;e.add(t),this._entryBtn.initCfg(t),e.initCfg(t)},_initTools:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["console","elements","network","resources","sources","info","snippets"];t=Ao()(t);var n=this._devTools;t.forEach((function(t){var o=e[Ke()(t)];try{o&&n.add(new o)}catch(e){ue()((function(){$e.error("Something wrong when initializing tool ".concat(t,":"),e.message)}))}})),n.showTool(t[0]||"settings")}}},4236:function(e,t){t=function(e){return null===e},e.exports=t},4249:function(e,t,n){var o=n(9100),r=n(5651);t=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"js",s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};r(s,i),e=e.replace(//g,">"),n=a[n];var c=0,l=[];o(n,(function(n){n.language&&(e=e.replace(n.re,(function(e,o){return o?(l[c++]=t(o,n.language,s),e.replace(o,"___subtmpl"+(c-1)+"___")):e})))})),o(n,(function(t,n){a[t.language]||(e=e.replace(t.re,"___"+n+"___$1___end"+n+"___"))}));var u=[];return e=e.replace(/___(?!subtmpl)\w+?___/g,(function(e){var t="end"===e.substr(3,3),o=(t?e.substr(6):e.substr(3)).replace(/_/g,""),r=u.length>0?u[u.length-1]:null;return!t&&(null==r||o==r||null!=r&&n[r]&&null!=n[r].embed&&n[r].embed.indexOf(o)>-1)?(u.push(o),e):t&&o==r?(u.pop(),e):""})),o(n,(function(t,n){var o=s[t.style]?' style="'.concat(s[t.style],'"'):"";e=e.replace(new RegExp("___end"+n+"___","g"),"
    ").replace(new RegExp("___"+n+"___","g"),'"))})),o(n,(function(t){t.language&&(e=e.replace(/___subtmpl\d+___/g,(function(e){var t=parseInt(e.replace(/___subtmpl(\d+)___/,"$1"),10);return l[t]})))})),e};var i={comment:"color:#63a35c;",string:"color:#183691;",number:"color:#0086b3;",keyword:"color:#a71d5d;",operator:"color:#994500;"},a={js:{comment:{re:/(\/\/.*|\/\*([\s\S]*?)\*\/)/g,style:"comment"},string:{re:/(('.*?')|(".*?"))/g,style:"string"},numbers:{re:/(-?(\d+|\d+\.\d+|\.\d+))/g,style:"number"},keywords:{re:/(?:\b)(function|for|foreach|while|if|else|elseif|switch|break|as|return|this|class|self|default|var|const|let|false|true|null|undefined)(?:\b)/gi,style:"keyword"},operator:{re:/(\+|-|\/|\*|%|=|<|>|\||\?|\.)/g,style:"operator"}}};a.html={comment:{re:/(<!--([\s\S]*?)-->)/g,style:"comment"},tag:{re:/(<\/?\w(.|\n)*?\/?>)/g,style:"keyword",embed:["string"]},string:a.js.string,css:{re:/(?:<style.*?>)([\s\S]*)?(?:<\/style>)/gi,language:"css"},script:{re:/(?:<script.*?>)([\s\S]*?)(?:<\/script>)/gi,language:"js"}},a.css={comment:a.js.comment,string:a.js.string,numbers:{re:/((-?(\d+|\d+\.\d+|\.\d+)(%|px|em|pt|in)?)|#[0-9a-fA-F]{3}[0-9a-fA-F]{3})/g,style:"number"},keywords:{re:/(@\w+|:?:\w+|[a-z-]+:)/g,style:"keyword"}},e.exports=t},4279:function(e,t,n){(t=n(6314)(!1)).push([e.id,"#_settings{overflow-y:auto;-webkit-overflow-scrolling:touch}._safe-area #_settings{padding-bottom:calc(0px + env(safe-area-inset-bottom))}",""]),e.exports=t},4307:function(e,t,n){var o=n(2263),r=n(2767),i=n(9100),a=n(438),s=n(9405),c=n(3915),l=n(3957);t={on:function(e,t,n){l(t)&&(n=t,t={}),e=e.split(f),i(e,(function(e){if(e=h(e),t.element){var o=t.element,r=o._hotkeyListeners||{};o._hotkeyListeners=r,r[e]=r[e]||[];var i=function(t){e===d(t)&&n(t)};r[e].push({listener:i,origin:n}),o.addEventListener("keydown",i)}else u.on(e,n)}))},off:function(e,t,n){l(t)&&(n=t,t={}),e=e.split(f),i(e,(function(e){if(e=h(e),t.element){var o=t.element,r=o._hotkeyListeners;if(r&&r[e]){for(var i,a=r[e],s=0,c=a.length;s]*>/g.test(e))try{var t=s.default.parse(e);return f(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),s.default.stringify(t)}catch(t){return n(e)}return n(e)}};var p,v="ontouchstart"in a.default,g={start:"touchstart",move:"touchmove",end:"touchend"},m={start:"mousedown",move:"mousemove",end:"mouseup"};t.drag=function(e){return v?g[e]:m[e]},t.eventClient=function(e,t){var n="x"===e?"clientX":"clientY";return t[n]?t[n]:t.changedTouches?t.changedTouches[0][n]:0},t.eventPage=function(e,t){var n="x"===e?"pageX":"pageY";return t[n]?t[n]:t.changedTouches?t.changedTouches[0][n]:0},t.measuredScrollbarWidth=function(){if((0,c.default)(p))return p;if(!document)return 16;var e=document.createElement("div"),t=document.createElement("div");return e.setAttribute("style","display: block; width: 100px; height: 100px; overflow: scroll;"),t.setAttribute("style","height: 200px"),e.appendChild(t),document.body.appendChild(e),p=e.offsetWidth-e.clientWidth,document.body.removeChild(e),p},t.hasVerticalScrollbar=function(e){return e.scrollHeight>e.offsetHeight},t.executeAfterTransition=function(e,t){if((0,h.default)(e))return t();var n=function(o){o.target===e&&(e.removeEventListener("transitionend",n),t())};e.addEventListener("transitionend",n)},t.pxToNum=function(e){return(0,u.default)(e.replace("px",""))},t.getPlatform=function(){var e=(0,d.default)();return"os x"===e?"mac":e},t.resetCanvasSize=function(e){e.width=Math.round(e.offsetWidth*window.devicePixelRatio),e.height=Math.round(e.offsetHeight*window.devicePixelRatio)}},4801:function(e,t,n){var o=n(4950),r=n(2989),i=n(2561),a=n(1580),s=n(1168),c=n(3145),l=n(9100),u=n(2717),d=n(5427),h=n(466),f=n(8105),p=n(8796),v=n(2571),g=n(3981),m=n(7514),b=n(3249),y=n(9760),A=n(4460),w=n(6513),_=n(1009),x=n(2806),k=n(4151),C=n(896),S=n(5793);function E(e,n,o,r){var a=[];return l(n,(function(e){var n,s=Object.getOwnPropertyDescriptor(o,e),c=s&&s.get,l=s&&s.set;if(!r.accessGetter&&c)n="(...)";else try{if(n=o[e],b(r.ignore,n))return;p(n)&&n.catch((function(){}))}catch(e){n=e.message}a.push("".concat(T(e),":").concat(t(n,r))),c&&a.push("".concat(T("get "+i(e)),":").concat(t(s.get,r))),l&&a.push("".concat(T("set "+i(e)),":").concat(t(s.set,r)))})),'"'.concat(e,'":{')+a.join(",")+"}"}function T(e){return'"'.concat(O(e),'"')}function N(e){return'"'.concat(O(i(e)),'"')}function O(e){return o(e).replace(/\\'/g,"'").replace(/\t/g,"\\t")}t=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=n.self,l=n.startTime,u=void 0===l?g():l,p=n.timeout,y=void 0===p?0:p,A=n.depth,w=void 0===A?0:A,_=n.curDepth,x=void 0===_?1:_,k=n.visitor,C=void 0===k?new j:k,S=n.unenumerable,T=void 0!==S&&S,O=n.symbol,M=void 0!==O&&O,I=n.accessGetter,z=void 0!==I&&I,D=n.ignore,B=void 0===D?[]:D,F="",R={visitor:C,unenumerable:T,symbol:M,accessGetter:z,depth:w,curDepth:x+1,timeout:y,startTime:u,ignore:B},L=r(e,!1);if("String"===L)F=N(e);else if("Number"===L)F=i(e),a(F,"Infinity")&&(F='{"value":"'.concat(F,'","type":"Number"}'));else if("NaN"===L)F='{"value":"NaN","type":"Number"}';else if("Boolean"===L)F=e?"true":"false";else if("Null"===L)F="null";else if("Undefined"===L)F='{"type":"Undefined"}';else if("Symbol"===L){var G="Symbol";try{G=i(e)}catch(e){}F='{"value":'.concat(N(G),',"type":"Symbol"}')}else{if(y&&g()-u>y)return N("Timeout");if(w&&x>w)return N("{...}");F="{";var P,H=[],Y=C.get(e);if(Y?(P=Y.id,H.push('"reference":'.concat(P))):(P=C.set(e),H.push('"id":'.concat(P))),H.push('"type":"'.concat(L,'"')),a(L,"Function")?H.push('"value":'.concat(N(s(e)))):"RegExp"===L&&H.push('"value":'.concat(N(e))),!Y){var $=c(e);if($.length&&H.push(E("enumerable",$,o||e,R)),T){var q=h(m(e,{prototype:!1,unenumerable:!0}),$);q.length&&H.push(E("unenumerable",q,o||e,R))}if(M){var Q=v(m(e,{prototype:!1,symbol:!0}),(function(e){return"symbol"==typeof e}));Q.length&&H.push(E("symbol",Q,o||e,R))}var U=d(e);if(U&&!b(B,U)){var W='"proto":'.concat(t(U,f(R,{self:o||e})));H.push(W)}}F+=H.join(",")+"}"}return F};var j=u({initialize:function(){this.id=1,this.visited=[]},set:function(e){var t=this.visited,n=this.id,o={id:n,val:e};return t.push(o),this.id++,n},get:function(e){for(var t=this.visited,n=0,o=t.length;n>6*t)+n);t>0;){o+=h(128|63&e>>6*(t-1)),t--}return o}function p(e){for(;;){if(i>=a&&l){if(e)return v();throw new Error("Invalid byte index")}if(i===a)return!1;var t=r[i];if(i++,l){if(td){if(e)return i--,v();throw new Error("Invalid continuation byte")}if(u=128,d=191,s=s<<6|63&t,++c===l){var n=s;return s=0,l=0,c=0,n}}else{if(!(128&t))return t;if(192==(224&t))l=1,s=31&t;else if(224==(240&t))224===t&&(u=160),237===t&&(d=159),l=2,s=15&t;else{if(240!=(248&t)){if(e)return v();throw new Error("Invalid UTF-8 detected")}240===t&&(u=144),244===t&&(d=143),l=3,s=7&t}}}}function v(){var e=i-c-1;return i=e+1,s=0,l=0,c=0,u=128,d=191,r[e]}e.exports=t},4983:function(e,t){t=function(e){try{return JSON.parse(e),!0}catch(e){return!1}},e.exports=t},4992:function(e,t,n){var o=n(3974);t=function(e){return"[object ArrayBuffer]"===o(e)},e.exports=t},4994:function(e,t,n){var o=n(2510);t=o((function(e,t,n){return o((function(o){return e.apply(t,n.concat(o))}))})),e.exports=t},5004:function(e,t,n){var o=n(1909),r=n(621);t=function(e){function t(t){return e.indexOf(t)>-1}if(!e&&o&&(e=navigator.userAgent),e){if(e=e.toLowerCase(),t("windows phone"))return"windows phone";if(t("win"))return"windows";if(t("android"))return"android";if(t("ipad")||t("iphone")||t("ipod"))return"ios";if(t("mac"))return"os x";if(t("linux"))return"linux"}else if(r){var n=process,i=n.platform,a=n.env;if("win32"===i||"cygwin"===a.OSTYPE||"msys"===a.OSTYPE)return"windows";if("darwin"===i)return"os x";if("linux"===i)return"linux"}return"unknown"},e.exports=t},5021:function(e,t,n){var o=n(7744),r=n(1931),i=n(9464),a=n(8032),s=n(5651),c=n(9760),l=r("local");t=o.extend({initialize:function(e,t){this._name=e,t=t||{};var n=l.getItem(e);try{n=JSON.parse(n)}catch(e){n={}}c(n)||(n={}),t=s(n,t),this.callSuper(o,"initialize",[t])},save:function(e){if(i(e))return l.removeItem(this._name);l.setItem(this._name,a(e))}}),e.exports=t},5119:function(e,t,n){var o=n(9100);t=function(e){var t=[];return o(e,(function(e){t.push(e)})),t},e.exports=t},5132:function(e,t,n){var o=n(3974);t=function(e){return"[object Arguments]"===o(e)},e.exports=t},5145:function(e,t,n){var o=n(9756),r=n(5651),i=n(3145),a=n(6214),s=n(9760);t=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};r(t,c);var n=t.deep,o=t.comparator,l=[],u=[];return function e(t){var r,c=l.indexOf(t);if(c>-1)return u[c];if(a(t)){r=[],l.push(t),u.push(r);for(var d=0,h=t.length;d=55296&&r<=56319&&n2?n-2:0),d=2;d=a?"":e.substr(i,a)},e.exports=t},5334:function(e,t,n){"use strict";var o=this&&this.__awaiter||function(e,t,n,o){return new(n||(n=Promise))((function(r,i){function a(e){try{c(o.next(e))}catch(e){i(e)}}function s(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}c((o=o.apply(e,t||[])).next())}))},r=this&&this.__generator||function(e,t){var n,o,r,i={label:0,sent:function(){if(1&r[0])throw r[1];return r[1]},trys:[],ops:[]},a=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return a.next=s(0),a.throw=s(1),a.return=s(2),"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function s(s){return function(c){return function(s){if(n)throw new TypeError("Generator is already executing.");for(;a&&(a=0,s[0]&&(i=0)),i;)try{if(n=1,o&&(r=2&s[0]?o.return:s[0]?o.throw||((r=o.return)&&r.call(o),0):o.next)&&!(r=r.call(o,s[1])).done)return r;switch(o=0,r&&(s=[2&s[0],r.value]),s[0]){case 0:case 1:r=s;break;case 4:return i.label++,{value:s[1],done:!1};case 5:i.label++,o=s[1],s=[0];continue;case 7:s=i.ops.pop(),i.trys.pop();continue;default:if(!(r=i.trys,(r=r.length>0&&r[r.length-1])||6!==s[0]&&2!==s[0])){i=0;continue}if(3===s[0]&&(!r||s[1]>r[0]&&s[1]e.length)&&(t=e.length);for(var n=0,o=Array(t);n1?n-1:0),u=1;u0?i.apply(null,p):0;return s(a(f,(function(e){return" "===e[0]?e.slice(b):e})).join("\n"))};var c=/^(\s+)\S+/;e.exports=t},5784:function(e,t,n){"use strict";n.d(t,{A:function(){return _e}});var o=n(7528),r=n(4467),i=n(3029),a=n(2901),s=n(388),c=n(3954),l=n(5361),u=n(2263),d=n.n(u),h=n(3693),f=n.n(h),p=n(3915),v=n.n(p),g=n(9405),m=n.n(g),b=n(5169),y=n.n(b),A=n(9548),w=n.n(A),_=(n(6097),n(3249)),x=n.n(_),k=(n(6030),n(5004)),C=n.n(k);n(9410),n(8609);function S(e){var t="luna-".concat(e,"-");function n(e){return v()(m()(e).split(/\s+/),(function(e){return x()(e,t)?e:e.replace(/[\w-]+/,(function(e){return"".concat(t).concat(e)}))})).join(" ")}return function(e){if(/<[^>]*>/g.test(e))try{var t=w().parse(e);return E(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),w().stringify(t)}catch(t){return n(e)}return n(e)}}function E(e,t){for(var n=0,o=e.length;n2&&void 0!==arguments[2]?arguments[2]:{}).theme,l=void 0===a?"light":a;return(0,i.A)(this,t),o=function(e,t,n){return t=(0,c.A)(t),(0,s.A)(e,H()?Reflect.construct(t,n||[],(0,c.A)(e).constructor):t.apply(e,n))}(this,t),o.subComponents=[],o.theme="",o.onThemeChange=function(e){"auto"===o.options.theme&&o.setTheme(e)},o.compName=r,o.c=S(r),o.options={},o.container=e,o.$container=f()(e),o.$container.addClass(["luna-".concat(r),o.c("platform-".concat(N()))]),o.on("changeOption",(function(e,t){if("theme"===e&&t){var n=t;"auto"===t&&(n=L().get()),o.setTheme(n),j()(o.subComponents,(function(e){return e.setOption("theme",t)}))}})),L().on("change",o.onThemeChange),o.setOption("theme",l),o}return(0,l.A)(t,e),(0,a.A)(t,[{key:"destroy",value:function(){var e=this;this.destroySubComponents();var t=this.$container,n=t.attr("class");j()(n.split(/\s+/),(function(n){P()(n,"luna-".concat(e.compName))&&t.rmClass(n)})),t.html(""),this.emit("destroy"),this.removeAllListeners(),L().off("change",this.onThemeChange)}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,j()(r,(function(e,t){var r=o[t];o[t]=e,e!==r&&n.emit("changeOption",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){F()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){j()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};D()(e,t),I()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}},{key:"setTheme",value:function(e){var t=this.c,n=this.$container;this.theme&&n.rmClass(t("theme-".concat(this.theme))),n.addClass(t("theme-".concat(e))),this.theme=e}}])}(d()),Q=n(5241),U=n.n(Q),W=n(2571),J=n.n(W),K=n(7181),V=n.n(K),Z=n(5773),X=n.n(Z),ee=n(769),te=n.n(ee),ne=n(2208),oe=n.n(ne),re=n(4249),ie=n.n(re),ae=n(15),se=n.n(ae),ce=n(3497),le=n.n(ce),ue=n(5902),de=n.n(ue),he=n(8098),fe=n.n(he),pe=n(4307),ve=n.n(pe),ge=n(96),me=n.n(ge);function be(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function ye(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:{};return(0,i.A)(this,t),o=this,r=t,a=[e,{compName:"dom-viewer"},l],r=(0,c.A)(r),(n=(0,s.A)(o,Ae()?Reflect.construct(r,a||[],(0,c.A)(o).constructor):r.apply(o,a))).isExpanded=!1,n.childNodes=[],n.childNodeDomViewers=[],n.expand=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];n.isExpandable()&&(n.isExpanded||(n.isExpanded=!0,n.renderExpandTag(),n.renderChildNodes()),e&&j()(n.childNodeDomViewers,(function(e){e.expand(!0)})))},n.collapse=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];n.isExpandable()&&(n.isExpanded&&(n.isExpanded=!1,n.renderCollapseTag()),e&&j()(n.childNodeDomViewers,(function(e){e.collapse(!0)})))},n.toggle=function(){n.isExpanded?n.collapse():n.expand()},n.onKeyRight=function(){n.isExpanded?n.childNodeDomViewers[0].select():n.expand()},n.onKeyLeft=function(){var e;n.isExpanded?n.collapse():null===(e=n.options.parent)||void 0===e||e.select()},n.onKeyDown=function(){var e=n.options;if(n.isExpanded)n.childNodeDomViewers[0].select();else{var t=e.parent;if(t)if(e.isEndTag){if(!(t=t.getOption("parent")))return;var o=t,r=o.childNodes,i=o.childNodeDomViewers,a=o.endTagDomViewer,s=r.indexOf(e.node);r[s+1]?i[s+1].select():a&&a.select()}else{var c=t,l=c.childNodeDomViewers,u=c.endTagDomViewer,d=l.indexOf(n);l[d+1]?l[d+1].select():u&&u.select()}}},n.onKeyUp=function(){var e=n.options,t=e.parent;if(t){var o,r;if(e.isEndTag)o=le()(t.childNodeDomViewers);else{var i=t.childNodeDomViewers.indexOf(n);i<1?t.select():o=t.childNodeDomViewers[i-1]}if(o)if(o.isExpanded)null===(r=o.endTagDomViewer)||void 0===r||r.select();else o.select()}},n.initOptions(l,{node:document.documentElement,parent:null,isEndTag:!1,observe:!0,rootContainer:e,rootDomViewer:n,ignore:function(){return!1},ignoreAttr:function(){return!1},lowerCaseTagName:!0,hotkey:!0}),n.isShadowRoot=V()(n.options.node),n.initTpl(),n.bindEvent(),!n.options.isEndTag&&n.options.observe&&n.initObserver(),n}return(0,l.A)(t,e),(0,a.A)(t,[{key:"select",value:function(e){var t=this.c,n=this.options;if(!e||e&&n.node===e){if(this.$tag.hasClass(t("selected")))return;return f()(this.options.rootContainer).find(t(".selected")).rmClass(t("selected")).rmAttr("tabindex"),this.$tag.attr("tabindex","0").get(0).focus(),this.$tag.addClass(t("selected")),void n.rootDomViewer.emit("select",n.node)}if(e.nodeType===Node.ELEMENT_NODE)for(var o=e,r=e.parentElement;r;){if(r===n.node){this.expand(),this.childNodeDomViewers[this.childNodes.indexOf(o)].select(e);break}o=r,r=r.parentElement}}},{key:"attach",value:function(){this.container.appendChild(this.$tag.get(0)),this.$children&&this.container.appendChild(this.$children.get(0))}},{key:"isAttached",value:function(){return!!this.$tag.get(0).parentNode}},{key:"detach",value:function(){this.$tag.remove(),this.$children&&this.$children.remove()}},{key:"destroy",value:function(){var e=this.c;this.$tag.hasClass(e("selected"))&&this.options.rootDomViewer.emit("deselect"),this.detach(),this.observer&&this.observer.disconnect(),this.destroySubComponents(),this.options.rootDomViewer===this&&this.$container.rmClass("luna-dom-viewer").rmClass(e("platform-".concat(N()))).rmClass(e("theme-".concat(this.options.theme))),this.emit("destroy"),this.removeAllListeners()}},{key:"renderExpandTag",value:function(){var e=this.$tag,t=this.c,n=this.options.node;this.isShadowRoot||e.html(this.renderHtmlTag(ye(ye({},xe(n)),{},{hasTail:!1,hasToggleButton:!0}))),e.addClass(t("expanded")),this.$children.rmClass(t("hidden"))}},{key:"renderCollapseTag",value:function(){var e=this.$tag,t=this.c,n=this.options.node;this.$children.addClass(t("hidden")),this.isShadowRoot||this.$tag.html(this.renderHtmlTag(ye(ye({},xe(n)),{},{hasTail:!0,hasToggleButton:!0}))),e.rmClass(t("expanded"))}},{key:"initObserver",value:function(){var e=this;this.observer=new(oe())((function(t){j()(t,(function(t){e.handleMutation(t)}))})),this.observer.observe(this.options.node,{attributes:!0,childList:!0,characterData:!0})}},{key:"handleMutation",value:function(e){var t=this.$tag,n=this.c,o=this.options,r=o.node,i=o.ignore;if(x()(["attributes","childList"],e.type)){if("childList"===e.type){if(fe()(e.addedNodes,i)&&fe()(e.removedNodes,i))return;this.renderChildNodes()}this.isExpandable()?this.isExpanded?this.renderExpandTag():this.renderCollapseTag():(this.$children.addClass(n("hidden")),this.isExpanded=!1,this.isShadowRoot?t.html(this.renderShadowRoot(!1)):t.html(this.renderHtmlTag(ye(ye({},xe(r)),{},{hasTail:!1}))))}else"characterData"===e.type&&(r.nodeType===Node.TEXT_NODE?t.html(this.renderTextNode(r)):r.nodeType===Node.COMMENT_NODE&&t.html(this.renderHtmlComment(r.nodeValue)))}},{key:"bindEvent",value:function(){var e=this,t=this.c,n=this.$tag;if((this.options.node.nodeType===Node.ELEMENT_NODE||this.isShadowRoot)&&n.on("click",t(".toggle"),(function(t){t.stopPropagation(),e.toggle()})),T?n.on("click",(function(){return e.select()})):n.on("mousedown",(function(){return e.select()})),this.options.hotkey){var o={element:n.get(0)};ve().on("right",o,this.onKeyRight),ve().on("left",o,this.onKeyLeft),ve().on("down",o,this.onKeyDown),ve().on("up",o,this.onKeyUp)}}},{key:"isExpandable",value:function(){return!(this.options.node.nodeType!==Node.ELEMENT_NODE&&!this.isShadowRoot)&&this.getChildNodes().length>0}},{key:"getChildNodes",value:function(){var e=this.options,t=e.rootContainer,n=e.ignore,o=this.options.node,r=te()(o.childNodes);return r=J()(r,(function(e){if(e.nodeType===Node.TEXT_NODE||e.nodeType===Node.COMMENT_NODE){var o=e.nodeValue;if(""===m()(o))return!1}return e!==t&&!n(e)})),o.shadowRoot?r.unshift(o.shadowRoot):o.chobitsuShadowRoot&&r.unshift(o.chobitsuShadowRoot),r}},{key:"initTpl",value:function(){var e=this.container,t=this.c,n=this.options,o=n.node,r=n.isEndTag,i=n.lowerCaseTagName,a=f()(U()("li"));if(a.addClass(t("tree-item")),this.$tag=a,r){var s=o.tagName;i&&(s=me()(s)),a.html(t('</'.concat(s,'>')))}else if(o.nodeType===Node.ELEMENT_NODE){var c=this.isExpandable(),l=ye(ye({},xe(o)),{},{hasTail:c,hasToggleButton:c});a.html(this.renderHtmlTag(l))}else if(V()(o)){var u=this.isExpandable();a.html(this.renderShadowRoot(u))}else if(o.nodeType===Node.TEXT_NODE)a.html(this.renderTextNode(o));else{if(o.nodeType!==Node.COMMENT_NODE)return;var d=o.nodeValue;if(""===d.trim())return;a.html(this.renderHtmlComment(d))}if(e.appendChild(a.get(0)),o.nodeType===o.ELEMENT_NODE||this.isShadowRoot){var h=f()(U()("ul"));h.addClass([t("children"),t("hidden")]),e.appendChild(h.get(0)),this.$children=h}}},{key:"renderChildNodes",value:function(){var e=this,n=this.options.node,o=this.options,r=o.rootContainer,i=o.ignore,a=o.ignoreAttr,s=o.rootDomViewer,c=o.observe,l=o.lowerCaseTagName,u=this.$children.get(0),d=this.childNodes,h=this.childNodeDomViewers;j()(h,(function(t){t.detach(),e.removeSubComponent(t)})),this.endTagDomViewer&&this.endTagDomViewer.detach();var f=this.getChildNodes();this.childNodes=f;var p=[];this.childNodeDomViewers=p,j()(f,(function(n,o){var f,v=d.indexOf(n);(f=v>-1?h[v]:new t(u,{node:n,observe:c,parent:e,rootContainer:r,rootDomViewer:s,ignore:i,ignoreAttr:a,lowerCaseTagName:l})).attach(),p[o]=f,e.addSubComponent(f)})),j()(h,(function(e){e.isAttached()||e.destroy()})),n&&!this.isShadowRoot&&(this.endTagDomViewer?this.endTagDomViewer.attach():(this.endTagDomViewer=new t(u,{node:n,parent:this,isEndTag:!0,lowerCaseTagName:l,rootContainer:r,rootDomViewer:s,ignore:i}),this.addSubComponent(this.endTagDomViewer)))}},{key:"renderHtmlTag",value:function(e){var t=this,n=this.options.lowerCaseTagName;e.attributes=J()(e.attributes,(function(n){return!t.options.ignoreAttr(e.el,n.name,n.value)}));var r=v()(e.attributes,(function(e){var t=e.name,n=e.value,o=e.isLink;return'\n '.concat(de()(t),"").concat(n?'="').concat(de()(n),'"'):"","")})).join(""),i="",a=e.tagName;return n&&(a=me()(a)),e.hasTail?i="".concat(e.hasTail?"…":"",'</').concat(a,">"):this.isExpandable()||(i='</'.concat(a,">")),this.c(X()(Y||(Y=(0,o.A)(["\n ",'\n <',"",">",'\n '])),e.hasToggleButton?this.renderToggle():"",a,r,i))}},{key:"renderTextNode",value:function(e){var t=this.c,n=e.nodeValue,o=e.parentElement,r='',i='';if(o&&n.length<1e4){if("STYLE"===o.tagName)return t("".concat(r).concat(ie()(n,"css",we)).concat(i));if("SCRIPT"===o.tagName)return t("".concat(r).concat(ie()(n,"js",we)).concat(i))}return t('"'.concat(r).concat(de()(se()(n,1e4,{separator:" ",ellipsis:"…"}))).concat(i,'"'))}},{key:"renderHtmlComment",value:function(e){return this.c('<!-- '.concat(de()(e),' -->'))}},{key:"renderShadowRoot",value:function(e){var t=this.options.node;return this.c(X()($||($=(0,o.A)(["\n ",'\n #shadow-root (',')\n '])),e?this.renderToggle():"",t.mode))}},{key:"renderToggle",value:function(){return'
    '}}])}(q);function xe(e){var t={el:e,tagName:"",attributes:[]};t.tagName=e.tagName;var n=[];return j()(e.attributes,(function(t){var o=t.name,r=t.value;n.push({name:o,value:r,isLink:ke(e,o)})})),t.attributes=n,t}function ke(e,t){var n=e.tagName;return("SCRIPT"===n||"IMAGE"===n||"VIDEO"===n||"AUDIO"===n)&&"src"===t||"LINK"===n&&"href"===t}(function(e,t){try{e.exports=t,e.exports.default=t}catch(e){}})(e,_e)},5793:function(e,t,n){var o=n(6097),r=n(3957),i=Math.pow(2,53)-1;t=function(e){if(!e)return!1;var t=e.length;return o(t)&&t>=0&&t<=i&&!r(e)},e.exports=t},5820:function(e,t,n){var o,r=n(3981),i=n(5169),a=i.performance,s=i.process;if(a&&a.now)t=function(){return a.now()};else if(s&&s.hrtime){var c=function(){var e=s.hrtime();return 1e9*e[0]+e[1]};o=c()-1e9*s.uptime(),t=function(){return(c()-o)/1e6}}else o=r(),t=function(){return r()-o};e.exports=t},5865:function(e,t,n){var o=n(4534);t=function(e,t){return o(e,t,!0)},e.exports=t},5869:function(e,t,n){var o=n(365);t=function(e,t){var n=function(r){var i=n.cache,a=""+(t?t.apply(this,arguments):r);return o(i,a)||(i[a]=e.apply(this,arguments)),i[a]};return n.cache={},n},e.exports=t},5902:function(e,t,n){var o=n(3145),r=(t=function(e){return a.test(e)?e.replace(s,c):e}).map={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},i="(?:"+o(r).join("|")+")",a=new RegExp(i),s=new RegExp(i,"g"),c=function(e){return r[e]};e.exports=t},5945:function(e,t,n){var o=n(3974);t=function(e){return"[object Set]"===o(e)},e.exports=t},5957:function(e,t,n){var o=n(1738),r=n(2990),i=n(4992),a=n(6214),s=n(3159),c=n(2989),l=n(96);(t=function(e,t){var n;if(t=l(t),o(e))n=new Uint8Array(r.decode(e));else if(i(e))e=e.slice(0),n=new Uint8Array(e);else if(a(e))n=new Uint8Array(e);else if("uint8array"===c(e))n=e.slice(0);else if(s(e)){n=new Uint8Array(e.length);for(var u=0;un?n:e},e.exports=t},6030:function(e,t,n){var o=n(6097),r=n(9760),i=n(3957),a=n(1738);t=function(e){if(o(e))return e;if(r(e)){var t=i(e.valueOf)?e.valueOf():e;e=r(t)?t+"":t}return a(e)?+e:0===e?e:+e},e.exports=t},6032:function(e,t,n){var o=n(2717),r=n(8105),i=n(9405),a=n(7257),s=n(9464),c=n(9100),l=n(6214),u=n(769),d=n(1909),h=n(9760),f=n(2561);t=o({className:"Url",initialize:function(e){!e&&d&&(e=window.location.href),r(this,t.parse(e||""))},setQuery:function(e,t){var n=this.query;return h(e)?c(e,(function(e,t){n[t]=f(e)})):n[e]=f(t),this},rmQuery:function(e){var t=this.query;return l(e)||(e=u(e)),c(e,(function(e){delete t[e]})),this},toString:function(){return t.stringify(this)}},{parse:function(e){var t={protocol:"",auth:"",hostname:"",hash:"",query:{},port:"",pathname:"",slashes:!1},n=i(e),o=!1,r=n.match(p);if(r&&(r=r[0],t.protocol=r.toLowerCase(),n=n.substr(r.length)),r&&(o="//"===n.substr(0,2))&&(n=n.slice(2),t.slashes=!0),o){for(var s=n,c=-1,l=0,u=g.length;l-1&&(s=n.slice(0,c),n=n.slice(c));var h=s.lastIndexOf("@");-1!==h&&(t.auth=decodeURIComponent(s.slice(0,h)),s=s.slice(h+1)),t.hostname=s;var f=s.match(v);f&&(":"!==(f=f[0])&&(t.port=f.substr(1)),t.hostname=s.substr(0,s.length-f.length))}var m=n.indexOf("#");-1!==m&&(t.hash=n.substr(m),n=n.slice(0,m));var b=n.indexOf("?");return-1!==b&&(t.query=a.parse(n.substr(b+1)),n=n.slice(0,b)),t.pathname=n||"/",t},stringify:function(e){var t=e.protocol+(e.slashes?"//":"")+(e.auth?encodeURIComponent(e.auth)+"@":"")+e.hostname+(e.port?":"+e.port:"")+e.pathname;return s(e.query)||(t+="?"+a.stringify(e.query)),e.hash&&(t+=e.hash),t}});var p=/^([a-z0-9.+-]+:)/i,v=/:[0-9]*$/,g=["/","?","#"];e.exports=t},6097:function(e,t,n){var o=n(3974);t=function(e){return"[object Number]"===o(e)},e.exports=t},6167:function(e,t,n){var o=n(5693);t=function(e,t,n,r){r=r||1,t=o(t,n);for(var i=e.length,a=r>0?0:i-1;a>=0&&a"),t))return void n.push(e);var i=[];(0,A.default)(e.attributes,(function(e){var t=e.name,n=e.value;return i.push(t,n)}));for(var a=0,s=i.length;a"),v.default.parse(i)[0].attrs));var i},t.setAttributeValue=function(e){var t=e.nodeId,n=e.name,o=e.value;(0,l.getNode)(t).setAttribute(n,o)},t.setInspectedNode=function(e){var t=(0,l.getNode)(e.nodeId);O.unshift(t),O.length>5&&O.pop();for(var n=0;n<5;n++)(0,k.setGlobal)("$".concat(n),O[n])},t.setNodeValue=function(e){var t=e.nodeId,n=e.value;(0,l.getNode)(t).nodeValue=n},t.setOuterHTML=function(e){var t=e.nodeId,n=e.outerHTML;(0,l.getNode)(t).outerHTML=n},t.getDOMNodeId=function(e){var t=e.node;return{nodeId:c.getOrCreateNodeId(t)}},t.getDOMNode=function(e){var t=e.nodeId;return{node:(0,l.getNode)(t)}},t.getTopLayerElements=function(){return{nodeIds:[]}},t.getNodesForSubtreeByStyle=function(){return{nodeIds:[]}};var s=a(n(8665)),c=i(n(9893)),l=n(9893),u=i(n(2484)),d=a(n(8757)),h=a(n(3693)),f=a(n(4236)),p=a(n(9464)),v=a(n(9548)),g=a(n(3915)),m=a(n(438)),b=a(n(3249)),y=a(n(96)),A=a(n(9100)),w=a(n(769)),_=a(n(8862)),x=a(n(4069)),k=n(2627),C=n(916);var S,E=!1;(S=Element.prototype.attachShadow)&&(Element.prototype.attachShadow=function(e){var t=S.apply(this,[e]);if(!c.isValidNode(this))return t;if(this.chobitsuShadowRoot=t,E){d.default.observe(t);var n=(0,l.getNodeId)(this);n&&s.default.trigger("DOM.shadowRootPushed",{hostId:n,root:c.wrap(t,{depth:1})})}return t});var T=new Map;function N(e){for(var t=[e],n=e.parentNode;n;){if(t.push(n),r=(0,l.getNodeId)(n))break;n=n.parentNode}for(;t.length;){var o=t.pop(),r=(0,l.getNodeId)(o);s.default.trigger("DOM.setChildNodes",{parentId:r,nodes:c.getChildNodes(o,1)})}return(0,l.getNodeId)(e)}var O=[];function j(e,t){for(var n=c.filterNodes(e.childNodes),o=0,r=n.length;o0&&r[r.length-1])||6!==s[0]&&2!==s[0])){i=0;continue}if(3===s[0]&&(!r||s[1]>r[0]&&s[1]-1)return r(e.substring(n+t.length,e.indexOf(".",n)))}e.exports=t},6631:function(e,t,n){var o=n(6030);t=function(e){return e?(e=o(e))-e%1:0===e?e:0},e.exports=t},6717:function(e,t,n){(t=n(6314)(!1)).push([e.id,"._container ._entry-btn{touch-action:none;width:40px;height:40px;display:flex;background:#000;opacity:.3;border-radius:10px;position:relative;z-index:1000;transition:opacity .3s;color:#fff;font-size:25px;align-items:center;justify-content:center}._container ._entry-btn._active,._container ._entry-btn:active{opacity:.8}",""]),e.exports=t},6741:function(e,t,n){var o=n(2717),r=n(6186),i=n(8105),a=n(2508),s=n(1738),c=n(3957);t=o({initialize:function(e,t){this._locale=e,this._langs=t},set:function(e,t){this._langs[e]?i(this._langs[e],t):this._langs[e]=t},t:function(e,t){var n="",o=this._langs[this._locale];return o?(n=r(o,e),t&&(s(n)?n=a(n,t):c(n)&&(n=n(t))),n||""):""},locale:function(e){this._locale=e}}),e.exports=t},6774:function(e,t){t=function(e,t,n){null==t&&(t=e,e=0);var o=Math.random();return n||e%1||t%1?Math.min(e+o*(t-e+parseFloat("1e-"+((o+"").length-1))),t):e+Math.floor(o*(t-e+1))},e.exports=t},6793:function(e,t,n){(t=n(6314)(!1)).push([e.id,"@font-face{font-family:eruda-icon;src:url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAA6UAAsAAAAAGvAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAARoAAAHeLjoycE9TLzIAAAIkAAAAPwAAAFZWm1KoY21hcAAAAmQAAAFdAAADwhPu1O9nbHlmAAADxAAAB+wAAA9I7RPQpGhlYWQAAAuwAAAAMQAAADZ26MSyaGhlYQAAC+QAAAAdAAAAJAgEBC9obXR4AAAMBAAAAB0AAACwXAv//GxvY2EAAAwkAAAAOwAAAFpuVmoybWF4cAAADGAAAAAfAAAAIAE9AQ1uYW1lAAAMgAAAASkAAAIWm5e+CnBvc3QAAA2sAAAA5QAAAU4VMmUJeJxNkD1Ow0AQhb9NHGISCH9RiB0cErCNHRrqFFSIyqKiQHSpEFJERUnBCTgPZ+AEHIe34wDe1f69efPezOKAHldc07q5re4ZrFevL8QE1MPHm3e3fn5aEf6+FAvsDHHuTUoxd7zzwSdffLulq9wjLbaYau8TacZMONE554xzZsrtNfBEzFOhbSmOyTmga0ikvRR/37RSsSMyDukYPjWdgGOtsSK55Y/k0Bf/ksK0MrbFr70idsVZKNPnDcSay3umd2TISCvWTJSxI78lFQ/C+qbv/Zo9tNXDP55ZL7k0Q90u5F5XX0qrYx16btccCtXg/ULrKzGFuqY9rUTMhf3fkCNj+MxUnsM/frr5Qx+ZbH4vVQ0F5Q/ZQBvxAAB4nGNgZJJgnMDAysDA1Mt0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDAcYdD+KsIC4MSxMDIxAGoQZALgnCOUAeJy1011SGlEQhuF3BFHxD5UUyr8gIJIsiiKJsSqJlrHKsJssKFeuxF6Bfj3dF96aqhzqoZnDzJyG8w2wCVTko1SheKLAx1/NFuV8hXo5X+WPjht6+fmfWHLDHQ+srfnykjMrvnPPoxXlzNtRlFc26HLBZblal1N9ntBnwIgx5/SYMaWt78+YM6TDgitduaEVq+q0xhbb7KifPQ441N2OOOaEJh9oaYka7xvdd57vQz1P+oPR+Bx6s2lbrc6H0Flc/cO9/sfY87fiOY8u8X0J/muX6VRW6UI+p4l8SX35mgZynUbyLY3lJukf0e6HnvxIM/mZpnKb2nKXvM/7dCa/0lwe0lAeU0d+p4Wsk3bBiuDptY2A10rw9Fo1eOJtM/iTYLWA162A1+2A152A13rwJ8R2g++AJaUU2w/KK3YQlFzsMCjDWCMozdhRUK6x46CEYydBWceagdYraihRngAAAHic7RdbbBxX9Z57Z2d2d2ZndryzM7ve9ax3NztjO/bann0lTuW16zoBJSWJ7Zg83NiUJCQ1Ik2ikKQJNC9FFQqVEG0RVLQoSpEKH2klqgpEIyWAUMRTNBJC/PUDhETgiwhQd8y5s1s7oqr624/srO6ce89zzjn3nHsJEPwxyn5GVEJKBTcCdc80pAiYhkjfNWL+NnhLdTKqfxVOqJlxFX6E84wb86/6X4+5GRLw0/vsOgkREoFGBFx62P/uFviBP78FWrC02d/r79vcpmMl+k2uBwwJxIILTrVeyXsmK8krRLb5YGqUaCb9ksYnMuBqMtnRcY6V1nidml6texaY9CxSRm3TtKNIjcxrUjhEWKD3OnuNJEgPKSG/I6nUpo06fxwXH8lmEoyDFQIVyrROs7254z990rj0u2PLez47WqG1yu69V7ZdfDxU9He4C6P+v+HN+vlnD9Uou0Zp+NnfvveT/XL0kbGFxT/u37tx7CTdeuGlKfiibcMr/gt9qfyu05e4+YEdb7A3iEVG0ArdEAvDIPHBqTbB7bgCDA0sdH0x3/nEHDT4YFJi9siz74iaOBkK3ZyRTRXwE+FGG15BeA0Pf14hqinP3AyFJnHhnVm5xzThmNSBNFjDdvwzw75GFJIlvWhZ1UHlYlI3zIputa3CSduiRF7P09e9on+jODpanPOKsJMDOPV2wU7/BqsVPcQ2ix41X/8ARKpbfhPVtHNgik1hXAhIlmQ1rIbbcCVIzN/7+65794KRTc13IBwJXVkhRACBkAEyhVyiBqJbRn81YRjKUDfRN9xHpoVBt0xJRZ+iS4ehZFg2utJrjCO2GrAUAizcj+c3pXpiXVQwThZmdNrbrx+hAjtjbhSF5FPyKSsqmGraWKYCbfl97vMLi79fXHje7XsAhBsoo0P35fyMPpCj+lM0FDptJexuYzl82upRufxlKgrTh/+fOwBXc+Jt9jZJBTnxUbH/yGT5j4jRT2pB9O1oO/oi3FyD2/ggU14LY/j5RuHTJIZf5LR/WVmbaB2CT6xdQa4KwJZIHPfyMFoWRNSmQZDLlJVpdRw8GwwVWEGlScOGijdOq2VKyfHDB7/d1/+d37zXeT/dXG42l7/Kh2a20pd0JpxsxTVNt8KWyuu/94Ujr+7uvFpvQXP5PCfEAU4l+6pZZ9Ix3eqGqmsGrvok28V+zi6TKEYyi/Udt0MNavkkJC1e+vQA1tGqil6EV93j/UBbY0AXm/2Vku+z53x/8MDT5879U9Nb4Cqq/yf/WEjReiECfS9+C2f/6umFS/77q3t7kp0nGu8DTrFTQrwG1KtsoHVXlnXL0qMKHTRpGbaJlt7aoVsSbO3aQFb5L7MTJElIwrBMvnWxQteCEl2QREn8Ci/Ef9i7u1IT6tX5Pb/ePV+rUXKEL3DMkUPzc6OeNzo3/6C8K2QdrzVlKAYyHhBcxGgUyoCRqXimJZXYwYO1y1tWxQWKLkyfunpqevrU5vJs4SQ02JUDw94qMlC6maORJpc9AR/Sm7C4cK7S4MoL/FNqFYy+Nw5VbpIoWaWXP0atf+fj1Lb36w12h6SxShIouuNQw+TCVDNsWvHqDStpNUoFnobUs6mhUvpmn+r2VxaeuXjmCc974vSjm44OxfytrXeH5iaKxYm5fXMThcLEHLwcGzq66dHTnObMxWcWKv2u2tfa1ipMzu7rEM5OFshqLfsFu4R9thszrVjAUoHFgH98DxRreb3CK74rMTh/bWmJTq9Pd0nCZOvsbfrYrVsTty9cOPc5Or2U6spq8rXbrbNAL9yeuHWLYuEnEiErK0JIAPIN8kNyl9wn/yUt7mioN6GGTi1jDQrypNPRxQ+8zREatnUsVtgbcDHAaZA0rc6TxOIWLPFVXLDbvYRT45CDSnBOqFhee4aTcWw8gapGnS+Z+EYrOuqh825jrY5WSVwPDSewh/OWqYueCJQFEjhELTdgcdEODjUCo5yge7lcAlJxRSgceyZyu5LFfqnaeldKlsyunnK6N6LEaUSqTSndgpZK7jC7NZaR7LGcGhXwgMNC+WFt0MxEomZcECQ9EY4JkgAQDilSNKnGuxXJ0u2hdG9YUZkiZcfWpaOWkUv0G6IaCseVVH81o0dEEClKGokassX0hKSk44PxBGOS4E8cmNk+OMSY5+2cXfz8zI4hrG4jI9tnFpW/hqKx7PCnH1O7wpFkqeANT4IUVhopPTUwnNJxzSlUzLASV+4YfUIkpoQFTYvoMUFkJgtJ/Z6VEIyymx4usdCW5CuDc9s+dZDm6GeiejTl1jN6VFKUdMHMlUIWzaQEOdyrKHIsL0VZJB0TE1rUlLvCo71yPKya3dW+ONBQRBajUdPuKoXFsBAOiYoUdx7JtSXlU3ZJNAW1O+4ktBCFqBjLJhMW97JgyonISE5kVIJQJJ6tO6nueCJj1TV/D6uMzu06tH/H44NlRr3RnbNPLu7cXh75sWOklURzi5ZI9dgqG6tuEAf0bkWX0/0j6S6+RjfaYiQsbkKHhuNdms6kUExWZNGSlJgzkjIGjPK61KjLxOvGc/1/27r9KOQe7omHe+LhnvjQnmArLTyHMYHiPbGbFLEL4Q1BxOsiHrfy2HIBz67BXQbPsVbB4TNDZP/wF4x63cAxUl/PRtbXI61f2QM2/iuZUqleKr3ABp1Mxnn/rjvpOJN0b9K2k/73+Xi/VHOcGl4qyf8AzjWNo3icY2BkYGAA4uhnXafj+W2+MnCzgASiOB/va4DR///+/8/CysIElOBgAJEMAHS2DWQAAAB4nGNgZGBgYQABFtb/f///ZWFlYGRABToAW+YEPQAAAHicY2BgYGAhiP//J6wGCbNCMcP/vwxUBgDl4QRhAAAAeJxjYAACBQYThiCGAoYtjAyMZowBjPuYuJjCmBYxvWNWYXZhzmFewfyIRYUliPUOexr7EmIhAF3rF0sAeJxjYGRgYNBhZGRgZwABJiDmAkIGhv9gPgMADcIBTAB4nGWQPW7CQBSEx2BIAlKCFCkps1UKIpmfkgNAT0GXwpi1MbK91npBossJcoQcIaeIcoIcKGPzaGAtP38zb97uygAG+IWHenm4bWq9WrihOnGb9CDsk5+FO+jjRbhLfyjcwxumwn084p07eP4dnQFK4Rbu8SHcpv8p7JO/hDt4wrdwl/6PcA8r/An38eoN08gUsSncUif7LLRnef6utK1SU6hJMD5bC11oGzq9Ueujqg7J1LlYxdbkas6uzjKjSmt2OnLB1rlyNhrF4geRyZEigkGBuKkOS2gk2CNDCHvVvdQrpi0q+rVWmCDA+Cq1YKpokiGVxobJNY6sFQ48bUrXMa34Ws7kpLnMat4kIyv+77q3oxPRD7BtpkrMMOITX+SD5g75Pz0RXqgAAAB4nG2MyW6DQBiD+RKYpKT7vqf7Gg55pNHwEyJNGDSMRHj70nKtD7Zly45G0YA0+h8LRoyJSVBMmLJDyoxd9tjngEOOOOaEU84454JLrrjmhlvuuGfOA4888cwLr7zxzgeffPHNgixKtfeuzawUYTZYv16VITXaS8hy11azwf7FibGi/dS4Te2laWLj6k7lYiVIIv3aK9nWusqng2TLsXR900m2VMXaBvFxbXWnvBjn84mXor8pk54kqKa/NmUvVkyIg3NW/VK2jFvtKzQeR0uGRSgIrFlRYsip2FDT0LGNoh/MCkh9AAAA') format('woff')}[class*=' _icon-'],[class^='_icon-']{display:inline-block;font-family:eruda-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}._icon-arrow-left:before{content:'\\f101'}._icon-arrow-right:before{content:'\\f102'}._icon-caret-down:before{content:'\\f103'}._icon-caret-right:before{content:'\\f104'}._icon-clear:before{content:'\\f105'}._icon-compress:before{content:'\\f106'}._icon-copy:before{content:'\\f107'}._icon-delete:before{content:'\\f108'}._icon-error:before{content:'\\f109'}._icon-expand:before{content:'\\f10a'}._icon-eye:before{content:'\\f10b'}._icon-filter:before{content:'\\f10c'}._icon-play:before{content:'\\f10d'}._icon-record:before{content:'\\f10e'}._icon-refresh:before{content:'\\f10f'}._icon-reset:before{content:'\\f110'}._icon-search:before{content:'\\f111'}._icon-select:before{content:'\\f112'}._icon-tool:before{content:'\\f113'}._icon-warn:before{content:'\\f114'}",""]),e.exports=t},6833:function(e,t){var n=/([A-Z])/g,o=/[_.\- ]+/g,r=/(^-)|(-$)/g;t=function(e){return(e=e.replace(n,"-$1").toLowerCase().replace(o,"-").replace(r,"")).split("-")},e.exports=t},6866:function(e,t,n){var o=n(1738),r=n(9760),i=n(7604),a=n(8971),s=n(3249),c=n(6097),l=n(3612),u=n(6969),d=n(9100);t=function(e,t,n){if(e=l(e),a(n)&&o(t))return function(e,t){return e.style[u(t)]||getComputedStyle(e,"").getPropertyValue(t)}(e[0],t);var f=t;r(f)||((f={})[t]=n),function(e,t){d(e,(function(e){var n=";";d(t,(function(e,t){t=u.dash(t),n+=t+":"+function(e,t){var n=c(t)&&!s(h,i(e));return n?t+"px":t}(t,e)+";"})),e.style.cssText+=n}))}(e,f)};var h=["column-count","columns","font-weight","line-weight","opacity","z-index","zoom"];e.exports=t},6911:function(e,t,n){"use strict";n.d(t,{j:function(){return Pe},A:function(){return $e}});var o=n(2284),r=n(3029),i=n(2901),a=n(388),s=n(3954),c=n(991),l=n(5361),u=n(5427),d=n.n(u),h=n(6097),f=n.n(h),p=n(6493),v=n.n(p),g=n(96),m=n.n(g),b=n(9760),y=n.n(b),A=n(6214),w=n.n(A),_=n(9931),x=n.n(_),k=n(3145),C=n.n(k),S=n(9100),E=n.n(S),T=n(1168),N=n.n(T),O=n(8796),j=n.n(O),M=n(2989),I=n.n(M),z=n(3693),D=n.n(z),B=n(466),F=n.n(B),R=n(15),L=n.n(R),G=n(1738),P=n.n(G),H=n(7514),Y=n.n(H),$=n(2571),q=n.n($),Q=n(7140),U=n.n(Q),W=n(2561),J=n.n(W),K=n(9993),V=n.n(K),Z=n(1532),X=n.n(Z),ee=n(8105),te=n.n(ee),ne=function(){return(0,i.A)((function e(){(0,r.A)(this,e),this.id=0,this.visited=[]}),[{key:"set",value:function(e,t){var n=this.visited,o=this.id,r={id:o,val:e};return te()(r,t),n.push(r),this.id++,o}},{key:"get",value:function(e){for(var t=this.visited,n=0,o=t.length;n500&&(e=e.slice(0,500)+"..."),"ƒ "+re()(function(e){var t=e.match(le);return t?t[0]:e}(e).replace("function",""))}var le=/function(.*?)\((.*?)\)/;var ue=n(1009),de=n.n(ue),he=n(5630),fe=n.n(he),pe=n(6030),ve=n.n(pe),ge=n(1932),me=n.n(ge),be=n(2263),ye=n.n(be),Ae=n(3915),we=n.n(Ae),_e=n(5169),xe=n.n(_e),ke=n(9548),Ce=n.n(ke),Se=n(3249),Ee=n.n(Se),Te=n(5004),Ne=n.n(Te);n(9410),n(8609);function Oe(e){var t="luna-".concat(e,"-");function n(e){return we()(re()(e).split(/\s+/),(function(e){return Ee()(e,t)?e:e.replace(/[\w-]+/,(function(e){return"".concat(t).concat(e)}))})).join(" ")}return function(e){if(/<[^>]*>/g.test(e))try{var t=Ce().parse(e);return je(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),Ce().stringify(t)}catch(t){return n(e)}return n(e)}}function je(e,t){for(var n=0,o=e.length;n2&&void 0!==arguments[2]?arguments[2]:{}).theme,u=void 0===l?"light":l;return(0,r.A)(this,t),o=function(e,t,n){return t=(0,s.A)(t),(0,a.A)(e,Re()?Reflect.construct(t,n||[],(0,s.A)(e).constructor):t.apply(e,n))}(this,t),o.subComponents=[],o.theme="",o.onThemeChange=function(e){"auto"===o.options.theme&&o.setTheme(e)},o.compName=c,o.c=Oe(c),o.options={},o.container=e,o.$container=D()(e),o.$container.addClass(["luna-".concat(c),o.c("platform-".concat((i=Ne()(),"os x"===i?"mac":i)))]),o.on("changeOption",(function(e,t){if("theme"===e&&t){var n=t;"auto"===t&&(n=Fe().get()),o.setTheme(n),E()(o.subComponents,(function(e){return e.setOption("theme",t)}))}})),Fe().on("change",o.onThemeChange),o.setOption("theme",u),o}return(0,l.A)(t,e),(0,i.A)(t,[{key:"destroy",value:function(){var e=this;this.destroySubComponents();var t=this.$container,n=t.attr("class");E()(n.split(/\s+/),(function(n){de()(n,"luna-".concat(e.compName))&&t.rmClass(n)})),t.html(""),this.emit("destroy"),this.removeAllListeners(),Fe().off("change",this.onThemeChange)}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,E()(r,(function(e,t){var r=o[t];o[t]=e,e!==r&&n.emit("changeOption",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){De()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){E()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};Ie()(e,t),te()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}},{key:"setTheme",value:function(e){var t=this.c,n=this.$container;this.theme&&n.rmClass(t("theme-".concat(this.theme))),n.addClass(t("theme-".concat(e))),this.theme=e}}])}(ye());function Ge(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(Ge=function(){return!!e})()}var Pe=function(e){function t(e){var n,o,i,c;return(0,r.A)(this,t),o=this,i=t,c=[e,{compName:"object-viewer"}],i=(0,s.A)(i),(n=(0,a.A)(o,Ge()?Reflect.construct(i,c||[],(0,s.A)(o).constructor):i.apply(o,c))).onItemClick=function(e){var t=n,o=t.map,r=t.c,i=D()(e.curTarget),a=i.data("object-id"),s=i.find("span").eq(0);if(!i.data("first-level")&&(a&&(i.find("ul").html(n.objToHtml(o[a],!1)),i.rmAttr("data-object-id")),e.stopImmediatePropagation(),s.hasClass(r("expanded")))){var c=i.find("ul").eq(0);s.hasClass(r("collapsed"))?(s.rmClass(r("collapsed")),c.show()):(s.addClass(r("collapsed")),c.hide()),n.emit("change")}},n.bindEvent(),n}return(0,l.A)(t,e),(0,i.A)(t,[{key:"set",value:function(e){P()(e)&&(e=JSON.parse(e)),this.data={id:fe()("json"),enumerable:{0:e}},this.map={},He(this.map,this.data),this.render()}},{key:"destroy",value:function(){var e,n,o,r,i;(e=t,n="destroy",o=this,r=3,i=(0,c.A)((0,s.A)(1&r?e.prototype:e),n,o),2&r&&"function"==typeof i?function(e){return i.apply(o,e)}:i)([]),this.$container.off("click","li",this.onItemClick)}},{key:"objToHtml",value:function(e,t){var n=this,o="";return E()(["enumerable","unenumerable","symbol"],(function(r){if(e[r]){var i=C()(e[r]);X()(i);for(var a=0,s=i.length;a3&&void 0!==arguments[3]&&arguments[3],i=this.c,a=(0,o.A)(t);if(null===t)return"
  • ".concat(h(e),'null
  • ');if(f()(t)||v()(t))return"
  • ".concat(h(e),'').concat(se(t),"
  • ");if("RegExp"===t.type&&(a="regexp"),"Number"===t.type&&(a="number"),"Number"===t.type||"RegExp"===t.type)return"
  • ".concat(h(e),'').concat(se(t.value),"
  • ");if("Undefined"===t.type||"Symbol"===t.type)return"
  • ".concat(h(e),'').concat(m()(t.type),"
  • ");if("(...)"===t)return"
  • ".concat(h(e),'').concat(t,"
  • ");if(y()(t)){var s=t.id,c=t.reference,l=function(e){var t=e.type,n=e.value;if(!t)return;if("Function"===t)return ce(n);if("Array"===t&&e.unenumerable)return"Array(".concat(e.unenumerable.length,")");return e.type}(t)||x()(a),u=r?"":''),d="
  • ").concat(u).concat(h(e),'').concat(r?"":l,'
      ");return r&&(d+=this.objToHtml(this.map[s])),d+'
  • ')}function h(e){if(r)return"";if(y()(t)&&t.jsonSplitArr)return"";var o=i("key");return"unenumerable"===n||"symbol"===n?o=i("key-lighter"):"proto"===n&&(o=i("key-special")),'').concat(se(e),": ")}return P()(t)&&t.length>1e4&&(t=L()(t,50,{separator:" ",ellipsis:"…"})),"
  • ".concat(h(e),'"').concat(se(t),'"
  • ')}},{key:"render",value:function(){var e=this.map[this.data.id];this.$container.html(this.objToHtml(e,!0))}},{key:"bindEvent",value:function(){this.$container.on("click","li",this.onItemClick)}}])}(Le);function He(e,t){var n=t.id;if(n||0===n){if(t.type&&de()(t.type,"Array")&&t.enumerable){var o=function(e,t,n){var o=[],r={};E()(e.enumerable,(function(e,t){var n=ve()(t);me()(n)?r[t]=e:o[n]=e})),o.enumerable=r,o.type=n,o.id=t,e.unenumerable&&(o.unenumerable=e.unenumerable);e.symbol&&(o.symbol=e.symbol);e.proto&&(o.proto=e.proto);return o}(t,n,t.type);o.length>100&&(t=function(e){var t=0,n={};E()(U()(e,100),(function(e){var o={},r=t;o.type="["+r,o.enumerable={},E()(e,(function(e){o.enumerable[t]=e,t+=1}));var i=t-1;o.type+=(i-r>0?" … "+i:"")+"]",o.id=fe()("json"),o.jsonSplitArr=!0,n[t]=o}));var o={};o.enumerable=n,o.id=e.id,o.type=e.type,e.unenumerable&&(o.unenumerable=e.unenumerable);e.symbol&&(o.symbol=e.symbol);e.proto&&(o.proto=e.proto);return o}(o))}e[n]=t;var r=[];E()(["enumerable","unenumerable","symbol"],(function(e){if(t[e])for(var n in t[e])r.push(t[e][n])})),t.proto&&r.push(t.proto);for(var i=0,a=r.length;i1&&void 0!==arguments[1]?arguments[1]:{};return(0,r.A)(this,t),o=this,i=t,c=[e,{compName:"object-viewer"}],i=(0,s.A)(i),(n=(0,a.A)(o,Ye()?Reflect.construct(i,c||[],(0,s.A)(o).constructor):i.apply(o,c))).onItemClick=function(e){var t=n,o=t.map,r=t.c;if(!function(e){var t=window.getSelection();if(!t||"Range"!==t.type||""===t.toString())return!1;var n=t.anchorNode,o=t.focusNode;return t.containsNode(e,!0)||n&&e.contains(n)||o&&e.contains(o)}(e.curTarget)){var i=D()(e.curTarget),a=i.data("object-id"),s=i.find("span").eq(0);if(!i.data("first-level")&&(a&&(i.find("ul").html(n.objToHtml(o[a],!1)),i.rmAttr("data-object-id")),e.stopImmediatePropagation(),s.hasClass(r("expanded")))){var c=i.find("ul").eq(0);s.hasClass(r("collapsed"))?(s.rmClass(r("collapsed")),c.show()):(s.addClass(r("collapsed")),c.hide()),n.emit("change")}}},n.initOptions(l,{prototype:!0,unenumerable:!1,accessGetter:!1}),n.bindEvent(),n.options.object&&n.set(n.options.object),n}return(0,l.A)(t,e),(0,i.A)(t,[{key:"set",value:function(e){this.data=[e],this.visitor=new ne,this.map={},this.render()}},{key:"destroy",value:function(){var e,n,o,r,i;(e=t,n="destroy",o=this,r=3,i=(0,c.A)((0,s.A)(1&r?e.prototype:e),n,o),2&r&&"function"==typeof i?function(e){return i.apply(o,e)}:i)([]),this.$container.off("click","li",this.onItemClick)}},{key:"objToHtml",value:function(e,t){var n=this,r=this.visitor,i=e,a=!1,s=r.get(e);s&&s.self&&(i=s.self);var c="",l=["enumerable"],u=C()(e),h=[],f=[],p=[],v={};if(this.options.unenumerable&&!t&&(l.push("unenumerable"),l.push("symbol"),h=F()(Y()(e,{prototype:!1,unenumerable:!0}),u),f=q()(Y()(e,{prototype:!1,symbol:!0}),(function(e){return"symbol"===(0,o.A)(e)}))),w()(e)&&e.length>100){l.unshift("virtual"),a=!0;var g=0,m={};E()(U()(e,100),(function(e){var t=Object.create(null),n=g,o="["+n;E()(e,(function(e){t[g]=e,m[g]=!0,g++}));var r=g-1;v[o+=(r-n>0?" … "+r:"")+"]"]=t})),p=C()(v),u=q()(u,(function(e){return!m[e]}))}if(E()(l,(function(o){var r=[];r="symbol"===o?f:"unenumerable"===o?h:"virtual"===o?p:u,a||X()(r);for(var s=0,l=r.length;s4&&void 0!==arguments[4]&&arguments[4],a=this.visitor,s=this.c,c=(0,o.A)(n),l=I()(n,!1);if("virtual"===r&&(l=e),null===n)return"
  • ".concat(A(e),'null
  • ');if(f()(n)||v()(n))return"
  • ".concat(A(e),'').concat(se(n),"
  • ");if("RegExp"===l&&(c="regexp"),"Number"===l&&(c="number"),"Undefined"===l||"Symbol"===l)return"
  • ".concat(A(e),'').concat(m()(l),"
  • ");if("(...)"===n)return"
  • ".concat(A(e),'').concat(n,"
  • ");if(y()(n)){var u,d=a.get(n);if(d)u=d.id;else{var h={};"proto"===r&&(h.self=t),u=a.set(n,h),this.map[u]=n}var p="Object";p="regexp"===c?'').concat(se(n)):se(function(e,t){if(!t)return;if("Function"===t)return ce(N()(e));if("Array"===t)return"Array(".concat(e.length,")");return t}(n,l)||x()(c));var g=i?"":''),b="
  • ").concat(g).concat(A(e),'').concat(i?"":p,'
      ");return i&&(b+=this.objToHtml(n)),b+'
  • ')}function A(e){if(i)return"";if(y()(n)&&"virtual"===r)return"";var t=s("key");return"unenumerable"===r||"symbol"===r?t=s("key-lighter"):"proto"===r&&(t=s("key-special")),'').concat(se(e),": ")}return P()(n)&&n.length>1e4&&(n=L()(n,50,{separator:" ",ellipsis:"…"})),"
  • ".concat(A(e),'"').concat(se(n),'"
  • ')}},{key:"render",value:function(){this.$container.html(this.objToHtml(this.data,!0))}},{key:"bindEvent",value:function(){var e=this;this.$container.on("click","li",this.onItemClick),this.on("changeOption",(function(t,n){switch(t){case"object":e.set(n);break;case"unenumerable":case"prototype":case"accessGetter":e.render()}}))}}])}(Le);$e.Static=Pe,function(e,t){try{e.exports=t,e.exports.default=t}catch(e){}}(e,$e)},6948:function(e,t){var n=/<[^>]*>/g;t=function(e){return e.replace(n,"")},e.exports=t},6949:function(e,t,n){var o=n(365),r=n(6214);t=function(e,t){if(r(e))return e;if(t&&o(t,e))return[e];var n=[];return e.replace(i,(function(e,t,o,r){n.push(o?r.replace(a,"$1"):t||e)})),n};var i=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,a=/\\(\\)?/g;e.exports=t},6962:function(e,t,n){var o=n(1909),r=n(1023),i=!1;function a(e){i&&t.emit(e)}t={start:function(){i=!0},stop:function(){i=!1}},r.mixin(t),o?(window.addEventListener("error",(function(e){if(e.error)a(e.error);else if(e.message){var t=new Error(e.message);t.stack="Error: ".concat(e.message," \n at ").concat(e.filename,":").concat(e.lineno,":").concat(e.colno),a(t)}})),window.addEventListener("unhandledrejection",(function(e){a(e.reason)}))):(process.on("uncaughtException",a),process.on("unhandledRejection",a)),e.exports=t},6969:function(e,t,n){var o=n(5869),r=n(387),i=n(9931),a=n(365),s=n(7604);(t=o((function(e){if(e=e.replace(l,""),e=r(e),a(u,e))return e;for(var t=c.length;t--;){var n=c[t]+i(e);if(a(u,n))return n}return e}))).dash=o((function(e){var n=t(e);return(l.test(n)?"-":"")+s(n)}));var c=["O","ms","Moz","Webkit"],l=/^(O)|(ms)|(Moz)|(Webkit)|(-o-)|(-ms-)|(-moz-)|(-webkit-)/g,u=document.createElement("p").style;e.exports=t},7e3:function(e,t,n){var o=n(2263),r=new(n(3737))("(prefers-color-scheme: dark)");t={get:function(){return r.isMatch()?"dark":"light"}},o.mixin(t),r.on("match",(function(){return t.emit("change","dark")})),r.on("unmatch",(function(){return t.emit("change","light")})),e.exports=t},7005:function(e,t,n){var o=n(2717),r=n(5395);t=o({initialize:function(){this.clear()},clear:function(){this._items=[],this.size=0},push:function(e){return this._items.push(e),++this.size},pop:function(){if(this.size)return this.size--,this._items.pop()},peek:function(){return this._items[this.size-1]},forEach:function(e,t){t=arguments.length>1?t:this;for(var n=this._items,o=this.size-1,r=0;o>=0;o--,r++)e.call(t,n[o],r,this)},toArr:function(){return r(this._items)}}),e.exports=t},7030:function(e,t,n){var o=n(1738),r=n(2517),i=n(2561),a=n(6392);t=function(e,n,a,h){1===arguments.length&&o(e)&&!u.test(e)&&(n=e,e=void 0),e=e||new Date,r(e)||(e=new Date(e));var f=(n=i(t.masks[n]||n||t.masks.default)).slice(0,4);"UTC:"!==f&&"GMT:"!==f||(n=n.slice(4),a=!0,"GMT:"===f&&(h=!0));var p=a?"getUTC":"get",v=e[p+"Date"](),g=e[p+"Day"](),m=e[p+"Month"](),b=e[p+"FullYear"](),y=e[p+"Hours"](),A=e[p+"Minutes"](),w=e[p+"Seconds"](),_=e[p+"Milliseconds"](),x=a?0:e.getTimezoneOffset(),k={d:v,dd:s(v),ddd:t.i18n.dayNames[g],dddd:t.i18n.dayNames[g+7],m:m+1,mm:s(m+1),mmm:t.i18n.monthNames[m],mmmm:t.i18n.monthNames[m+12],yy:i(b).slice(2),yyyy:b,h:y%12||12,hh:s(y%12||12),H:y,HH:s(y),M:A,MM:s(A),s:w,ss:s(w),l:s(_,3),L:s(Math.round(_/10)),t:y<12?"a":"p",tt:y<12?"am":"pm",T:y<12?"A":"P",TT:y<12?"AM":"PM",Z:h?"GMT":a?"UTC":(i(e).match(l)||[""]).pop().replace(d,""),o:(x>0?"-":"+")+s(100*Math.floor(Math.abs(x)/60)+Math.abs(x)%60,4),S:["th","st","nd","rd"][v%10>3?0:(v%100-v%10!=10)*v%10]};return n.replace(c,(function(e){return e in k?k[e]:e.slice(1,e.length-1)}))};var s=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:2;return a(i(e),t,"0")},c=/d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZWN]|"[^"]*"|'[^']*'/g,l=/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,u=/\d/,d=/[^-+\dA-Z]/g;t.masks={default:"ddd mmm dd yyyy HH:MM:ss",shortDate:"m/d/yy",mediumDate:"mmm d, yyyy",longDate:"mmmm d, yyyy",fullDate:"dddd, mmmm d, yyyy",shortTime:"h:MM TT",mediumTime:"h:MM:ss TT",longTime:"h:MM:ss TT Z",isoDate:"yyyy-mm-dd",isoTime:"HH:MM:ss",isoDateTime:"yyyy-mm-dd'T'HH:MM:sso",isoUtcDateTime:"UTC:yyyy-mm-dd'T'HH:MM:ss'Z'",expiresHeaderFormat:"ddd, dd mmm yyyy HH:MM:ss Z"},t.i18n={dayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],monthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","January","February","March","April","May","June","July","August","September","October","November","December"]},e.exports=t},7119:function(e){e.exports='.luna-dom-highlighter{position:fixed;left:0;top:0;width:100%;height:100%;z-index:100000;pointer-events:none;font-size:13px}.luna-dom-highlighter-fill{position:absolute;top:0;right:0;bottom:0;left:0}.luna-dom-highlighter-platform-linux{font-family:Roboto,Ubuntu,Arial,sans-serif}.luna-dom-highlighter-platform-mac{color:#303942;font-family:\'.SFNSDisplay-Regular\',\'Helvetica Neue\',\'Lucida Grande\',sans-serif}.luna-dom-highlighter-platform-windows{font-family:\'Segoe UI\',Tahoma,sans-serif}.luna-dom-highlighter-px{color:gray}#luna-dom-highlighter-element-title{position:absolute;z-index:10}.luna-dom-highlighter-tooltip-content{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:#fff;padding:5px 8px;border:1px solid #fff;border-radius:3px;box-sizing:border-box;min-width:100px;max-width:min(300px,100% - 4px);z-index:2;background-clip:padding-box;will-change:transform;text-rendering:optimizeLegibility;pointer-events:none;filter:drop-shadow(0 2px 4px rgba(0,0,0,.35))}.luna-dom-highlighter-tooltip-content .luna-dom-highlighter-tooltip-arrow{background:#fff;width:15px;height:8px;position:absolute}.luna-dom-highlighter-element-info-section{margin-top:12px;margin-bottom:6px}.luna-dom-highlighter-section-name{color:#333;font-weight:500;font-size:10px;text-transform:uppercase;letter-spacing:.05em;line-height:12px}.luna-dom-highlighter-element-info{display:flex;flex-direction:column}.luna-dom-highlighter-element-info-header{display:flex;align-items:center}.luna-dom-highlighter-element-info-body{display:flex;flex-direction:column;padding-top:2px;margin-top:2px}.luna-dom-highlighter-element-info-row{display:flex;line-height:19px}.luna-dom-highlighter-separator-container{display:flex;align-items:center;flex:auto;margin-left:7px}.luna-dom-highlighter-separator{border-top:1px solid #ddd;width:100%}.luna-dom-highlighter-element-info-name{flex-shrink:0;color:#666}.luna-dom-highlighter-element-info-gap{flex:auto}.luna-dom-highlighter-element-info-value-color{display:flex;color:#303942;margin-left:10px;align-items:baseline}.luna-dom-highlighter-a11y-icon{width:16px;height:16px;background-repeat:no-repeat;display:inline-block}.luna-dom-highlighter-element-info-value-contrast{display:flex;align-items:center;text-align:right;color:#303942;margin-left:10px}.luna-dom-highlighter-element-info-value-contrast .luna-dom-highlighter-a11y-icon{margin-left:8px}.luna-dom-highlighter-element-info-value-icon{display:flex;align-items:center}.luna-dom-highlighter-element-info-value-text{text-align:right;color:#303942;margin-left:10px;align-items:baseline;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.luna-dom-highlighter-color-swatch{display:flex;margin-right:2px;width:10px;height:10px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);line-height:10px}.luna-dom-highlighter-color-swatch-inner{flex:auto;border:1px solid #808002}.luna-dom-highlighter-element-layout-type{margin-right:10px;width:16px;height:16px}.luna-dom-highlighter-element-layout-type.luna-dom-highlighter-grid{background-image:url(\'data:image/svg+xml,\')}.luna-dom-highlighter-element-layout-type.luna-dom-highlighter-flex{background-image:url(\'data:image/svg+xml,\')}.luna-dom-highlighter-element-description{flex:1 1;font-weight:700;word-wrap:break-word;word-break:break-all}.luna-dom-highlighter-dimensions{color:#737373;text-align:right;margin-left:10px}.luna-dom-highlighter-material-node-width{margin-right:2px}.luna-dom-highlighter-material-node-height{margin-left:2px}.luna-dom-highlighter-material-tag-name{color:#881280}.luna-dom-highlighter-material-class-name,.luna-dom-highlighter-material-node-id{color:#1a1aa6}.luna-dom-highlighter-contrast-text{width:16px;height:16px;text-align:center;line-height:16px;margin-right:8px;border:1px solid #000;padding:0 1px}.luna-dom-highlighter-a11y-icon-not-ok{background-image:url(\'data:image/svg+xml,\')}.luna-dom-highlighter-a11y-icon-warning{background-image:url(\'data:image/svg+xml,\')}.luna-dom-highlighter-a11y-icon-ok{background-image:url(\'data:image/svg+xml,\')}@media (forced-colors:active){:root,body{background-color:transparent;forced-color-adjust:none}.luna-dom-highlighter-tooltip-content{border-color:Highlight;background-color:canvas;color:text;forced-color-adjust:none}.luna-dom-highlighter-tooltip-content::after{background-color:Highlight}.luna-dom-highlighter-color-swatch-inner,.luna-dom-highlighter-contrast-text,.luna-dom-highlighter-separator{border-color:Highlight}.luna-dom-highlighter-section-name{color:Highlight}.luna-dom-highlighter-dimensions,.luna-dom-highlighter-element-info-name,.luna-dom-highlighter-element-info-value-color,.luna-dom-highlighter-element-info-value-contrast,.luna-dom-highlighter-element-info-value-icon,.luna-dom-highlighter-element-info-value-text,.luna-dom-highlighter-material-class-name,.luna-dom-highlighter-material-node-id,.luna-dom-highlighter-material-tag-name{color:canvastext}}\n\n/*# sourceMappingURL=luna-dom-highlighter.css.map*/'},7140:function(e,t){t=function(e,t){var n=[];t=t||1;for(var o=0,r=Math.ceil(e.length/t);o0?n.join("="):null;o=decodeURIComponent(o),r=decodeURIComponent(r),i(t[o])?t[o]=r:a(t[o])?t[o].push(r):t[o]=[t[o],r]})),t},stringify:function(e,n){return l(s(e,(function(e,o){return u(e)&&c(e)?"":a(e)?t.stringify(e,o):(n?encodeURIComponent(n):encodeURIComponent(o))+"="+encodeURIComponent(e)})),(function(e){return e.length>0})).join("&")}};var d=/^(\?|#|&)/g;e.exports=t},7308:function(e,t,n){var o=n(9100),r=n(1738),i=n(8971),a=n(3249),s=n(6214),c=n(9760),l=n(769);(t=function(e,t){if(i(e))return n={},d((function(e,t){n[e]=t})),n;var n;if(r(e)&&i(t)||s(e))return function(e){if(!r(e)){var t={};return d((function(n,o){a(e,n)&&(t[n]=o)})),t}var n=h(e);if(n)return n.getAttribute("content")}(e);var l=e;c(l)||((l={})[e]=t),function(e){o(e,(function(e,t){var n=h(t);if(n)return n.setAttribute("content",e);(n=u.createElement("meta")).setAttribute("name",t),n.setAttribute("content",e),u.head.appendChild(n)}))}(l)}).remove=function(e){e=l(e),o(e,(function(e){var t=h(e);t&&u.head.removeChild(t)}))};var u=document;function d(e){var t=u.querySelectorAll("meta");o(t,(function(t){var n=t.getAttribute("name"),o=t.getAttribute("content");n&&o&&e(n,o)}))}function h(e){return u.querySelector('meta[name="'+e+'"]')}e.exports=t},7375:function(e,t){t=function(e,t,n){return Array.prototype.indexOf.call(e,t,n)},e.exports=t},7468:function(e,t,n){var o=n(3145);t=function(e,t){var n=o(t),r=n.length;if(null==e)return!r;e=Object(e);for(var i=0;i1&&void 0!==arguments[1]?arguments[1]:{},n=t.prototype,c=void 0===n||n,l=t.unenumerable,u=void 0!==l&&l,d=t.symbol,h=void 0!==d&&d,f=[];if((u||h)&&a){var p=o;u&&a&&(p=a);do{f=f.concat(p(e)),h&&s&&(f=f.concat(s(e)))}while(c&&(e=r(e))&&e!==Object.prototype);f=i(f)}else if(c)for(var v in e)f.push(v);else f=o(e);return f},e.exports=t},7528:function(e,t,n){"use strict";function o(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}n.d(t,{A:function(){return o}})},7542:function(e,t){t=function(e,t){var n;return function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=null),n}},e.exports=t},7571:function(e,t,n){var o=n(2263),r=n(6186),i=window.screen;t={get:function(){if(i){var e=r(i,"orientation.type");if(e)return e.split("-").shift()}return window.innerWidth>window.innerHeight?"landscape":"portrait"}},o.mixin(t),window.addEventListener("orientationchange",(function(){setTimeout((function(){t.emit("change",t.get())}),200)}),!1),e.exports=t},7604:function(e,t,n){var o=n(6833);t=function(e){return o(e).join("-")},e.exports=t},7622:function(e,t,n){var o=n(2263),r=n(2192),i=n(769),a=n(8971),s=n(8420),c=n(1738),l=n(6097);t=o.extend({initialize:function(e,n){this.name=e,this.setLevel(a(n)?t.level.DEBUG:n),this.callSuper(o,"initialize",arguments)},setLevel:function(e){return c(e)?((e=t.level[e.toUpperCase()])&&(this._level=e),this):(l(e)&&(this._level=e),this)},getLevel:function(){return this._level},formatter:function(e,t){return t},trace:function(){return this._log("trace",arguments)},debug:function(){return this._log("debug",arguments)},info:function(){return this._log("info",arguments)},warn:function(){return this._log("warn",arguments)},error:function(){return this._log("error",arguments)},_log:function(e,n){return 0===(n=i(n)).length?this:(this.emit("all",e,s(n)),t.level[e.toUpperCase()]*{vertical-align:top}.luna-console-log-item .luna-console-log-content .luna-console-null,.luna-console-log-item .luna-console-log-content .luna-console-undefined{color:#5e5e5e}.luna-console-log-item .luna-console-log-content .luna-console-number{color:#1c00cf}.luna-console-log-item .luna-console-log-content .luna-console-boolean{color:#0d22aa}.luna-console-log-item .luna-console-log-content .luna-console-regexp,.luna-console-log-item .luna-console-log-content .luna-console-symbol{color:#881391}.luna-console-log-item .luna-console-data-grid,.luna-console-log-item .luna-console-dom-viewer{white-space:initial}.luna-console-log-item.luna-console-error{z-index:50;background:#fff0f0;color:red;border-top:1px solid #ffd6d6;border-bottom:1px solid #ffd6d6}.luna-console-log-item.luna-console-error .luna-console-stack{padding-left:1.2em;white-space:nowrap}.luna-console-log-item.luna-console-error .luna-console-count{background:red}.luna-console-log-item.luna-console-debug{z-index:20}.luna-console-log-item.luna-console-input{border-bottom-color:transparent}.luna-console-log-item.luna-console-warn{z-index:40;color:#5c5c00;background:#fffbe5;border-top:1px solid #fff5c2;border-bottom:1px solid #fff5c2}.luna-console-log-item.luna-console-warn .luna-console-count{background:#e8a400}.luna-console-log-item.luna-console-info{z-index:30}.luna-console-log-item.luna-console-group,.luna-console-log-item.luna-console-groupCollapsed{font-weight:700}.luna-console-preview{display:inline-block}.luna-console-preview .luna-console-preview-container{display:flex;align-items:center}.luna-console-preview .luna-console-json{overflow-x:auto;-webkit-overflow-scrolling:touch;padding-left:12px}.luna-console-preview .luna-console-preview-icon-container{display:block}.luna-console-preview .luna-console-preview-icon-container .luna-console-icon{position:relative;font-size:12px}.luna-console-preview .luna-console-preview-icon-container .luna-console-icon-caret-down{top:2px}.luna-console-preview .luna-console-preview-icon-container .luna-console-icon-caret-right{top:1px}.luna-console-preview .luna-console-preview-content-container{word-break:break-all}.luna-console-preview .luna-console-descriptor,.luna-console-preview .luna-console-object-preview{font-style:italic}.luna-console-preview .luna-console-key{color:#881391}.luna-console-preview .luna-console-number{color:#1c00cf}.luna-console-preview .luna-console-null{color:#5e5e5e}.luna-console-preview .luna-console-string{color:#c41a16}.luna-console-preview .luna-console-boolean{color:#0d22aa}.luna-console-preview .luna-console-special{color:#5e5e5e}.luna-console-theme-dark{color-scheme:dark}.luna-console-theme-dark .luna-console-log-container.luna-console-selected .luna-console-log-item{background:#29323d}.luna-console-theme-dark .luna-console-log-container.luna-console-selected .luna-console-log-item:not(.luna-console-error):not(.luna-console-warn){border-color:#4173b4}.luna-console-theme-dark .luna-console-log-item{color:#a5a5a5;border-bottom-color:#3d3d3d}.luna-console-theme-dark .luna-console-log-item .luna-console-code .luna-console-keyword{color:#e36eec}.luna-console-theme-dark .luna-console-log-item .luna-console-code .luna-console-number{color:#9980ff}.luna-console-theme-dark .luna-console-log-item .luna-console-code .luna-console-operator{color:#7f7f7f}.luna-console-theme-dark .luna-console-log-item .luna-console-code .luna-console-comment{color:#747474}.luna-console-theme-dark .luna-console-log-item .luna-console-code .luna-console-string{color:#f29766}.luna-console-theme-dark .luna-console-log-item.luna-console-error{background:#290000;color:#ff8080;border-top-color:#5c0000;border-bottom-color:#5c0000}.luna-console-theme-dark .luna-console-log-item.luna-console-error .luna-console-count{background:#ff8080}.luna-console-theme-dark .luna-console-log-item.luna-console-warn{color:#ffcb6b;background:#332a00;border-top-color:#650;border-bottom-color:#650}.luna-console-theme-dark .luna-console-log-item .luna-console-count{background:#42597f;color:#949494}.luna-console-theme-dark .luna-console-log-item .luna-console-log-content .luna-console-null,.luna-console-theme-dark .luna-console-log-item .luna-console-log-content .luna-console-undefined{color:#7f7f7f}.luna-console-theme-dark .luna-console-log-item .luna-console-log-content .luna-console-boolean,.luna-console-theme-dark .luna-console-log-item .luna-console-log-content .luna-console-number{color:#9980ff}.luna-console-theme-dark .luna-console-log-item .luna-console-log-content .luna-console-regexp,.luna-console-theme-dark .luna-console-log-item .luna-console-log-content .luna-console-symbol{color:#e36eec}.luna-console-theme-dark .luna-console-icon-container .luna-console-icon-caret-down,.luna-console-theme-dark .luna-console-icon-container .luna-console-icon-caret-right{color:#9aa0a6}.luna-console-theme-dark .luna-console-header{border-bottom-color:#3d3d3d}.luna-console-theme-dark .luna-console-nesting-level{border-right-color:#3d3d3d}.luna-console-theme-dark .luna-console-nesting-level::before{border-bottom-color:#3d3d3d}.luna-console-theme-dark .luna-console-preview .luna-console-key{color:#e36eec}.luna-console-theme-dark .luna-console-preview .luna-console-number{color:#9980ff}.luna-console-theme-dark .luna-console-preview .luna-console-null{color:#7f7f7f}.luna-console-theme-dark .luna-console-preview .luna-console-string{color:#f29766}.luna-console-theme-dark .luna-console-preview .luna-console-boolean{color:#9980ff}.luna-console-theme-dark .luna-console-preview .luna-console-special{color:#7f7f7f}",""]),e.exports=t},8009:function(e,t,n){var o=n(6513);t=function(e,t){e.prototype=o(t.prototype)},e.exports=t},8032:function(e,t,n){var o=n(2989),r=n(9931),i=n(2561),a=n(8971),s=n(3957),c=n(1976);t=function(e,t){return JSON.stringify(e,(n=[],l=[],function(e,t){if(n.length>0){var u=n.indexOf(this);u>-1?(n.splice(u+1),l.splice(u,1/0,e)):(n.push(this),l.push(e));var d=n.indexOf(t);d>-1&&(t=n[0]===t?"[Circular ~]":"[Circular ~."+l.slice(0,d).join(".")+"]")}else n.push(t);return c(t)||s(t)?t="["+r(o(t))+" "+i(t)+"]":a(t)&&(t=null),t}),t);var n,l},e.exports=t},8046:function(e,t,n){var o=n(7731);t=function(){var e=o(16);return e[6]=15&e[6]|64,e[8]=63&e[8]|128,r[e[0]]+r[e[1]]+r[e[2]]+r[e[3]]+"-"+r[e[4]]+r[e[5]]+"-"+r[e[6]]+r[e[7]]+"-"+r[e[8]]+r[e[9]]+"-"+r[e[10]]+r[e[11]]+r[e[12]]+r[e[13]]+r[e[14]]+r[e[15]]};for(var r=[],i=0;i<256;i++)r[i]=(i+256).toString(16).substr(1);e.exports=t},8052:function(e,t,n){"use strict";n.d(t,{A:function(){return K}});var o=n(7528),r=n(3029),i=n(2901),a=n(388),s=n(3954),c=n(5361),l=n(2263),u=n.n(l),d=n(3693),h=n.n(d),f=n(3915),p=n.n(f),v=n(9405),g=n.n(v),m=n(5169),b=n.n(m),y=n(9548),A=n.n(y),w=n(6097),_=n.n(w),x=n(3249),k=n.n(x),C=(n(6030),n(5004)),S=n.n(C);n(9410),n(8609);function E(e){var t="luna-".concat(e,"-");function n(e){return p()(g()(e).split(/\s+/),(function(e){return k()(e,t)?e:e.replace(/[\w-]+/,(function(e){return"".concat(t).concat(e)}))})).join(" ")}return function(e){if(/<[^>]*>/g.test(e))try{var t=A().parse(e);return T(t,(function(e){e.attrs&&e.attrs.class&&(e.attrs.class=n(e.attrs.class))})),A().stringify(t)}catch(t){return n(e)}return n(e)}}function T(e,t){for(var n=0,o=e.length;n2&&void 0!==arguments[2]?arguments[2]:{}).theme,u=void 0===l?"light":l;return(0,r.A)(this,t),o=function(e,t,n){return t=(0,s.A)(t),(0,a.A)(e,H()?Reflect.construct(t,n||[],(0,s.A)(e).constructor):t.apply(e,n))}(this,t),o.subComponents=[],o.theme="",o.onThemeChange=function(e){"auto"===o.options.theme&&o.setTheme(e)},o.compName=c,o.c=E(c),o.options={},o.container=e,o.$container=h()(e),o.$container.addClass(["luna-".concat(c),o.c("platform-".concat((i=S()(),"os x"===i?"mac":i)))]),o.on("changeOption",(function(e,t){if("theme"===e&&t){var n=t;"auto"===t&&(n=L().get()),o.setTheme(n),j()(o.subComponents,(function(e){return e.setOption("theme",t)}))}})),L().on("change",o.onThemeChange),o.setOption("theme",u),o}return(0,c.A)(t,e),(0,i.A)(t,[{key:"destroy",value:function(){var e=this;this.destroySubComponents();var t=this.$container,n=t.attr("class");j()(n.split(/\s+/),(function(n){P()(n,"luna-".concat(e.compName))&&t.rmClass(n)})),t.html(""),this.emit("destroy"),this.removeAllListeners(),L().off("change",this.onThemeChange)}},{key:"setOption",value:function(e,t){var n=this,o=this.options,r={};"string"==typeof e?r[e]=t:r=e,j()(r,(function(e,t){var r=o[t];o[t]=e,e!==r&&n.emit("changeOption",t,e,r)}))}},{key:"getOption",value:function(e){return this.options[e]}},{key:"addSubComponent",value:function(e){e.setOption("theme",this.options.theme),this.subComponents.push(e)}},{key:"removeSubComponent",value:function(e){F()(this.subComponents,(function(t){return t===e}))}},{key:"destroySubComponents",value:function(){j()(this.subComponents,(function(e){return e.destroy()})),this.subComponents=[]}},{key:"initOptions",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};D()(e,t),I()(this.options,e)}},{key:"find",value:function(e){return this.$container.find(this.c(e))}},{key:"setTheme",value:function(e){var t=this.c,n=this.$container;this.theme&&n.rmClass(t("theme-".concat(this.theme))),n.addClass(t("theme-".concat(e))),this.theme=e}}])}(u()),q=n(5773),Q=n.n(q),U=n(5902),W=n.n(U);function J(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(J=function(){return!!e})()}e=n.hmd(e);var K=function(e){function t(e){var n,o,i,c,l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return(0,r.A)(this,t),o=this,i=t,c=[e,{compName:"tab"},l],i=(0,s.A)(i),(n=(0,a.A)(o,J()?Reflect.construct(i,c||[],(0,s.A)(o).constructor):i.apply(o,c))).initOptions(l,{height:30}),n.initTpl(),n.$tabs=n.find(".tabs"),n.tabs=n.$tabs.get(0),n.$slider=n.find(".slider"),n.bindEvent(),n.updateHeight(),n}return(0,c.A)(t,e),(0,i.A)(t,[{key:"length",get:function(){return this.$tabs.find(this.c(".item")).length}},{key:"insert",value:function(e,t){var n=this.c,o=this.$tabs,r=this.options.height-1,i=o.find(n(".item")),a=i.length,s='
    ').concat(W()(t.title),"").concat(t.closeable?'
    '):"","
    ");e>a-1?o.append(s):i.eq(e).before(s),this.updateSlider()}},{key:"append",value:function(e){this.insert(this.length,e)}},{key:"remove",value:function(e){var t=this.c;if(1!==this.length){var n=this;this.$tabs.find(t(".item")).each((function(o){var r=h()(this);if(r.data("id")===e){if(r.remove(),r.hasClass(t("selected")))if(n.length>0){var i=o===n.length?o-1:o,a=n.$tabs.find(t(".item")).eq(i).data("id");n.select(a)}else n.emit("deselect");r.data("closeable")&&n.emit("close",e)}})),this.updateSlider()}}},{key:"select",value:function(e){var t=this.c,n=this;this.$tabs.find(t(".item")).each((function(){var o=h()(this);o.data("id")===e?(o.addClass(t("selected")),n.updateSlider(),n.scrollToSelected(),n.emit("select",e)):o.rmClass(t("selected"))}))}},{key:"deselect",value:function(){var e=this.c;this.$tabs.find(e(".item")).each((function(){h()(this).rmClass(e("selected"))})),this.emit("deselect"),this.updateSlider()}},{key:"scrollToSelected",value:function(){var e,t=this.$tabs,n=this.tabs,o=this.c,r=t.find(o(".selected")).get(0),i=r.offsetLeft,a=r.offsetWidth,s=n.offsetWidth,c=n.scrollLeft;is+c&&(e=i+a-s),_()(e)&&(n.scrollLeft=e)}},{key:"hideScrollbar",value:function(){var e=this.$tabs;if("none"!==getComputedStyle(this.tabs,"::-webkit-scrollbar").display){var t=function(){if(_()(N))return N;if(!document)return 16;var e=document.createElement("div"),t=document.createElement("div");e.setAttribute("style","display: block; width: 100px; height: 100px; overflow: scroll;"),t.setAttribute("style","height: 200px"),e.appendChild(t);var n=document.body||document.documentElement;return n.appendChild(e),N=e.offsetWidth-e.clientWidth,n.removeChild(e),N}();e.css("height",this.options.height-1+t+"px")}}},{key:"updateSlider",value:function(){var e=this.$slider,t=this.$tabs,n=this.c,o=t.find(n(".selected")).get(0);o?e.css({width:o.offsetWidth,left:o.offsetLeft-t.get(0).scrollLeft}):e.css({width:0})}},{key:"updateHeight",value:function(){var e=this.options.height,t=e-1;this.find(".tabs-container").css("height",e+"px"),this.find(".item").css({height:t,lineHeight:t}),this.hideScrollbar()}},{key:"bindEvent",value:function(){var e=this,t=this.tabs,n=this.c;this.on("changeOption",(function(t){if("height"===t)e.updateHeight()}));var o=this;this.$tabs.on("wheel",(function(e){e.preventDefault(),t.scrollLeft+=e.origEvent.deltaY})).on("click",n(".item"),(function(){var e=h()(this);o.select(e.data("id"))})).on("click",n(".close"),(function(e){e.stopPropagation();var t=h()(this).parent().parent();o.remove(t.data("id"))})).on("scroll",(function(){e.updateSlider()}))}},{key:"initTpl",value:function(){this.$container.html(this.c(Q()(Y||(Y=(0,o.A)(['\n
    \n
    \n
    \n
    \n '])))))}}])}($);(function(e,t){try{e.exports=t,e.exports.default=t}catch(e){}})(e,K)},8091:function(e,t,n){var o=n(282),r=n(9100),i=n(5207);function a(e){return''+e+""}t=function(e,t){t=t||a;var n=o(e);return r(n,(function(n){e=e.replace(new RegExp(i(n),"g"),t)})),e},e.exports=t},8098:function(e,t,n){var o=n(5693),r=n(5793),i=n(3145);t=function(e,t,n){t=o(t,n);for(var a=!r(e)&&i(e),s=(a||e).length,c=0;ct.right||e.bottomt.bottom}t=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.display,o=void 0===n||n,s=t.visibility,c=void 0!==s&&s,l=t.opacity,u=void 0!==l&&l,d=t.size,h=void 0!==d&&d,f=t.viewport,p=void 0!==f&&f,v=t.overflow,g=void 0!==v&&v,m=r(e);if(o){var b=e.tagName;if("BODY"===b||"HTML"===b||"fixed"===m.position){if("none"===m.display)return!0;for(var y=e;y=y.parentElement;){if("none"===r(y).display)return!0}}else if(null===e.offsetParent)return!0}if(c&&"hidden"===m.visibility)return!0;if(u){if("0"===m.opacity)return!0;for(var A=e;A=A.parentElement;){if("0"===r(A).opacity)return!0}}var w=e.getBoundingClientRect();if(h&&(0===w.width||0===w.height))return!0;if(p)return a(w,{top:0,left:0,right:i.documentElement.clientWidth,bottom:i.documentElement.clientHeight});if(g)for(var _=e;_=_.parentElement;){var x=r(_).overflow;if("scroll"===x||"hidden"===x)if(a(w,_.getBoundingClientRect()))return!0}return!1},e.exports=t},8665:function(e,t,n){"use strict";var o,r=this&&this.__extends||(o=function(e,t){return o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},o(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}o(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var a=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.trigger=function(e,t){this.emit("message",JSON.stringify({method:e,params:t}))},t}(i(n(2263)).default);t.default=new a},8687:function(e,t,n){(t=n(6314)(!1)).push([e.id,'._container .luna-console{background:var(--background)}._container .luna-console-header{color:var(--link-color);border-bottom-color:var(--border)}._container .luna-console-nesting-level{border-right-color:var(--border)}._container .luna-console-nesting-level::before{border-bottom-color:var(--border)}._container .luna-console-log-container.luna-console-selected .luna-console-log-item{background:var(--contrast)}._container .luna-console-log-container.luna-console-selected .luna-console-log-item:not(.luna-console-error):not(.luna-console-warn){border-color:var(--border)}._container .luna-console-log-item{border-bottom-color:var(--border);color:var(--foreground)}._container .luna-console-log-item a{color:var(--link-color)!important}._container .luna-console-log-item .luna-console-icon-container .luna-console-icon{color:var(--foreground)}._container .luna-console-log-item .luna-console-icon-container .luna-console-icon-error{color:#ef3842}._container .luna-console-log-item .luna-console-icon-container .luna-console-icon-warn{color:#e8a400}._container .luna-console-log-item .luna-console-count{color:var(--select-foreground);background:var(--highlight)}._container .luna-console-log-item.luna-console-warn{color:var(--console-warn-foreground);background:var(--console-warn-background);border-color:var(--console-warn-border)}._container .luna-console-log-item.luna-console-error{background:var(--console-error-background);color:var(--console-error-foreground);border-color:var(--console-error-border)}._container .luna-console-log-item.luna-console-error .luna-console-count{background:var(--console-error-foreground)}._container .luna-console-log-item .luna-console-code .luna-console-key{color:var(--var-color)}._container .luna-console-log-item .luna-console-code .luna-console-number{color:var(--number-color)}._container .luna-console-log-item .luna-console-code .luna-console-null{color:var(--operator-color)}._container .luna-console-log-item .luna-console-code .luna-console-string{color:var(--string-color)}._container .luna-console-log-item .luna-console-code .luna-console-boolean{color:var(--keyword-color)}._container .luna-console-log-item .luna-console-code .luna-console-special{color:var(--operator-color)}._container .luna-console-log-item .luna-console-code .luna-console-keyword{color:var(--keyword-color)}._container .luna-console-log-item .luna-console-code .luna-console-operator{color:var(--operator-color)}._container .luna-console-log-item .luna-console-code .luna-console-comment{color:var(--comment-color)}._container .luna-console-log-item .luna-console-log-content .luna-console-null,._container .luna-console-log-item .luna-console-log-content .luna-console-undefined{color:var(--operator-color)}._container .luna-console-log-item .luna-console-log-content .luna-console-number{color:var(--number-color)}._container .luna-console-log-item .luna-console-log-content .luna-console-boolean{color:var(--keyword-color)}._container .luna-console-log-item .luna-console-log-content .luna-console-regexp,._container .luna-console-log-item .luna-console-log-content .luna-console-symbol{color:var(--var-color)}._container .luna-console-preview .luna-console-key{color:var(--var-color)}._container .luna-console-preview .luna-console-number{color:var(--number-color)}._container .luna-console-preview .luna-console-null{color:var(--operator-color)}._container .luna-console-preview .luna-console-string{color:var(--string-color)}._container .luna-console-preview .luna-console-boolean{color:var(--keyword-color)}._container .luna-console-preview .luna-console-special{color:var(--operator-color)}._container .luna-console-preview .luna-console-keyword{color:var(--keyword-color)}._container .luna-console-preview .luna-console-operator{color:var(--operator-color)}._container .luna-console-preview .luna-console-comment{color:var(--comment-color)}._container .luna-object-viewer{color:var(--primary);font-size:12px!important}._container .luna-object-viewer-null{color:var(--operator-color)}._container .luna-object-viewer-regexp,._container .luna-object-viewer-string{color:var(--string-color)}._container .luna-object-viewer-number{color:var(--number-color)}._container .luna-object-viewer-boolean{color:var(--keyword-color)}._container .luna-object-viewer-special{color:var(--operator-color)}._container .luna-object-viewer-key,._container .luna-object-viewer-key-lighter{color:var(--var-color)}._container .luna-object-viewer-expanded:before{border-color:transparent;border-top-color:var(--foreground)}._container .luna-object-viewer-collapsed:before{border-top-color:transparent;border-left-color:var(--foreground)}._container .luna-notification{pointer-events:none!important;padding:10px;z-index:1000}._container .luna-notification-item{z-index:500;color:var(--foreground);background:var(--background);box-shadow:none;padding:5px 10px;border:1px solid var(--border)}._container .luna-notification-upper{margin-bottom:10px}._container .luna-notification-lower{margin-top:10px}._container .luna-data-grid{color:var(--foreground);background:var(--background);border-color:var(--border)}._container .luna-data-grid td,._container .luna-data-grid th{border-color:var(--border)}._container .luna-data-grid th{background:var(--darker-background)}._container .luna-data-grid th.luna-data-grid-sortable:active,._container .luna-data-grid th.luna-data-grid-sortable:hover{color:var(--select-foreground);background:var(--highlight)}._container .luna-data-grid .luna-data-grid-data-container .luna-data-grid-node.luna-data-grid-selectable:hover,._container .luna-data-grid .luna-data-grid-data-container .luna-data-grid-node.luna-data-grid-selected{background:var(--highlight)}._container .luna-data-grid .luna-data-grid-data-container tr:nth-child(even){background:var(--contrast)}._container .luna-data-grid:focus .luna-data-grid-data-container .luna-data-grid-node.luna-data-grid-selected{background:var(--accent)}._container .luna-dom-viewer{color:var(--foreground)}._container .luna-dom-viewer .luna-dom-viewer-html-tag,._container .luna-dom-viewer .luna-dom-viewer-tag-name{color:var(--tag-name-color)}._container .luna-dom-viewer .luna-dom-viewer-attribute-name{color:var(--attribute-name-color)}._container .luna-dom-viewer .luna-dom-viewer-attribute-value{color:var(--string-color)}._container .luna-dom-viewer .luna-dom-viewer-html-comment{color:var(--comment-color)}._container .luna-dom-viewer .luna-dom-viewer-tree-item:hover .luna-dom-viewer-selection{background:var(--contrast)}._container .luna-dom-viewer .luna-dom-viewer-tree-item.luna-dom-viewer-selected .luna-dom-viewer-selection{background:var(--highlight)}._container .luna-dom-viewer .luna-dom-viewer-tree-item.luna-dom-viewer-selected:focus .luna-dom-viewer-selection{background:var(--accent);opacity:.2}._container .luna-dom-viewer .luna-dom-viewer-text-node .luna-dom-viewer-key{color:var(--var-color)}._container .luna-dom-viewer .luna-dom-viewer-text-node .luna-dom-viewer-number{color:var(--number-color)}._container .luna-dom-viewer .luna-dom-viewer-text-node .luna-dom-viewer-null{color:var(--operator-color)}._container .luna-dom-viewer .luna-dom-viewer-text-node .luna-dom-viewer-string{color:var(--string-color)}._container .luna-dom-viewer .luna-dom-viewer-text-node .luna-dom-viewer-boolean{color:var(--keyword-color)}._container .luna-dom-viewer .luna-dom-viewer-text-node .luna-dom-viewer-special{color:var(--operator-color)}._container .luna-dom-viewer .luna-dom-viewer-text-node .luna-dom-viewer-keyword{color:var(--keyword-color)}._container .luna-dom-viewer .luna-dom-viewer-text-node .luna-dom-viewer-operator{color:var(--operator-color)}._container .luna-dom-viewer .luna-dom-viewer-text-node .luna-dom-viewer-comment{color:var(--comment-color)}._container .luna-dom-viewer-children{margin:0;padding-left:15px!important}._container ._inline .luna-modal,._container ._inline .luna-notification{position:absolute}._container .luna-modal{z-index:9999999}._container .luna-modal-body,._container .luna-modal-input{color:var(--foreground);background:var(--background)}._container .luna-modal-body{border-color:var(--border)}._container .luna-modal-input{-webkit-user-select:text!important;-moz-user-select:text!important;-ms-user-select:text!important;user-select:text!important;border-color:var(--border)}._container .luna-modal-button-group .luna-modal-secondary{border-color:var(--border);color:var(--foreground);background:var(--background)}._container .luna-modal-button-group .luna-modal-primary{background:var(--accent)}._container .luna-modal-button-group .luna-modal-button:active::before{background:var(--accent)}._container .luna-tab{position:absolute;left:0;top:0;color:var(--foreground);background:var(--darker-background)}._container .luna-tab-tabs-container{border-color:var(--border)}._container .luna-tab-item.luna-tab-selected,._container .luna-tab-item:hover{background:var(--highlight);color:var(--select-foreground)}._container .luna-tab-slider{background:var(--accent)}._container .luna-text-viewer{color:var(--foreground);border:none;border-bottom:1px solid var(--border);background:var(--background);font-size:12px}._container .luna-text-viewer .luna-text-viewer-line-text{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}._container .luna-text-viewer .luna-text-viewer-line-text *{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}._container .luna-text-viewer .luna-text-viewer-copy,._container .luna-text-viewer .luna-text-viewer-line-number{border-color:var(--border)}._container .luna-text-viewer .luna-text-viewer-copy .luna-text-viewer-icon-check{color:var(--accent)}._container .luna-text-viewer .luna-text-viewer-copy{background-color:var(--background)}._container .luna-setting{color:var(--foreground);background:var(--background)}._container .luna-setting-item.luna-setting-selected,._container .luna-setting-item:hover{background:var(--darker-background)}._container .luna-setting-item.luna-setting-selected:focus{outline:0}._container .luna-setting-item-title{font-size:14px}._container .luna-setting-item-separator{border-color:var(--border)}._container .luna-setting-item-checkbox input{border-color:var(--border)}._container .luna-setting-item-checkbox input:checked{background-color:var(--accent);border-color:var(--accent)}._container .luna-setting-item-select .luna-setting-select select{color:var(--foreground);border-color:var(--border);background:var(--background)}._container .luna-setting-item-select .luna-setting-select:after{border-top-color:var(--foreground)}._container .luna-setting-item-button button{color:var(--accent);background:var(--background);border-color:var(--border)}._container .luna-setting-item-button button:active,._container .luna-setting-item-button button:hover{background:var(--darker-background)}._container .luna-setting-item-button button:active{border:1px solid var(--accent)}._container .luna-setting-item-number .luna-setting-range-container .luna-setting-range-track .luna-setting-range-track-bar{background:var(--border)}._container .luna-setting-item-number .luna-setting-range-container .luna-setting-range-track .luna-setting-range-track-bar .luna-setting-range-track-progress{background:var(--accent)}._container .luna-setting-item-number .luna-setting-range-container input::-webkit-slider-thumb{border-color:var(--border);background:radial-gradient(circle at center,var(--dark) 0,var(--dark) 15%,var(--light) 22%,var(--light) 100%)}._container .luna-box-model{background:var(--background)}._container .luna-box-model-border,._container .luna-box-model-content,._container .luna-box-model-margin,._container .luna-box-model-padding,._container .luna-box-model-position{color:var(--foreground);background:var(--background)}._container{min-width:320px;pointer-events:none;position:fixed;left:0;top:0;width:100%;height:100%;z-index:9999999;color:var(--foreground);font-family:-apple-system,system-ui,BlinkMacSystemFont,".SFNSDisplay-Regular","Helvetica Neue","Lucida Grande","Segoe UI",Tahoma,sans-serif;font-size:14px;direction:ltr}._container._dark{color-scheme:dark}._container *{box-sizing:border-box;pointer-events:all;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:none}._container ul{list-style:none;padding:0;margin:0}._container h1,._container h2,._container h3,._container h4{margin:0}._container h2{font-size:14px}._container h2 [class*=" _icon-"],._container h2 [class^=icon-]{font-weight:400}._container._inline{position:static}._hidden{display:none}._icon-disabled{opacity:.5;pointer-events:none;cursor:default!important}._icon-disabled:active{color:inherit!important}._tag-name-color{color:var(--tag-name-color)}._function-color{color:var(--function-color)}._attribute-name-color{color:var(--attribute-name-color)}._operator-color{color:var(--operator-color)}._string-color{color:var(--string-color)}',""]),e.exports=t},8734:function(e,t,n){var o=n(2717),r=n(1738),i=n(6026),a=n(8),s=n(928),c=n(9848);t=o({initialize:function(e){r(e)&&(e=t.parse(e)),this.model=e.model,this.val=e.val},toRgb:function(){var e=this.val;"hsl"===this.model&&(e=s(e));var t="rgba";return 1===e[3]&&(t="rgb",e=e.slice(0,3)),t+"("+e.join(", ")+")"},toHex:function(){var e=this.val;"hsl"===this.model&&(e=s(e));var t=c.encode(e.slice(0,3));return t[0]===t[1]&&t[2]===t[3]&&t[4]===t[5]&&(t=t[0]+t[2]+t[5]),"#"+t},toHsl:function(){var e=this.val;"rgb"===this.model&&(e=a(e));var t="hsla";return 1===e[3]&&(t="hsl",e=e.slice(0,3)),e[1]=e[1]+"%",e[2]=e[2]+"%",t+"("+e.join(", ")+")"}},{parse:function(e){var t,n,o=[0,0,0,1],r="rgb";if(n=e.match(l))for(n=n[1],t=0;t<3;t++)o[t]=parseInt(n[t]+n[t],16);else if(n=e.match(u))for(n=n[1],t=0;t<3;t++){var a=2*t;o[t]=parseInt(n.slice(a,a+2),16)}else if(n=e.match(d)){for(t=0;t<3;t++)o[t]=parseInt(n[t+1],0);n[4]&&(o[3]=parseFloat(n[4]))}else if(n=e.match(h)){for(t=0;t<3;t++)o[t]=Math.round(2.55*parseFloat(n[t+1]));n[4]&&(o[3]=parseFloat(n[4]))}else(n=e.match(f))&&(r="hsl",o=[(parseFloat(n[1])%360+360)%360,i(parseFloat(n[2]),0,100),i(parseFloat(n[3]),0,100),i(parseFloat(n[4]),0,1)]);return{val:o,model:r}}});var l=/^#([a-fA-F0-9]{3})$/,u=/^#([a-fA-F0-9]{6})$/,d=/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/,h=/^rgba?\(\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/,f=/^hsla?\(\s*([+-]?\d*[.]?\d+)(?:deg)?\s*,\s*([+-]?[\d.]+)%\s*,\s*([+-]?[\d.]+)%\s*(?:,\s*([+-]?[\d.]+)\s*)?\)$/;e.exports=t},8757:function(e,t,n){"use strict";var o,r=this&&this.__extends||(o=function(e,t){return o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},o(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}o(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var a=i(n(2263)),s=i(n(9100)),c=function(e){function t(){var t=e.call(this)||this;return t.observer=new MutationObserver((function(e){(0,s.default)(e,(function(e){return t.handleMutation(e)}))})),t}return r(t,e),t.prototype.observe=function(e){this.observer.observe(e,{attributes:!0,childList:!0,characterData:!0,subtree:!0})},t.prototype.disconnect=function(){this.observer.disconnect()},t.prototype.handleMutation=function(e){"attributes"===e.type?this.emit("attributes",e.target,e.attributeName):"childList"===e.type?this.emit("childList",e.target,e.addedNodes,e.removedNodes):"characterData"===e.type&&this.emit("characterData",e.target)},t}(a.default);t.default=new c},8785:function(e,t){t=function(){for(var e=arguments,t=e[0],n=1,o=e.length;n0&&(n+="["+o+"]"),new i(n,e.nodeType===Node.DOCUMENT_NODE)}t=function(e,t){return o(e)?function(e){for(var t=[],n=document.evaluate(e,document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null),o=0;o1&&void 0!==arguments[1]&&arguments[1];if(e.nodeType===Node.DOCUMENT_NODE)return"/";var n=[],o=e;for(;o;){var i=r(o,t);if(!i)break;if(n.push(i),i.optimized)break;o=o.parentNode}return n.reverse(),(n.length&&n[0].optimized?"":"/")+n.join("/")}(e,t)};var i=n(2717)({initialize:function(e,t){this.value=e,this.optimized=t||!1},toString:function(){return this.value}});e.exports=t},8966:function(e,t,n){var o=n(2717),r=n(3249);function i(){return!0}function a(){return!1}function s(e){var n,o=this.events[e.type],r=c.call(this,e,o);e=new t.Event(e);for(var i,a,s=0;(a=r[s++])&&!e.isPropagationStopped();)for(e.curTarget=a.el,i=0;(n=a.handlers[i++])&&!e.isImmediatePropagationStopped();)!1===n.handler.apply(a.el,[e])&&(e.preventDefault(),e.stopPropagation())}function c(e,t){var n,o,i,a,s=e.target,c=[],l=t.delegateCount;if(s.nodeType)for(;s!==this;s=s.parentNode||this){for(o=[],a=0;a=i[a[l]]){c=a[l];break}return+(n/i[c]).toFixed(2)+c};var i={ms:1,s:1e3};i.m=60*i.s,i.h=60*i.m,i.d=24*i.h,i.y=365.25*i.d;var a=["y","d","h","m","s"],s=/^((?:\d+)?\.?\d+) *(s|m|h|d|y)?$/;e.exports=t},9122:function(e,t,n){var o=n(9760),r=n(3957),i=n(1168);t=function(e){return!!o(e)&&(r(e)?s.test(i(e)):c.test(i(e)))};var a=Object.prototype.hasOwnProperty,s=new RegExp("^"+i(a).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),c=/^\[object .+?Constructor\]$/;e.exports=t},9186:function(e,t,n){var o=n(769),r=n(9760),i=n(1738),a=n(9100),s=n(8971),c=n(3612);(t=function(e,t,n){if(e=c(e),s(n)&&i(t))return function(e,t){return e.getAttribute(t)}(e[0],t);var o=t;r(o)||((o={})[t]=n),function(e,t){a(e,(function(e){a(t,(function(t,n){e.setAttribute(n,t)}))}))}(e,o)}).remove=function(e,t){e=c(e),t=o(t),a(e,(function(e){a(t,(function(t){e.removeAttribute(t)}))}))},e.exports=t},9196:function(e,t,n){"use strict";var o,r=this&&this.__extends||(o=function(e,t){return o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},o(e,t)},function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}o(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),i=this&&this.__assign||function(){return i=Object.assign||function(e){for(var t,n=1,o=arguments.length;n=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")},s=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0});var c=s(n(7214)),l=n(926),u=n(4725),d=s(n(4095)),h=s(n(5865)),f=s(n(96)),p=s(n(9100)),v=s(n(8734)),g=s(n(9848)),m=s(n(3805)),b=s(n(8105)),y=s(n(387)),A=s(n(3249)),w=s(n(6030)),_=s(n(3019)),x=s(n(1738));n(3270);var k=function(e){function t(t,n){void 0===n&&(n={});var o=e.call(this,t,{compName:"dom-highlighter"},n)||this;return o.overlay=new l.HighlightOverlay(window),o.reset=function(){var e=document.documentElement.clientWidth,t=document.documentElement.clientHeight;o.overlay.reset({viewportSize:{width:e,height:t},deviceScaleFactor:1,pageScaleFactor:1,pageZoomFactor:1,emulationScaleFactor:1,scrollX:window.scrollX,scrollY:window.scrollY})},o.initOptions(n,{showRulers:!1,showExtensionLines:!1,showInfo:!0,showStyles:!0,showAccessibilityInfo:!0,colorFormat:"hex",contentColor:"rgba(111, 168, 220, .66)",paddingColor:"rgba(147, 196, 125, .55)",borderColor:"rgba(255, 229, 153, .66)",marginColor:"rgba(246, 178, 107, .66)",monitorResize:!0}),o.overlay.setContainer(t),o.overlay.setPlatform("mac"),o.redraw=(0,h.default)((function(){o.reset(),o.draw()}),16),o.redraw(),o.bindEvent(),o}return r(t,e),t.prototype.highlight=function(e,t){t&&(0,b.default)(this.options,t),this.target=e,e instanceof HTMLElement&&this.options.monitorResize&&(this.resizeSensor&&this.resizeSensor.destroy(),this.resizeSensor=new d.default(e),this.resizeSensor.addListener(this.redraw)),this.redraw()},t.prototype.hide=function(){this.target=null,this.redraw()},t.prototype.intercept=function(e){this.interceptor=e},t.prototype.destroy=function(){window.removeEventListener("resize",this.redraw),window.removeEventListener("scroll",this.redraw),this.resizeSensor&&this.resizeSensor.destroy(),e.prototype.destroy.call(this)},t.prototype.draw=function(){var e=this.target;e&&(e instanceof Text?this.drawText(e):this.drawElement(e))},t.prototype.drawText=function(e){var t=this.options,n=document.createRange();n.selectNode(e);var o=n.getBoundingClientRect(),r=o.left,i=o.top,a=o.width,s=o.height;n.detach();var c={paths:[{path:this.rectToPath({left:r,top:i,width:a,height:s}),fillColor:E(t.contentColor),name:"content"}],showExtensionLines:t.showExtensionLines,showRulers:t.showRulers};t.showInfo&&(c.elementInfo={tagName:"#text",nodeWidth:a,nodeHeight:s}),this.overlay.drawHighlight(c)},t.prototype.drawElement=function(e){var t={paths:this.getPaths(e),showExtensionLines:this.options.showExtensionLines,showRulers:this.options.showRulers,colorFormat:this.options.colorFormat};if(this.options.showInfo&&(t.elementInfo=this.getElementInfo(e)),this.interceptor){var n=this.interceptor(t);n&&(t=n)}this.overlay.drawHighlight(t)},t.prototype.getPaths=function(e){var t=this.options,n=window.getComputedStyle(e),o=e.getBoundingClientRect(),r=o.left,i=o.top,a=o.width,s=o.height,c=function(e){return(0,u.pxToNum)(n.getPropertyValue(e))},l=c("margin-left"),d=c("margin-right"),h=c("margin-top"),f=c("margin-bottom"),p=c("border-left-width"),v=c("border-right-width"),g=c("border-top-width"),m=c("border-bottom-width"),b=c("padding-left"),y=c("padding-right"),A=c("padding-top"),w=c("padding-bottom");return[{path:this.rectToPath({left:r+p+b,top:i+g+A,width:a-p-b-v-y,height:s-g-A-m-w}),fillColor:E(t.contentColor),name:"content"},{path:this.rectToPath({left:r+p,top:i+g,width:a-p-v,height:s-g-m}),fillColor:E(t.paddingColor),name:"padding"},{path:this.rectToPath({left:r,top:i,width:a,height:s}),fillColor:E(t.borderColor),name:"border"},{path:this.rectToPath({left:r-l,top:i-h,width:a+l+d,height:s+h+f}),fillColor:E(t.marginColor),name:"margin"}]},t.prototype.getElementInfo=function(e){var t=e.getBoundingClientRect(),n=t.width,o=t.height,r=e.getAttribute("class")||"";r=r.split(/\s+/).map((function(e){return"."+e})).join("");var i={tagName:(0,f.default)(e.tagName),className:r,idValue:e.id,nodeWidth:n,nodeHeight:o};return this.options.showStyles&&(i.style=this.getStyles(e)),this.options.showAccessibilityInfo&&(0,b.default)(i,this.getAccessibilityInfo(e)),i},t.prototype.getStyles=function(e){for(var t=window.getComputedStyle(e),n=!1,o=e.childNodes,r=0,i=o.length;r-1)},t.prototype.getAccessibleNameAndRole=function(e){var t=e.getAttribute("labelledby")||e.getAttribute("aria-label"),n=e.getAttribute("role"),o=(0,f.default)(e.tagName);return _.default.forEach((function(t){var r,i;if(!n){var s=t[0],c=t[2];if(s===o){if(c)try{for(var l=a(c),u=l.next();!u.done;u=l.next()){var d=u.value;if(e.getAttribute(d[0])!==d[1])return}}catch(e){r={error:e}}finally{try{u&&!u.done&&(i=l.return)&&i.call(l)}finally{if(r)throw r.error}}n=t[1]}}})),{accessibleName:t||e.getAttribute("title")||"",accessibleRole:n||"generic"}},t.prototype.bindEvent=function(){var e=this;window.addEventListener("resize",this.redraw),window.addEventListener("scroll",this.redraw),this.on("optionChange",(function(){return e.redraw()}))},t.prototype.rectToPath=function(e){var t=e.left,n=e.top,o=e.width,r=e.height,i=[];return i.push("M",t,n),i.push("L",t+o,n),i.push("L",t+o,n+r),i.push("L",t,n+r),i.push("Z"),i},t}(c.default);t.default=k,e.exports=k,e.exports.default=k;var C=/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,S=/^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d*(?:\.\d+)?)\)$/;function E(e){return(0,x.default)(e)?e:e.a?"rgba(".concat(e.r,", ").concat(e.g,", ").concat(e.b,", ").concat(e.a,")"):"rgb(".concat(e.r,", ").concat(e.g,", ").concat(e.b,")")}function T(e,t,n){void 0===n&&(n=!1);var o={};return(0,p.default)(t,(function(t){var r,i=e["text-opacity"===t?"color":t];i&&(r=i,(C.test(r)||S.test(r))&&(i=function(e){var t=v.default.parse(e),n=t.val[3]||1;return t.val=t.val.slice(0,3),t.val.push(Math.round(255*n)),"#"+(0,m.default)(g.default.encode(t.val))}(i),"text-opacity"===t&&(i=i.slice(7),i=g.default.decode(i)[0]/255)),n&&(t=(0,y.default)(t)),o[t]=i)})),o}},9350:function(e,t){t=function(e){return"symbol"==typeof e},e.exports=t},9389:function(e,t,n){var o=n(5902),r=n(3145);t=function(e){return s.test(e)?e.replace(c,l):e};var i=n(5282)(o.map),a="(?:"+r(i).join("|")+")",s=new RegExp(a),c=new RegExp(a,"g");function l(e){return i[e]}e.exports=t},9405:function(e,t,n){var o=n(5333),r=n(9651);t=function(e,t){return null==t&&e.trim?e.trim():o(r(e,t),t)},e.exports=t},9410:function(e,t,n){var o=n(9993);t=function(e,t){t=t||o;var n=new Image;n.onload=function(){t(null,n)},n.onerror=function(e){t(e)},n.src=e},e.exports=t},9464:function(e,t,n){var o=n(5793),r=n(6214),i=n(1738),a=n(5132),s=n(3145);t=function(e){return null==e||(o(e)&&(r(e)||i(e)||a(e))?0===e.length:0===s(e).length)},e.exports=t},9548:function(e,t,n){var o=n(383),r=n(7005),i=n(6214),a=n(9100),s=n(1738),c=n(5154);var l=function(e){return e.replace(/"/g,'"')},u=function(e){return e.replace(/"/g,""")};t={parse:function(e){var t=[],n=new r;return o(e,{start:function(e,t){t=c(t,(function(e){return l(e)})),n.push({tag:e,attrs:t})},end:function(){var e=n.pop();if(n.size){var o=n.peek();i(o.content)||(o.content=[]),o.content.push(e)}else t.push(e)},comment:function(e){var o="\x3c!--".concat(e,"--\x3e"),r=n.peek();r?(r.content||(r.content=[]),r.content.push(o)):t.push(o)},text:function(e){var o=n.peek();o?(o.content||(o.content=[]),o.content.push(e)):t.push(e)}}),t},stringify:function e(t){var n="";return i(t)?a(t,(function(t){return n+=e(t)})):s(t)?n=t:(n+="<".concat(t.tag),a(t.attrs,(function(e,t){return n+=" ".concat(t,'="').concat(u(e),'"')})),n+=">",t.content&&(n+=e(t.content)),n+="")),n}},e.exports=t},9651:function(e,t){t=function(e,t){if(null==t){if(e.trimRight)return e.trimRight();t=" \r\n\t\f\v"}for(var n,o,r=e.length-1,i=t.length,a=!0;a&&r>=0;)for(a=!1,n=-1,o=e.charAt(r);++n=0?e.substring(0,r+1):""},e.exports=t},9756:function(e,t){t=function(e){for(var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:t.defComparator,o=0,r=e.length;o0)return!1;return!0},t.defComparator=function(e,t){return et?1:0},e.exports=t},9760:function(e,t){t=function(e){var t=typeof e;return!!e&&("function"===t||"object"===t)},e.exports=t},9848:function(e,t,n){var o=n(6024);t={encode:function(e){for(var t=[],n=0,o=e.length;n>>4).toString(16)),t.push((15&r).toString(16))}return t.join("")},decode:function(e){var t=[],n=e.length;o(n)&&n--;for(var r=0;r0||u)&&(i.children=g(e,o)),i}function g(e,t){var n=m(e.childNodes);return(0,r.default)(n,(function(e){return v(e,{depth:t-1})}))}function m(e){return i.default(e,(function(e){return b(e)}))}function b(e){if(1===e.nodeType){var t=e.getAttribute("class")||"";if((0,c.default)(t,"__chobitsu-hide__")||(0,c.default)(t,"html2canvas-container"))return!1}var n=!(3===e.nodeType&&""===(0,s.default)(e.nodeValue||""));return n&&e.parentNode?b(e.parentNode):n}},9907:function(e,t,n){(t=n(6314)(!1)).push([e.id,"@font-face{font-family:luna-object-viewer-icon;src:url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAS8AAsAAAAAB7QAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAAGEAAACMISgl+k9TLzIAAAFsAAAAPQAAAFZLxUkWY21hcAAAAawAAADWAAACdBU42qdnbHlmAAAChAAAAC4AAAAwabU7V2hlYWQAAAK0AAAALwAAADZzjr4faGhlYQAAAuQAAAAYAAAAJAFyANlobXR4AAAC/AAAABAAAABAAZAAAGxvY2EAAAMMAAAAEAAAACIAtACobWF4cAAAAxwAAAAfAAAAIAEbAA9uYW1lAAADPAAAASkAAAIWm5e+CnBvc3QAAARoAAAAUwAAAHZW8MNZeJxNjTsOQFAQRc/z/+sV1mABohKV0gZeJRJR2X9cT4RJZu7nFIMBMjoGvHGaF6rdngcNAc/c/O/Nvq2W5E1igdNE2zv1iGh1c5FQPlYXUlJRyxt9+/pUKadQa/AveGEGZQAAAHicY2BkkGScwMDKwMBQx9ADJGWgdAIDJ4MxAwMTAyszA1YQkOaawnCAQfcjE8MJIFcITDIwMIIIAFqDCGkAAAB4nM2STQ4BQRCFv54ZP8MwFhYW4gQcShBsSERi50BWDuFCcwJedddKRGKnOt8k9aanqudVAy0gF3NRQLgTsLhJDVHP6UW94Kp8zEhKwYIlG/YcOXHm0mTPp96aumLLwdUQ1fcIqmJrwpSZL+iqak5JmyE1Ayr1bdGhr/2ZPmp/qPQtuj/uJzqQl+pfDyypesQD6AT/ElV8PjyrMccT9rdLR3PUFBI227VTio1jbm6dodg5VnPvmAsHxzofHfmi+Sbs/pwdWcXFkWdNSNg9arIE2QufuSCyAAB4nGNgZACBlQzTGZgYGMyVxVc2O073AIpAxHsYloHFRc2dPZY2OTIwAACmEQesAAB4nGNgZGBgAOINe2b6x/PbfGXgZjgBFIjifLyvAUEDwUqGZUCSg4EJxAEAUn4LLAB4nGNgZGBgOMHAACdXMjAyoAIBADizAkx4nGNgAIITUEwGAABZUAGReJxjYAACHgYJ3BAAE94BXXicY2BkYGAQYGBmANEMDExAzAWEDAz/wXwGAApcASsAeJxlkD1uwkAUhMdgSAJSghQpKbNVCiKZn5IDQE9Bl8KYtTGyvdZ6QaLLCXKEHCGniHKCHChj82hgLT9/M2/e7soABviFh3p5uG1qvVq4oTpxm/Qg7JOfhTvo40W4S38o3MMbpsJ9POKdO3j+HZ0BSuEW7vEh3Kb/KeyTv4Q7eMK3cJf+j3APK/wJ9/HqDdPIFLEp3FIn+yy0Z3n+rrStUlOoSTA+WwtdaBs6vVHro6oOydS5WMXW5GrOrs4yo0prdjpywda5cjYaxeIHkcmRIoJBgbipDktoJNgjQwh71b3UK6YtKvq1VpggwPgqtWCqaJIhlcaGyTWOrBUOPG1K1zGt+FrO5KS5zGreJCMr/u+6t6MT0Q+wbaZKzDDiE1/kg+YO+T89EV6oAAAAeJxdxjkOgCAUANE/uOOGB+FQBIjaaEJIuL6FsfE1M6Lk9fXPoKioaWjp6BnQjEzMLKwYNtHepZhtuMs1vpvO/ch4HIlIxhK4KVyc7BwiD8nvDlkA') format('woff')}[class*=' luna-object-viewer-icon-'],[class^=luna-object-viewer-icon-]{display:inline-block;font-family:luna-object-viewer-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.luna-object-viewer-icon-caret-down:before{content:'\\f101'}.luna-object-viewer-icon-caret-right:before{content:'\\f102'}.luna-object-viewer{overflow-x:auto;-webkit-overflow-scrolling:touch;overflow-y:hidden;cursor:default;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:12px;line-height:1.2;min-height:100%;color:#333;list-style:none!important}.luna-object-viewer ul{list-style:none!important;padding:0!important;padding-left:12px!important;margin:0!important}.luna-object-viewer li{position:relative;white-space:nowrap;line-height:16px;min-height:16px}.luna-object-viewer>li>.luna-object-viewer-key{display:none}.luna-object-viewer span{position:static!important}.luna-object-viewer li .luna-object-viewer-collapsed~.luna-object-viewer-close:before{color:#999}.luna-object-viewer-array .luna-object-viewer-object .luna-object-viewer-key{display:inline}.luna-object-viewer-null{color:#5e5e5e}.luna-object-viewer-regexp,.luna-object-viewer-string{color:#c41a16}.luna-object-viewer-number{color:#1c00cf}.luna-object-viewer-boolean{color:#0d22aa}.luna-object-viewer-special{color:#5e5e5e}.luna-object-viewer-key,.luna-object-viewer-key-lighter{color:#881391}.luna-object-viewer-key-lighter{opacity:.6}.luna-object-viewer-key-special{color:#5e5e5e}.luna-object-viewer-collapsed .luna-object-viewer-icon,.luna-object-viewer-expanded .luna-object-viewer-icon{position:absolute!important;left:-12px;color:#727272;font-size:12px}.luna-object-viewer-icon-caret-right{top:0}.luna-object-viewer-icon-caret-down{top:1px}.luna-object-viewer-expanded>.luna-object-viewer-icon-caret-down{display:inline}.luna-object-viewer-expanded>.luna-object-viewer-icon-caret-right{display:none}.luna-object-viewer-collapsed>.luna-object-viewer-icon-caret-down{display:none}.luna-object-viewer-collapsed>.luna-object-viewer-icon-caret-right{display:inline}.luna-object-viewer-hidden~ul{display:none}.luna-object-viewer-theme-dark{color:#fff}.luna-object-viewer-theme-dark .luna-object-viewer-null,.luna-object-viewer-theme-dark .luna-object-viewer-special{color:#a1a1a1}.luna-object-viewer-theme-dark .luna-object-viewer-regexp,.luna-object-viewer-theme-dark .luna-object-viewer-string{color:#f28b54}.luna-object-viewer-theme-dark .luna-object-viewer-boolean,.luna-object-viewer-theme-dark .luna-object-viewer-number{color:#9980ff}.luna-object-viewer-theme-dark .luna-object-viewer-key,.luna-object-viewer-theme-dark .luna-object-viewer-key-lighter{color:#5db0d7}",""]),e.exports=t},9931:function(e,t){t=function(e){return e.length<1?e:e[0].toUpperCase()+e.slice(1)},e.exports=t},9993:function(e,t){t=function(){},e.exports=t}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return __webpack_require__.d(t,{a:t}),t},__webpack_require__.d=function(e,t){for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=function(e){return(e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e},__webpack_require__.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},__webpack_require__.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var __webpack_exports__=__webpack_require__(2980);return __webpack_exports__}()})); +//# sourceMappingURL=eruda.js.map \ No newline at end of file diff --git a/manager/app/src/main/cpp/jni.cc b/manager/app/src/main/cpp/jni.cc index ccd93408f66e..30134cc35e13 100644 --- a/manager/app/src/main/cpp/jni.cc +++ b/manager/app/src/main/cpp/jni.cc @@ -330,6 +330,17 @@ Java_me_weishu_kernelsu_Natives_setKernelUmountEnabled(JNIEnv *env, jobject thiz return set_kernel_umount_enabled(enabled); } +extern "C" +JNIEXPORT jboolean JNICALL +Java_me_weishu_kernelsu_Natives_isAvcSpoofEnabled(JNIEnv *env, jobject thiz) { + return is_avc_spoof_enabled(); +} +extern "C" +JNIEXPORT jboolean JNICALL +Java_me_weishu_kernelsu_Natives_setAvcSpoofEnabled(JNIEnv *env, jobject thiz, jboolean enabled) { + return set_avc_spoof_enabled(enabled); +} + extern "C" JNIEXPORT jstring JNICALL Java_me_weishu_kernelsu_Natives_getUserName(JNIEnv *env, jobject thiz, jint uid) { diff --git a/manager/app/src/main/cpp/ksu.cc b/manager/app/src/main/cpp/ksu.cc index 07af7951cc10..03195bf669e9 100644 --- a/manager/app/src/main/cpp/ksu.cc +++ b/manager/app/src/main/cpp/ksu.cc @@ -169,6 +169,25 @@ bool is_su_enabled() { return cmd.value != 0; } +bool set_avc_spoof_enabled(bool enabled) { + struct ksu_set_feature_cmd cmd = {}; + cmd.feature_id = KSU_FEATURE_AVC_SPOOF; + cmd.value = enabled ? 1 : 0; + return ksuctl(KSU_IOCTL_SET_FEATURE, &cmd) == 0; +} + +bool is_avc_spoof_enabled() { + struct ksu_get_feature_cmd cmd = {}; + cmd.feature_id = KSU_FEATURE_AVC_SPOOF; + if (ksuctl(KSU_IOCTL_GET_FEATURE, &cmd) != 0) { + return false; + } + if (!cmd.supported) { + return false; + } + return cmd.value != 0; +} + static inline bool get_feature(uint32_t feature_id, uint64_t *out_value, bool *out_supported) { struct ksu_get_feature_cmd cmd = {}; cmd.feature_id = feature_id; diff --git a/manager/app/src/main/cpp/ksu.h b/manager/app/src/main/cpp/ksu.h index 09892762c5da..14ad4af18b54 100644 --- a/manager/app/src/main/cpp/ksu.h +++ b/manager/app/src/main/cpp/ksu.h @@ -42,6 +42,11 @@ bool set_kernel_umount_enabled(bool enabled); bool is_kernel_umount_enabled(); +// Avc spoof +bool set_avc_spoof_enabled(bool enabled); + +bool is_avc_spoof_enabled(); + bool get_allow_list(struct ksu_new_get_allow_list_cmd *); inline std::pair legacy_get_info() { diff --git a/manager/app/src/main/java/me/weishu/kernelsu/KernelSUApplication.kt b/manager/app/src/main/java/me/weishu/kernelsu/KernelSUApplication.kt index b10f96d2eaeb..e897c4ec4c81 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/KernelSUApplication.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/KernelSUApplication.kt @@ -46,7 +46,7 @@ class KernelSUApplication : Application(), ViewModelStoreOwner { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { val prefs = this.getSharedPreferences("settings", MODE_PRIVATE) - val enable = prefs.getBoolean("enable_predictive_back", false) + val enable = prefs.getBoolean("enable_predictive_back", true) HiddenApiBypass.addHiddenApiExemptions("Landroid/content/pm/ApplicationInfo;->setEnableOnBackInvokedCallback") setEnableOnBackInvokedCallback(applicationInfo, enable) } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/Natives.kt b/manager/app/src/main/java/me/weishu/kernelsu/Natives.kt index 63ff5e16f08a..153948fe9065 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/Natives.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/Natives.kt @@ -21,7 +21,7 @@ object Natives { // 32310: new get_allow_list ioctl // 32336: new set_sepolicy ioctl // 32377: add set_init_pgrp ioctl - const val MINIMAL_SUPPORTED_KERNEL = 32377 + const val MINIMAL_SUPPORTED_KERNEL = 32377 + 30 // KowSU commit around 30 const val KERNEL_SU_DOMAIN = "u:r:ksu:s0" @@ -78,6 +78,15 @@ object Natives { external fun isKernelUmountEnabled(): Boolean external fun setKernelUmountEnabled(enabled: Boolean): Boolean + /** + * Avc spoof can be enabled/disabled. + * 0: disabled + * 1: enabled + * negative : error + */ + external fun isAvcSpoofEnabled(): Boolean + external fun setAvcSpoofEnabled(enabled: Boolean): Boolean + /** * Get the user name for the uid. */ diff --git a/manager/app/src/main/java/me/weishu/kernelsu/data/repository/ModuleRepositoryImpl.kt b/manager/app/src/main/java/me/weishu/kernelsu/data/repository/ModuleRepositoryImpl.kt index fdbc66522230..1193038287fe 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/data/repository/ModuleRepositoryImpl.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/data/repository/ModuleRepositoryImpl.kt @@ -52,7 +52,7 @@ class ModuleRepositoryImpl : ModuleRepository { if (!isNetworkAvailable(ksuApp)) { return@runCatching ModuleUpdateInfo.Empty } - if (module.updateJson.isEmpty() || module.remove || module.update || !module.enabled) { + if (module.updateJson.isEmpty() || module.remove || !module.enabled) { return@runCatching ModuleUpdateInfo.Empty } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/data/repository/SettingsRepository.kt b/manager/app/src/main/java/me/weishu/kernelsu/data/repository/SettingsRepository.kt index 6bbda4e5326e..146412744f8c 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/data/repository/SettingsRepository.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/data/repository/SettingsRepository.kt @@ -9,6 +9,10 @@ interface SettingsRepository { var keyColor: Int var colorStyle: String var colorSpec: String + var enableOfficialLauncher: Boolean + var classicUi: Boolean + var showSwitchIcon: Boolean + var scrollAnimation: Boolean var enablePredictiveBack: Boolean var enableBlur: Boolean var enableFloatingBottomBar: Boolean @@ -37,6 +41,10 @@ interface SettingsRepository { suspend fun getAdbRootPersistValue(): Long? fun setAdbRootEnabled(enabled: Boolean): Boolean + suspend fun getAvcSpoofStatus(): String + fun isAvcSpoofEnabled(): Boolean + fun setAvcSpoofEnabled(enabled: Boolean): Boolean + fun isDefaultUmountModules(): Boolean fun setDefaultUmountModules(enabled: Boolean): Boolean diff --git a/manager/app/src/main/java/me/weishu/kernelsu/data/repository/SettingsRepositoryImpl.kt b/manager/app/src/main/java/me/weishu/kernelsu/data/repository/SettingsRepositoryImpl.kt index 58e3bad335d4..8d64018a548d 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/data/repository/SettingsRepositoryImpl.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/data/repository/SettingsRepositoryImpl.kt @@ -54,8 +54,24 @@ class SettingsRepositoryImpl : SettingsRepository { get() = prefs.getString("color_spec", ColorSpec.SpecVersion.Default.name) ?: ColorSpec.SpecVersion.Default.name set(value) = prefs.edit { putString("color_spec", value) } + override var enableOfficialLauncher: Boolean + get() = prefs.getBoolean("enable_official_launcher", false) + set(value) = prefs.edit { putBoolean("enable_official_launcher", value) } + + override var classicUi: Boolean + get() = prefs.getBoolean("classic_ui", false) + set(value) = prefs.edit { putBoolean("classic_ui", value) } + + override var showSwitchIcon: Boolean + get() = prefs.getBoolean("show_switch_icon", false) + set(value) = prefs.edit { putBoolean("show_switch_icon", value) } + + override var scrollAnimation: Boolean + get() = prefs.getBoolean("scroll_animation", false) + set(value) = prefs.edit { putBoolean("scroll_animation", value) } + override var enablePredictiveBack: Boolean - get() = prefs.getBoolean("enable_predictive_back", false) + get() = prefs.getBoolean("enable_predictive_back", true) set(value) = prefs.edit { putBoolean("enable_predictive_back", value) } override var enableBlur: Boolean @@ -135,6 +151,12 @@ class SettingsRepositoryImpl : SettingsRepository { false } + override suspend fun getAvcSpoofStatus(): String = getFeatureStatus("avc_spoof") + + override fun isAvcSpoofEnabled(): Boolean = Natives.isAvcSpoofEnabled() + + override fun setAvcSpoofEnabled(enabled: Boolean): Boolean = Natives.setAvcSpoofEnabled(enabled) + override fun isDefaultUmountModules(): Boolean = Natives.isDefaultUmountModules() override fun setDefaultUmountModules(enabled: Boolean): Boolean = Natives.setDefaultUmountModules(enabled) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt index 5336acf7e271..e2f8035438de 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/MainActivity.kt @@ -11,6 +11,14 @@ import androidx.activity.SystemBarStyle import androidx.activity.compose.LocalActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleOut +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.animation.togetherWith import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -33,8 +41,10 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.Alignment @@ -86,10 +96,13 @@ import me.weishu.kernelsu.ui.screen.superuser.SuperUserPager import me.weishu.kernelsu.ui.screen.template.AppProfileTemplateScreen import me.weishu.kernelsu.ui.screen.templateeditor.TemplateEditorScreen import me.weishu.kernelsu.ui.theme.KernelSUTheme +import me.weishu.kernelsu.ui.theme.LocalClassicUi import me.weishu.kernelsu.ui.theme.LocalColorMode import me.weishu.kernelsu.ui.theme.LocalEnableBlur import me.weishu.kernelsu.ui.theme.LocalEnableFloatingBottomBar import me.weishu.kernelsu.ui.theme.LocalEnableFloatingBottomBarBlur +import me.weishu.kernelsu.ui.util.LocalScrollAnimation +import me.weishu.kernelsu.ui.util.LocalShowSwitchIcon import me.weishu.kernelsu.ui.util.LocalSnackbarHost import me.weishu.kernelsu.ui.util.getFileName import me.weishu.kernelsu.ui.util.install @@ -97,6 +110,8 @@ import me.weishu.kernelsu.ui.util.rememberBlurBackdrop import me.weishu.kernelsu.ui.util.rememberContentReady import me.weishu.kernelsu.ui.util.rootAvailable import me.weishu.kernelsu.ui.viewmodel.MainActivityViewModel +import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel +import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel import me.weishu.kernelsu.ui.webui.WebUIActivity import top.yukonga.miuix.kmp.basic.Scaffold import top.yukonga.miuix.kmp.theme.MiuixTheme @@ -115,6 +130,9 @@ class MainActivity : ComponentActivity() { setContent { val viewModel = viewModel() + val superUserViewModel = viewModel() + val moduleViewModel = viewModel() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() val appSettings = uiState.appSettings val uiMode = uiState.uiMode @@ -150,9 +168,22 @@ class MainActivity : ComponentActivity() { LocalEnableFloatingBottomBar provides uiState.enableFloatingBottomBar, LocalEnableFloatingBottomBarBlur provides uiState.enableFloatingBottomBarBlur, LocalUiMode provides uiMode, - LocalSnackbarHost provides snackBarHostState + LocalSnackbarHost provides snackBarHostState, + LocalShowSwitchIcon provides appSettings.showSwitchIcon, + LocalScrollAnimation provides appSettings.scrollAnimation, + LocalClassicUi provides appSettings.classicUi ) { KernelSUTheme(appSettings = appSettings, uiMode = uiMode) { + val isFullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable() + LaunchedEffect(isFullFeatured) { + if (isFullFeatured) { + superUserViewModel.initializePreferences() + superUserViewModel.loadAppList() + moduleViewModel.initializePreferences() + moduleViewModel.fetchModuleList() + } + } + HandleDeepLink(intentState = intentState.collectAsStateWithLifecycle()) ZipFileIntentHandler(intentState = intentState, isManager = isManager) ShortcutIntentHandler(intentState = intentState) @@ -177,6 +208,21 @@ class MainActivity : ComponentActivity() { else -> navigator.pop() } }, + transitionSpec = { + val enter = slideInHorizontally(initialOffsetX = { it }) + val exit = slideOutHorizontally(targetOffsetX = { -it / 4 }) + fadeOut() + enter togetherWith exit + }, + popTransitionSpec = { + val enter = slideInHorizontally(initialOffsetX = { -it / 4 }) + fadeIn() + val exit = scaleOut(targetScale = 0.9f) + fadeOut() + enter togetherWith exit + }, + predictivePopTransitionSpec = { + val enter = slideInHorizontally(initialOffsetX = { -it / 4 }) + fadeIn() + val exit = scaleOut(targetScale = 0.9f) + fadeOut() + enter togetherWith exit + }, entryProvider = entryProvider { entry { MainScreen() } entry { AboutScreen() } @@ -224,8 +270,14 @@ fun MainScreen() { val enableBlur = LocalEnableBlur.current val enableFloatingBottomBar = LocalEnableFloatingBottomBar.current val enableFloatingBottomBarBlur = LocalEnableFloatingBottomBarBlur.current - val pagerState = rememberPagerState(pageCount = { 4 }) - val mainPagerState = rememberMainPagerState(pagerState) + val scrollAnimation = LocalScrollAnimation.current + var currentPage by rememberSaveable { mutableIntStateOf(0) } + val pagerState = rememberPagerState(initialPage = currentPage, pageCount = { 4 }) + LaunchedEffect(pagerState.currentPage) { + currentPage = pagerState.currentPage + } + val mainPagerState = rememberMainPagerState(pagerState, initialPage = currentPage) + mainPagerState.usePager = scrollAnimation val isManager = Natives.isManager val isFullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable() var userScrollEnabled by remember(isFullFeatured) { mutableStateOf(isFullFeatured) } @@ -245,6 +297,10 @@ fun MainScreen() { mainPagerState.syncPage() } + LaunchedEffect(mainPagerState.selectedPage) { + currentPage = mainPagerState.selectedPage + } + MainScreenBackHandler(mainPagerState, navController) val isLandscape = LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE @@ -255,20 +311,36 @@ fun MainScreen() { ) { val contentReady = rememberContentReady() val pagerContent = @Composable { bottomInnerPadding: Dp -> + val mainModifier = Modifier + .then(if (enableFloatingBottomBar && enableFloatingBottomBarBlur) Modifier.layerBackdrop(backdrop) else Modifier) + Box(modifier = if (blurBackdrop != null) Modifier.miuixLayerBackdrop(blurBackdrop) else Modifier) { - HorizontalPager( - modifier = Modifier - .then(if (enableFloatingBottomBar && enableFloatingBottomBarBlur) Modifier.layerBackdrop(backdrop) else Modifier), - state = mainPagerState.pagerState, - beyondViewportPageCount = if (contentReady) 3 else 0, - userScrollEnabled = userScrollEnabled, - ) { page -> - val isCurrentPage = page == mainPagerState.pagerState.settledPage - when (page) { - 0 -> if (isCurrentPage || contentReady) HomePager(navController, bottomInnerPadding, isCurrentPage) - 1 -> if (isCurrentPage || contentReady) SuperUserPager(navController, bottomInnerPadding, isCurrentPage) - 2 -> if (isCurrentPage || contentReady) ModulePager(bottomInnerPadding, isCurrentPage) - 3 -> if (isCurrentPage || contentReady) SettingPager(navController, bottomInnerPadding) + if (scrollAnimation) { + HorizontalPager( + modifier = mainModifier, + state = mainPagerState.pagerState, + beyondViewportPageCount = if (contentReady) 3 else 0, + userScrollEnabled = userScrollEnabled + ) { page -> + val isCurrentPage = page == mainPagerState.pagerState.settledPage + MainPage( + page = page, + navigator = navController, + bottomInnerPadding = bottomInnerPadding, + isCurrentPage = isCurrentPage, + contentReady = contentReady + ) + } + } else { + AnimatedContent( + modifier = mainModifier, + targetState = mainPagerState.selectedPage, + transitionSpec = { + fadeIn(tween(340)) togetherWith fadeOut(tween(340)) + }, + label = "MainScreenTransition" + ) { page -> + MainPage(page, navController, bottomInnerPadding) } } } @@ -336,6 +408,23 @@ fun MainScreen() { } } +@Composable +fun MainPage( + page: Int, + navigator: Navigator, + bottomInnerPadding: Dp, + isCurrentPage: Boolean = true, + contentReady: Boolean = true, +) { + if (!contentReady && !isCurrentPage) return + + when (page) { + 0 -> HomePager(navigator, bottomInnerPadding, isCurrentPage) + 1 -> SuperUserPager(navigator, bottomInnerPadding, isCurrentPage) + 2 -> ModulePager(bottomInnerPadding, isCurrentPage) + 3 -> SettingPager(navigator, bottomInnerPadding) + } +} @Composable private fun MainScreenBackHandler( @@ -373,13 +462,21 @@ private fun ZipFileIntentHandler( val activity = LocalActivity.current ?: return val context = LocalContext.current var zipUri by remember { mutableStateOf(null) } + var isAnyKernel by remember { mutableStateOf(false) } val isSafeMode = Natives.isSafeMode val clearZipUri = { zipUri = null } val navigator = LocalNavigator.current val installDialog = rememberConfirmDialog( onConfirm = { - zipUri?.let { uri -> navigator.push(Route.Flash(FlashIt.FlashModules(listOf(uri)))) } + zipUri?.let { uri -> + val flashIt = if (isAnyKernel) { + FlashIt.FlashAnyKernel(uri) + } else { + FlashIt.FlashModules(listOf(uri)) + } + navigator.push(Route.Flash(flashIt)) + } clearZipUri() }, onDismiss = clearZipUri @@ -394,17 +491,34 @@ private fun ZipFileIntentHandler( val currentIntent = activity.intent val uri = currentIntent?.data ?: return@LaunchedEffect - if (!isManager || uri.scheme != "content" || currentIntent.type != "application/zip") { + if (uri.scheme != "content" || currentIntent.type != "application/zip") { return@LaunchedEffect } + val component = currentIntent.component?.className + val isAnyKernelIntent = component?.endsWith("FlashAnyKernel") == true + + if (!isAnyKernelIntent && !isManager) return@LaunchedEffect + activity.intent.data = null activity.intent.type = null + if (isAnyKernelIntent) { + if (!rootAvailable()) return@LaunchedEffect + zipUri = uri + isAnyKernel = true + installDialog.showConfirm( + title = context.getString(R.string.anykernel_install), + content = getDisplayName(uri) + ) + return@LaunchedEffect + } + if (isSafeMode) { Toast.makeText(context, context.getString(R.string.safe_mode_module_disabled), Toast.LENGTH_SHORT).show() } else { zipUri = uri + isAnyKernel = false installDialog.showConfirm( title = context.getString(R.string.module), content = context.getString( diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/UiMode.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/UiMode.kt index 6fa66cb46b5b..6532317dd1c9 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/UiMode.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/UiMode.kt @@ -8,12 +8,12 @@ enum class UiMode(val value: String) { companion object { fun fromValue(value: String): UiMode = when (value) { - Material.value -> Material - else -> Miuix + Miuix.value -> Miuix + else -> Material } - val DEFAULT_VALUE = Miuix.value + val DEFAULT_VALUE = Material.value } } -val LocalUiMode = staticCompositionLocalOf { UiMode.Miuix } +val LocalUiMode = staticCompositionLocalOf { UiMode.Material } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/BottomBar.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/BottomBar.kt index 5c0cfbb4e308..b3dea9125abb 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/BottomBar.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/BottomBar.kt @@ -24,14 +24,17 @@ import kotlin.math.abs class MainPagerState( val pagerState: PagerState, - private val coroutineScope: CoroutineScope + private val coroutineScope: CoroutineScope, + initialPage: Int = pagerState.currentPage, ) { - var selectedPage by mutableIntStateOf(pagerState.currentPage) + var selectedPage by mutableIntStateOf(initialPage) private set var isNavigating by mutableStateOf(false) private set + var usePager by mutableStateOf(true) + private var navJob: Job? = null fun animateToPage(targetIndex: Int) { @@ -40,6 +43,9 @@ class MainPagerState( navJob?.cancel() selectedPage = targetIndex + + if (!usePager) return + isNavigating = true val distance = abs(targetIndex - pagerState.currentPage).coerceAtLeast(2) @@ -68,6 +74,7 @@ class MainPagerState( } fun syncPage() { + if (!usePager) return if (!isNavigating && selectedPage != pagerState.currentPage) { selectedPage = pagerState.currentPage } @@ -77,10 +84,11 @@ class MainPagerState( @Composable fun rememberMainPagerState( pagerState: PagerState, - coroutineScope: CoroutineScope = rememberCoroutineScope() + coroutineScope: CoroutineScope = rememberCoroutineScope(), + initialPage: Int = pagerState.currentPage, ): MainPagerState { return remember(pagerState, coroutineScope) { - MainPagerState(pagerState, coroutineScope) + MainPagerState(pagerState, coroutineScope, initialPage) } } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/BottomBarMaterial.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/BottomBarMaterial.kt index 35d7f2dd393d..fe36a2668771 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/BottomBarMaterial.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/BottomBarMaterial.kt @@ -71,7 +71,8 @@ fun BottomBarMaterial() { maxLines = 1, overflow = TextOverflow.Ellipsis ) - } + }, + alwaysShowLabel = false ) } } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/NavigationRailMaterial.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/NavigationRailMaterial.kt index 3b478029d3bd..38aa32cc3b76 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/NavigationRailMaterial.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/bottombar/NavigationRailMaterial.kt @@ -68,7 +68,8 @@ fun NavigationRailMaterial( stringResource(label) ) }, - label = { Text(stringResource(label)) } + label = { Text(stringResource(label)) }, + alwaysShowLabel = false ) } Spacer(Modifier.weight(1f)) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/material/ExpressiveSwitch.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/material/ExpressiveSwitch.kt index 0497bf1b2247..7aac1084bc9c 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/material/ExpressiveSwitch.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/material/ExpressiveSwitch.kt @@ -13,6 +13,7 @@ import androidx.compose.material3.SwitchDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import me.weishu.kernelsu.ui.util.LocalShowSwitchIcon @Composable fun ExpressiveSwitch( @@ -23,7 +24,7 @@ fun ExpressiveSwitch( enabled: Boolean = true, colors: SwitchColors = SwitchDefaults.colors(), interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, - showThumbIcon: Boolean = true, + showThumbIcon: Boolean = LocalShowSwitchIcon.current, ) { Switch( checked = checked, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/rebootlistpopup/RebootListPopup.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/rebootlistpopup/RebootListPopup.kt index 330215029cbe..91b3552661ab 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/rebootlistpopup/RebootListPopup.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/rebootlistpopup/RebootListPopup.kt @@ -1,6 +1,7 @@ package me.weishu.kernelsu.ui.component.rebootlistpopup import android.content.Context +import android.os.Build import android.os.PowerManager import androidx.annotation.StringRes import androidx.compose.runtime.Composable @@ -19,7 +20,8 @@ fun getRebootListOption(): List { val pm = LocalContext.current.getSystemService(Context.POWER_SERVICE) as PowerManager? @Suppress("DEPRECATION") - val isRebootingUserspaceSupported = pm?.isRebootingUserspaceSupported == true + val isRebootingUserspaceSupported = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && pm?.isRebootingUserspaceSupported == true return buildList { add(RebootListOption(R.string.reboot, "")) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/rebootlistpopup/RebootListPopupMaterial.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/rebootlistpopup/RebootListPopupMaterial.kt index d5cb032f4c23..99467479bb34 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/component/rebootlistpopup/RebootListPopupMaterial.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/component/rebootlistpopup/RebootListPopupMaterial.kt @@ -1,52 +1,165 @@ package me.weishu.kernelsu.ui.component.rebootlistpopup +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.RotateRight import androidx.compose.material.icons.filled.PowerSettingsNew -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material.icons.outlined.DeveloperMode +import androidx.compose.material.icons.outlined.Download +import androidx.compose.material.icons.outlined.Memory +import androidx.compose.material.icons.outlined.Refresh +import androidx.compose.material.icons.outlined.RestartAlt +import androidx.compose.material.icons.outlined.SystemUpdate +import androidx.compose.material3.BasicAlertDialog +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp import me.weishu.kernelsu.R import me.weishu.kernelsu.ui.component.KsuIsValid +import me.weishu.kernelsu.ui.component.material.SegmentedColumn +import me.weishu.kernelsu.ui.component.material.SegmentedListItem import me.weishu.kernelsu.ui.util.reboot +private data class RebootOption( + val labelRes: Int, + val reason: String, + val icon: ImageVector +) + @Composable -fun RebootDropdownItems(onItemClick: (String) -> Unit) { - getRebootListOption().forEach { option -> - DropdownMenuItem( - text = { Text(" " + stringResource(option.labelRes)) }, - onClick = { onItemClick(option.reason) } +private fun getRebootOptions(): List { + return getRebootListOption().map { option -> + RebootOption( + labelRes = option.labelRes, + reason = option.reason, + icon = when (option.reason) { + "" -> Icons.Outlined.Refresh + "userspace" -> Icons.Outlined.RestartAlt + "soft_reboot" -> Icons.AutoMirrored.Outlined.RotateRight + "recovery" -> Icons.Outlined.SystemUpdate + "bootloader" -> Icons.Outlined.Memory + "download" -> Icons.Outlined.Download + "edl" -> Icons.Outlined.DeveloperMode + else -> Icons.Outlined.Refresh + } ) } } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RebootDialog( + show: Boolean, + onDismiss: () -> Unit, + onReboot: (String) -> Unit +) { + if (!show) return + + val options = getRebootOptions() + + BasicAlertDialog( + onDismissRequest = onDismiss + ) { + Surface( + shape = RoundedCornerShape(28.dp), + color = MaterialTheme.colorScheme.surfaceContainerHigh + ) { + Column( + modifier = Modifier.padding(24.dp) + ) { + Text( + text = stringResource(R.string.reboot), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.onSurface + ) + + SegmentedColumn( + modifier = Modifier.padding(top = 20.dp), + content = options.map { option -> + { + SegmentedListItem( + headlineContent = { + Text(stringResource(option.labelRes)) + }, + leadingContent = { + Box( + modifier = Modifier + .size(40.dp) + .background( + color = MaterialTheme.colorScheme.secondaryContainer, + shape = CircleShape + ), + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = option.icon, + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = MaterialTheme.colorScheme.onSecondaryContainer + ) + } + }, + onClick = { + onDismiss() + onReboot(option.reason) + } + ) + } + } + ) + } + } + } +} + @Composable fun RebootListPopupMaterial() { - var expanded by remember { mutableStateOf(false) } + var showDialog by remember { mutableStateOf(false) } KsuIsValid { - IconButton(onClick = { expanded = true }) { + IconButton(onClick = { showDialog = true }) { Icon( imageVector = Icons.Filled.PowerSettingsNew, contentDescription = stringResource(id = R.string.reboot) ) } - DropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false } - ) { - RebootDropdownItems { reason -> - expanded = false - reboot(reason) - } - } + RebootDialog( + show = showDialog, + onDismiss = { showDialog = false }, + onReboot = { reason -> reboot(reason) } + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun RebootDialogPreview() { + MaterialTheme { + RebootDialog( + show = true, + onDismiss = {}, + onReboot = {} + ) } } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutMaterial.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutMaterial.kt index 06c8d9ceae18..544b31cf1471 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutMaterial.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutMaterial.kt @@ -38,7 +38,6 @@ import androidx.compose.ui.layout.FixedScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import me.weishu.kernelsu.R import me.weishu.kernelsu.ui.component.material.SegmentedColumn import me.weishu.kernelsu.ui.component.material.SegmentedListItem @@ -94,7 +93,7 @@ fun AboutScreenMaterial( .background(Color.White) ) { Image( - painter = painterResource(id = R.drawable.ic_launcher_foreground), + painter = painterResource(id = state.appIconRes), contentDescription = null, contentScale = FixedScale(1f) ) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutMiuix.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutMiuix.kt index d7ef757429aa..bef7b8e8325d 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutMiuix.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutMiuix.kt @@ -293,7 +293,7 @@ private fun AboutContent( ) } else Modifier ), - painter = painterResource(id = R.drawable.ic_launcher_foreground), + painter = painterResource(id = state.appIconRes), colorFilter = ColorFilter.tint(colorScheme.onBackground), contentDescription = null, ) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutScreen.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutScreen.kt index 22773368d58a..3aa34b2c6e13 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutScreen.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutScreen.kt @@ -9,6 +9,7 @@ import me.weishu.kernelsu.R import me.weishu.kernelsu.ui.LocalUiMode import me.weishu.kernelsu.ui.UiMode import me.weishu.kernelsu.ui.navigation3.LocalNavigator +import me.weishu.kernelsu.ui.util.AppInfo @Composable fun AboutScreen() { @@ -16,12 +17,13 @@ fun AboutScreen() { val uriHandler = LocalUriHandler.current val htmlString = stringResource( id = R.string.about_source_code, - "GitHub", - "Telegram" + "GitHub", + "Telegram" ) val state = AboutUiState( title = stringResource(R.string.about), - appName = stringResource(R.string.app_name), + appName = AppInfo.appName(), + appIconRes = AppInfo.appIconRes(), versionName = BuildConfig.VERSION_NAME, links = extractLinks(htmlString), ) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutUiState.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutUiState.kt index 6f7111a98cee..c760bccb433d 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutUiState.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/about/AboutUiState.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.Immutable data class AboutUiState( val title: String, val appName: String, + val appIconRes: Int, val versionName: String, val links: List, ) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreen.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreen.kt index 1e37473c7401..a04b7c013007 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreen.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreen.kt @@ -47,6 +47,10 @@ fun ColorPaletteScreen() { onSetColorMode = viewModel::setColorMode, onSetColorStyle = viewModel::setColorStyle, onSetColorSpec = viewModel::setColorSpec, + onSetEnableOfficialLauncher = viewModel::setEnableOfficialLauncher, + onSetClassicUi = viewModel::setClassicUi, + onSetShowSwitchIcon = viewModel::setShowSwitchIcon, + onSetScrollAnimation = viewModel::setScrollAnimation, onSetEnableBlur = viewModel::setEnableBlur, onSetEnableFloatingBottomBar = viewModel::setEnableFloatingBottomBar, onSetEnableFloatingBottomBarBlur = viewModel::setEnableFloatingBottomBarBlur, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreenMaterial.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreenMaterial.kt index 81d292a271e8..4e7d22857c9b 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreenMaterial.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreenMaterial.kt @@ -1,6 +1,8 @@ package me.weishu.kernelsu.ui.screen.colorpalette import android.annotation.SuppressLint +import android.content.ComponentName +import android.content.pm.PackageManager import android.os.Build import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.animateFloatAsState @@ -30,9 +32,11 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredSize import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState @@ -50,7 +54,10 @@ import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.rounded.AspectRatio import androidx.compose.material.icons.rounded.Check import androidx.compose.material.icons.rounded.DesignServices +import androidx.compose.material.icons.rounded.Home import androidx.compose.material.icons.rounded.Style +import androidx.compose.material.icons.rounded.ToggleOn +import androidx.compose.material.icons.rounded.ViewCarousel import androidx.compose.material3.ButtonGroupDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi @@ -64,8 +71,10 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.ToggleButton import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.darkColorScheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.expressiveLightColorScheme import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -83,6 +92,7 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.role @@ -92,6 +102,7 @@ import com.materialkolor.PaletteStyle import com.materialkolor.dynamiccolor.ColorSpec import com.materialkolor.rememberDynamicColorScheme import me.weishu.kernelsu.R +import me.weishu.kernelsu.ui.MainActivity import me.weishu.kernelsu.ui.component.material.SegmentedColumn import me.weishu.kernelsu.ui.component.material.SegmentedDropdownItem import me.weishu.kernelsu.ui.component.material.SegmentedSwitchItem @@ -112,6 +123,7 @@ fun ColorPaletteScreenMaterial( val colorStyle = state.currentPaletteStyle val colorSpec = state.currentColorSpec val haptic = LocalHapticFeedback.current + val context = LocalContext.current LaunchedEffect(Unit) { scrollBehavior.state.heightOffset = scrollBehavior.state.heightOffsetLimit @@ -152,6 +164,8 @@ fun ColorPaletteScreenMaterial( isDark = isDark, paletteStyle = colorStyle, colorSpec = colorSpec, + officialIcon = uiState.enableOfficialLauncher, + classicUi = uiState.classicUi, ) Spacer(modifier = Modifier.height(8.dp)) @@ -239,6 +253,54 @@ fun ColorPaletteScreenMaterial( } } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(ButtonGroupDefaults.ConnectedSpaceBetween) + ) { + val launcherOptions = listOf(false, true) + launcherOptions.forEachIndexed { index, isOfficial -> + ToggleButton( + checked = uiState.enableOfficialLauncher == isOfficial, + onCheckedChange = { enabled -> + if (enabled) { + actions.onSetEnableOfficialLauncher(isOfficial) + val pm = context.packageManager + val mainComponent = ComponentName(context, MainActivity::class.java) + val aliasComponent = ComponentName(context, "me.weishu.kernelsu.MainActivityOfficial") + val (enableComp, disableComp) = if (isOfficial) aliasComponent to mainComponent else mainComponent to aliasComponent + + haptic.performHapticFeedback(HapticFeedbackType.VirtualKey) + pm.setComponentEnabledSetting(enableComp, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP) + pm.setComponentEnabledSetting(disableComp, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP) + } + }, + modifier = Modifier + .weight(1f) + .semantics { role = Role.RadioButton }, + shapes = when (index) { + 0 -> ButtonGroupDefaults.connectedLeadingButtonShapes() + 1 -> ButtonGroupDefaults.connectedTrailingButtonShapes() + else -> ButtonGroupDefaults.connectedMiddleButtonShapes() + }, + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + painter = painterResource(id = if (isOfficial) R.drawable.ic_launcher_monochrome else R.drawable.ic_launcher_kowsu), + contentDescription = null, + modifier = Modifier + .size(24.dp) + .wrapContentSize(unbounded = true) + .requiredSize(48.dp) + ) + Text(if (isOfficial) stringResource(R.string.app_name) else stringResource(R.string.app_name_kowsu)) + } + } + } + } + SegmentedColumn( modifier = Modifier.padding(top = 4.dp), content = listOf( @@ -265,6 +327,42 @@ fun ColorPaletteScreenMaterial( actions.onSetColorSpec(specs[index].name) } ) + }, + ) + ) + + SegmentedColumn( + modifier = Modifier.padding(top = 4.dp), + content = listOf( + { + SegmentedSwitchItem( + icon = Icons.Rounded.Home, + title = stringResource(R.string.settings_classic_home_ui), + checked = uiState.classicUi, + onCheckedChange = { + actions.onSetClassicUi(it) + } + ) + }, + { + SegmentedSwitchItem( + icon = Icons.Rounded.ToggleOn, + title = stringResource(R.string.settings_switch_icon), + checked = uiState.showSwitchIcon, + onCheckedChange = { + actions.onSetShowSwitchIcon(it) + } + ) + }, + { + SegmentedSwitchItem( + icon = Icons.Rounded.ViewCarousel, + title = stringResource(R.string.settings_scroll_animation), + checked = uiState.scrollAnimation, + onCheckedChange = { + actions.onSetScrollAnimation(it) + } + ) } ) ) @@ -348,6 +446,8 @@ private fun ThemePreviewCard( isDark: Boolean, paletteStyle: PaletteStyle = PaletteStyle.TonalSpot, colorSpec: ColorSpec.SpecVersion = ColorSpec.SpecVersion.SPEC_2021, + officialIcon: Boolean = false, + classicUi: Boolean = false, ) { val context = LocalContext.current val configuration = LocalConfiguration.current @@ -357,7 +457,12 @@ private fun ThemePreviewCard( val dynamicColor = keyColor == 0 val colorScheme = if (dynamicColor) { - val baseScheme = if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + val baseScheme = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> + if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + else -> + if (isDark) darkColorScheme() else expressiveLightColorScheme() + } rememberDynamicColorScheme( seedColor = Color.Unspecified, isDark = isDark, @@ -400,11 +505,11 @@ private fun ThemePreviewCard( Row( modifier = Modifier .fillMaxSize() - .padding(start = 12.dp, top = 16.dp, bottom = 8.dp), + .padding(start = 12.dp, top = 16.dp, end = 12.dp, bottom = 8.dp), verticalAlignment = Alignment.CenterVertically ) { Text( - text = stringResource(id = R.string.app_name), + text = if (officialIcon) stringResource(R.string.app_name) else stringResource(R.string.app_name_kowsu), style = MaterialTheme.typography.bodyMedium, color = colorScheme.onSurface ) @@ -425,28 +530,26 @@ private fun ThemePreviewCard( containerColor = MaterialTheme.colorScheme.secondaryContainer, modifier = Modifier .fillMaxWidth() - .height(40.dp), + .height(if (classicUi) 64.dp else 40.dp), shape = RoundedCornerShape(12.dp), content = { } ) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - TonalCard( - modifier = Modifier - .weight(1f) - .height(32.dp), - shape = RoundedCornerShape(12.dp), - content = { } - ) - TonalCard( - modifier = Modifier - .weight(1f) - .height(32.dp), - shape = RoundedCornerShape(12.dp), - content = { } - ) + if (!classicUi) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + TonalCard( + modifier = Modifier.weight(1f).height(40.dp), + shape = RoundedCornerShape(12.dp), + content = { } + ) + TonalCard( + modifier = Modifier.weight(1f).height(40.dp), + shape = RoundedCornerShape(12.dp), + content = { } + ) + } } TonalCard( modifier = Modifier @@ -480,6 +583,7 @@ private fun ThemePreviewCard( } } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable private fun ColorButtonMaterial( color: Color, @@ -492,7 +596,12 @@ private fun ColorButtonMaterial( val context = LocalContext.current val haptic = LocalHapticFeedback.current val colorScheme = if (color == Color.Unspecified) { - val baseScheme = if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + val baseScheme = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> + if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + else -> + if (isDark) darkColorScheme() else expressiveLightColorScheme() + } rememberDynamicColorScheme( seedColor = Color.Unspecified, isDark = isDark, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreenMiuix.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreenMiuix.kt index d0513523ff1e..fdd512449045 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreenMiuix.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteScreenMiuix.kt @@ -1,6 +1,8 @@ package me.weishu.kernelsu.ui.screen.colorpalette import android.annotation.SuppressLint +import android.content.ComponentName +import android.content.pm.PackageManager import android.os.Build import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background @@ -24,8 +26,10 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredSize import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -37,6 +41,7 @@ import androidx.compose.material.icons.rounded.Colorize import androidx.compose.material.icons.rounded.DesignServices import androidx.compose.material.icons.rounded.RoundedCorner import androidx.compose.material.icons.rounded.Style +import androidx.compose.material.icons.rounded.ViewCarousel import androidx.compose.material.icons.rounded.Wallpaper import androidx.compose.material.icons.rounded.WaterDrop import androidx.compose.runtime.Composable @@ -53,7 +58,9 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp @@ -62,6 +69,7 @@ import com.materialkolor.PaletteStyle import com.materialkolor.dynamiccolor.ColorSpec import com.materialkolor.rememberDynamicColorScheme import me.weishu.kernelsu.R +import me.weishu.kernelsu.ui.MainActivity import me.weishu.kernelsu.ui.component.miuix.ScaleDialog import me.weishu.kernelsu.ui.theme.LocalEnableBlur import me.weishu.kernelsu.ui.theme.keyColorOptions @@ -102,6 +110,8 @@ fun ColorPaletteScreenMiuix( val currentColorMode = state.currentColorMode val isDark = currentColorMode.isDark || currentColorMode.isSystem && isSystemInDarkTheme() + val context = LocalContext.current + Scaffold( topBar = { BlurredBar(backdrop) { @@ -276,6 +286,55 @@ fun ColorPaletteScreenMiuix( } } + Card( + modifier = Modifier + .padding(top = 12.dp) + .fillMaxWidth(), + ) { + SwitchPreference( + title = stringResource(id = R.string.settings_official_icon), + startAction = { + Icon( + painter = painterResource(R.drawable.ic_launcher_monochrome), + contentDescription = stringResource(id = R.string.settings_official_icon), + modifier = Modifier + .padding(end = 6.dp) + .size(24.dp) + .wrapContentSize(unbounded = true) + .requiredSize(48.dp), + tint = colorScheme.onBackground + ) + }, + checked = uiState.enableOfficialLauncher, + onCheckedChange = { enabled -> + actions.onSetEnableOfficialLauncher(enabled) + val pm = context.packageManager + val mainComponent = ComponentName(context, MainActivity::class.java) + val aliasComponent = ComponentName(context, "me.weishu.kernelsu.MainActivityOfficial") + val (enableComp, disableComp) = if (enabled) aliasComponent to mainComponent else mainComponent to aliasComponent + + pm.setComponentEnabledSetting(enableComp, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP) + pm.setComponentEnabledSetting(disableComp, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP) + } + ) + + SwitchPreference( + title = stringResource(id = R.string.settings_scroll_animation), + startAction = { + Icon( + Icons.Rounded.ViewCarousel, + modifier = Modifier.padding(end = 6.dp), + contentDescription = stringResource(id = R.string.settings_scroll_animation), + tint = colorScheme.onBackground + ) + }, + checked = uiState.scrollAnimation, + onCheckedChange = { enabled -> + actions.onSetScrollAnimation(enabled) + } + ) + } + Card( modifier = Modifier .padding(top = 12.dp) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteUiState.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteUiState.kt index c1a45c2bab47..03a489cbcc8b 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteUiState.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/colorpalette/ColorPaletteUiState.kt @@ -23,6 +23,10 @@ data class ColorPaletteScreenActions( val onSetColorMode: (ColorMode) -> Unit, val onSetColorStyle: (String) -> Unit, val onSetColorSpec: (String) -> Unit, + val onSetEnableOfficialLauncher: (Boolean) -> Unit, + val onSetClassicUi: (Boolean) -> Unit, + val onSetShowSwitchIcon: (Boolean) -> Unit, + val onSetScrollAnimation: (Boolean) -> Unit, val onSetEnableBlur: (Boolean) -> Unit, val onSetEnableFloatingBottomBar: (Boolean) -> Unit, val onSetEnableFloatingBottomBarBlur: (Boolean) -> Unit, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/executemoduleaction/ExecuteModuleActionUtils.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/executemoduleaction/ExecuteModuleActionUtils.kt index 541776c04ad5..b901de381274 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/executemoduleaction/ExecuteModuleActionUtils.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/executemoduleaction/ExecuteModuleActionUtils.kt @@ -51,7 +51,7 @@ fun ExecuteModuleActionEffect( onExit() return@LaunchedEffect } - if (!moduleInfo.enabled || moduleInfo.update || moduleInfo.remove) { + if (!moduleInfo.enabled || moduleInfo.remove) { Toast.makeText(context, moduleUnavailable.format(moduleInfo.name), Toast.LENGTH_SHORT).show() onExit() return@LaunchedEffect diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/flash/FlashUtils.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/flash/FlashUtils.kt index 6b0cdbbdc003..3c1a03cc2df5 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/flash/FlashUtils.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/flash/FlashUtils.kt @@ -33,6 +33,7 @@ import kotlinx.parcelize.Parcelize import me.weishu.kernelsu.R import me.weishu.kernelsu.ui.util.FlashResult import me.weishu.kernelsu.ui.util.LkmSelection +import me.weishu.kernelsu.ui.util.flashAnyKernelZip import me.weishu.kernelsu.ui.util.flashModule import me.weishu.kernelsu.ui.util.installBoot import me.weishu.kernelsu.ui.util.restoreBoot @@ -82,6 +83,9 @@ sealed class FlashIt : Parcelable { @Parcelize data class FlashModules(val uris: List) : FlashIt() + @Parcelize + data class FlashAnyKernel(val uri: Uri) : FlashIt() + @Parcelize data object FlashRestore : FlashIt() @@ -125,6 +129,10 @@ fun flashIt( flashModulesSequentially(flashIt.uris, onStdout, onStderr) } + is FlashIt.FlashAnyKernel -> { + flashAnyKernelZip(flashIt.uri, onStdout, onStderr) + } + FlashIt.FlashRestore -> restoreBoot(onStdout, onStderr) FlashIt.FlashUninstall -> uninstallPermanently(onStdout, onStderr) } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeMaterial.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeMaterial.kt index 9a0c1166399c..917818a07ff2 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeMaterial.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeMaterial.kt @@ -1,5 +1,6 @@ package me.weishu.kernelsu.ui.screen.home +import android.os.Build import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn @@ -15,14 +16,23 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredSize import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Block import androidx.compose.material.icons.outlined.CheckCircle +import androidx.compose.material.icons.outlined.Fingerprint +import androidx.compose.material.icons.outlined.LocalPolice +import androidx.compose.material.icons.outlined.Memory +import androidx.compose.material.icons.outlined.Security +import androidx.compose.material.icons.outlined.VerifiedUser import androidx.compose.material.icons.outlined.Warning +import androidx.compose.material.icons.outlined.Widgets import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api @@ -40,9 +50,11 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.UriHandler +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -54,6 +66,10 @@ import me.weishu.kernelsu.ui.component.dialog.rememberConfirmDialog import me.weishu.kernelsu.ui.component.material.TonalCard import me.weishu.kernelsu.ui.component.rebootlistpopup.RebootListPopup import me.weishu.kernelsu.ui.component.statustag.StatusTag +import me.weishu.kernelsu.ui.theme.LocalClassicUi +import me.weishu.kernelsu.ui.theme.LocalEnableOfficialLauncher +import me.weishu.kernelsu.ui.util.getModuleCount +import me.weishu.kernelsu.ui.util.getSuperuserCount @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -65,7 +81,7 @@ fun HomePagerMaterial( val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()) Scaffold( - topBar = { TopBar(scrollBehavior = scrollBehavior) }, + topBar = { TopBar(appName = state.appName, scrollBehavior = scrollBehavior) }, contentWindowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal) ) { innerPadding -> Column( @@ -85,17 +101,17 @@ fun HomePagerMaterial( } else if (state.showKernelPrBuildWarning) { WarningCard(stringResource(id = R.string.home_pr_kernel_warning)) } - if (state.showVersionMismatchWarning) { - WarningCard( - stringResource(id = R.string.home_version_mismatch, - state.currentManagerVersionCode, - state.ksuVersion ?: 0 - ) - ) - } - if (state.showGkiWarning) { - WarningCard(stringResource(id = R.string.home_gki_warning)) - } +// if (state.showVersionMismatchWarning) { +// WarningCard( +// stringResource(id = R.string.home_version_mismatch, +// state.currentManagerVersionCode, +// state.ksuVersion ?: 0 +// ) +// ) +// } +// if (state.showGkiWarning) { +// WarningCard(stringResource(id = R.string.home_gki_warning)) +// } if (state.showRequireKernelWarning) { WarningCard( stringResource(id = R.string.require_kernel_version, @@ -107,9 +123,9 @@ fun HomePagerMaterial( if (state.showRootWarning) { WarningCard(stringResource(id = R.string.grant_root_failed)) } - if (state.checkUpdateEnabled) { - UpdateCard(state = state, actions = actions) - } +// if (state.checkUpdateEnabled) { +// UpdateCard(state = state, actions = actions) +// } InfoCard(systemInfo = state.systemInfo) DonateCard(onOpenUrl = actions.onOpenUrl) LearnMoreCard(onOpenUrl = actions.onOpenUrl) @@ -154,10 +170,11 @@ private fun UpdateCard( @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable private fun TopBar( + appName: String, scrollBehavior: TopAppBarScrollBehavior? = null ) { LargeFlexibleTopAppBar( - title = { Text(stringResource(R.string.app_name)) }, + title = { Text(appName) }, actions = { RebootListPopup() }, colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.surface, @@ -173,6 +190,7 @@ private fun StatusCard( state: HomeUiState, actions: HomeActions, ) { + val classicUi = LocalClassicUi.current Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { TonalCard( containerColor = if (state.ksuVersion != null) { @@ -195,7 +213,7 @@ private fun StatusCard( when { state.ksuVersion != null -> { val workingMode = when (state.lkmMode) { - null -> "" + null -> if (Build.SUPPORTED_64_BIT_ABIS.isEmpty()) "32-BIT" else "LEGACY" true -> "LKM" else -> "GKI" } @@ -237,6 +255,19 @@ private fun StatusCard( text = stringResource(R.string.home_working_version, state.ksuVersion), style = MaterialTheme.typography.bodyMedium ) + if (classicUi) { + Spacer(Modifier.height(4.dp)) + Text( + text = stringResource( + R.string.home_superuser_count, getSuperuserCount() + ), style = MaterialTheme.typography.bodyMedium + ) + Spacer(Modifier.height(4.dp)) + Text( + text = stringResource(R.string.home_module_count, getModuleCount()), + style = MaterialTheme.typography.bodyMedium + ) + } } } @@ -287,7 +318,7 @@ private fun StatusCard( } } } - if (state.isFullFeatured) { + if (state.isFullFeatured && !classicUi) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(16.dp) @@ -296,46 +327,66 @@ private fun StatusCard( modifier = Modifier.weight(1f), onClick = actions.onSuperuserClick ) { - Column( + Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 24.dp, vertical = 16.dp) + .padding(horizontal = 20.dp, vertical = 16.dp), + verticalAlignment = Alignment.CenterVertically ) { - Text( - text = stringResource(R.string.superuser), - style = MaterialTheme.typography.bodyLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Spacer(Modifier.height(4.dp)) - Text( - text = state.superuserCount.toString(), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.outline + Icon( + imageVector = Icons.Outlined.Security, + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant ) + Spacer(Modifier.width(16.dp)) + Column { + Text( + text = stringResource(R.string.superuser), + style = MaterialTheme.typography.bodyLarge, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Spacer(Modifier.height(4.dp)) + Text( + text = state.superuserCount.toString(), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.outline + ) + } } } TonalCard( modifier = Modifier.weight(1f), onClick = actions.onModuleClick ) { - Column( + Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 24.dp, vertical = 16.dp) + .padding(horizontal = 20.dp, vertical = 16.dp), + verticalAlignment = Alignment.CenterVertically ) { - Text( - text = stringResource(R.string.module), - style = MaterialTheme.typography.bodyLarge, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Spacer(Modifier.height(4.dp)) - Text( - text = state.moduleCount.toString(), - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.outline + Icon( + imageVector = Icons.Outlined.Widgets, + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant ) + Spacer(Modifier.width(16.dp)) + Column { + Text( + text = stringResource(R.string.module), + style = MaterialTheme.typography.bodyLarge, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Spacer(Modifier.height(4.dp)) + Text( + text = state.moduleCount.toString(), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.outline + ) + } } } } @@ -412,27 +463,80 @@ private fun DonateCard(onOpenUrl: (String) -> Unit) { @Composable private fun InfoCard(systemInfo: SystemInfo) { + val isOfficial = LocalEnableOfficialLauncher.current + val isClassicUi = LocalClassicUi.current + TonalCard { Column( modifier = Modifier .fillMaxWidth() - .padding(start = 24.dp, top = 24.dp, end = 24.dp, bottom = 16.dp) + .padding(horizontal = 20.dp, vertical = 24.dp) ) { @Composable - fun InfoCardItem(label: String, content: String) { - Text(text = label, style = MaterialTheme.typography.bodyLarge) - Text( - text = content, - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.outline - ) + fun InfoCardItem( + label: String, + content: String, + icon: @Composable () -> Unit + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + if (!isClassicUi) { + icon() + Spacer(Modifier.width(16.dp)) + } + Column { + Text(text = label, style = MaterialTheme.typography.bodyLarge) + Text( + text = content, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.outline, + ) + } + } } - InfoCardItem(stringResource(R.string.home_kernel), systemInfo.kernelVersion) + @Composable + fun InfoCardItem(icon: ImageVector, label: String, content: String) = InfoCardItem( + label = label, + content = content, + icon = { + Icon( + imageVector = icon, + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + ) + + InfoCardItem( + icon = Icons.Outlined.Memory, + label = stringResource(R.string.home_kernel), + content = systemInfo.kernelVersion + ) + Spacer(Modifier.height(16.dp)) - InfoCardItem(stringResource(R.string.home_manager_version), systemInfo.managerVersion) + InfoCardItem( + icon = { + Icon( + painter = painterResource(if (isOfficial) R.drawable.ic_launcher_foreground else R.drawable.ic_launcher_kowsu), + contentDescription = null, + modifier = Modifier.size(20.dp).wrapContentSize(unbounded = true).requiredSize(48.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + }, + label = stringResource(R.string.home_manager_version), + content = systemInfo.managerVersion + ) + Spacer(Modifier.height(16.dp)) - InfoCardItem(stringResource(R.string.home_fingerprint), systemInfo.fingerprint) + InfoCardItem( + icon = Icons.Outlined.Fingerprint, + label = stringResource(R.string.home_fingerprint), + content = systemInfo.fingerprint + ) + Spacer(Modifier.height(16.dp)) val selinuxDisplay = when (systemInfo.selinuxStatus) { "Enforcing" -> stringResource(R.string.selinux_status_enforcing) @@ -440,7 +544,12 @@ private fun InfoCard(systemInfo: SystemInfo) { "Disabled" -> stringResource(R.string.selinux_status_disabled) else -> stringResource(R.string.selinux_status_unknown) } - InfoCardItem(stringResource(R.string.home_selinux_status), selinuxDisplay) + InfoCardItem( + icon = Icons.Outlined.VerifiedUser, + label = stringResource(R.string.home_selinux_status), + content = selinuxDisplay + ) + Spacer(Modifier.height(16.dp)) val seccompDisplay = when (systemInfo.seccompStatus) { -1 -> stringResource(R.string.seccomp_status_not_supported) @@ -449,7 +558,11 @@ private fun InfoCard(systemInfo: SystemInfo) { 2 -> stringResource(R.string.seccomp_status_filter) else -> stringResource(R.string.seccomp_status_unknown) } - InfoCardItem(stringResource(R.string.home_seccomp_status), seccompDisplay) + InfoCardItem( + icon = Icons.Outlined.LocalPolice, + label = stringResource(R.string.home_seccomp_status), + content = seccompDisplay + ) } } } @@ -508,6 +621,7 @@ private fun HomeScreenPreviewContent( superuserCount: Int = 0, moduleCount: Int = 0, selinuxStatus: String = "Enforcing", + classicUi: Boolean = false, ) { CompositionLocalProvider(LocalUriHandler provides previewUriHandler) { Column( @@ -524,6 +638,7 @@ private fun HomeScreenPreviewContent( superuserCount = superuserCount, moduleCount = moduleCount, selinuxStatus = selinuxStatus, + classicUi = classicUi, ), actions = actions ) @@ -566,7 +681,10 @@ private fun previewHomeScreenState( superuserCount: Int = 0, moduleCount: Int = 0, selinuxStatus: String = "Enforcing", + classicUi: Boolean = false, ) = HomeUiState( + appName = "KernelSU", + classicUi = classicUi, kernelVersion = KernelVersion(6, 1, 0), ksuVersion = ksuVersion, lkmMode = lkmMode, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeMiuix.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeMiuix.kt index ac013fcb71fb..dcd718334e23 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeMiuix.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeMiuix.kt @@ -1,5 +1,6 @@ package me.weishu.kernelsu.ui.screen.home +import android.os.Build import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn @@ -89,6 +90,7 @@ fun HomePagerMiuix( Scaffold( topBar = { TopBar( + appName = state.appName, scrollBehavior = scrollBehavior, backdrop = backdrop, barColor = barColor, @@ -119,18 +121,18 @@ fun HomePagerMiuix( } else if (state.showKernelPrBuildWarning) { WarningCard(stringResource(id = R.string.home_pr_kernel_warning)) } - if (state.showVersionMismatchWarning) { - WarningCard( - stringResource( - id = R.string.home_version_mismatch, - state.currentManagerVersionCode, - state.ksuVersion ?: 0 - ) - ) - } - if (state.showGkiWarning) { - WarningCard(stringResource(id = R.string.home_gki_warning)) - } +// if (state.showVersionMismatchWarning) { +// WarningCard( +// stringResource( +// id = R.string.home_version_mismatch, +// state.currentManagerVersionCode, +// state.ksuVersion ?: 0 +// ) +// ) +// } +// if (state.showGkiWarning) { +// WarningCard(stringResource(id = R.string.home_gki_warning)) +// } if (state.showRequireKernelWarning) { WarningCard( stringResource( @@ -146,9 +148,9 @@ fun HomePagerMiuix( state = state, actions = actions, ) - if (state.checkUpdateEnabled) { - UpdateCard(state = state, actions = actions) - } +// if (state.checkUpdateEnabled) { +// UpdateCard(state = state, actions = actions) +// } InfoCard(systemInfo = state.systemInfo) DonateCard(onOpenUrl = actions.onOpenUrl) LearnMoreCard(onOpenUrl = actions.onOpenUrl) @@ -196,6 +198,7 @@ private fun UpdateCard( @Composable private fun TopBar( + appName: String, scrollBehavior: ScrollBehavior, backdrop: LayerBackdrop?, barColor: Color, @@ -203,7 +206,7 @@ private fun TopBar( BlurredBar(backdrop) { TopAppBar( color = barColor, - title = stringResource(R.string.app_name), + title = appName, actions = { RebootListPopupMiuix() }, @@ -229,7 +232,7 @@ private fun StatusCard( } } val workingMode = when (state.lkmMode) { - null -> "" + null -> if (Build.SUPPORTED_64_BIT_ABIS.isEmpty()) " <32-BIT>" else " " true -> " " else -> " " } @@ -638,6 +641,7 @@ private fun previewHomeScreenState( moduleCount: Int = 0, selinuxStatus: String = "Enforcing", ) = HomeUiState( + appName = "KernelSU", kernelVersion = KernelVersion(6, 1, 0), ksuVersion = ksuVersion, lkmMode = lkmMode, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeUiState.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeUiState.kt index b870d5c6bdc0..ef97f4d3c406 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeUiState.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/home/HomeUiState.kt @@ -6,6 +6,8 @@ import me.weishu.kernelsu.ui.util.module.LatestVersionInfo @Immutable data class HomeUiState( + val appName: String, + val classicUi: Boolean = false, val kernelVersion: KernelVersion, val ksuVersion: Int?, val lkmMode: Boolean?, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallMaterial.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallMaterial.kt index da4579c9abb4..694cd8383083 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallMaterial.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallMaterial.kt @@ -87,8 +87,13 @@ internal fun InstallScreenMaterial( state = uiState, onSelected = actions.onSelectMethod, onSelectBootImage = actions.onSelectBootImage, + onSelectAnyKernel = actions.onSelectAnyKernel, ) - + AnimatedVisibility( + visible = uiState.showInstallOptions, + enter = fadeIn() + expandVertically(), + exit = fadeOut() + shrinkVertically() + ) { Column { SegmentedColumn( modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), content = buildList { @@ -190,6 +195,7 @@ internal fun InstallScreenMaterial( } } ) + }} Button( modifier = Modifier .fillMaxWidth() @@ -206,6 +212,7 @@ private fun SelectInstallMethod( state: InstallUiState, onSelected: (InstallMethod) -> Unit, onSelectBootImage: () -> Unit, + onSelectAnyKernel: () -> Unit, ) { val confirmDialog = rememberConfirmDialog( onConfirm = { @@ -221,6 +228,7 @@ private fun SelectInstallMethod( is InstallMethod.SelectFile -> onSelectBootImage() is InstallMethod.DirectInstall -> onSelected(option) is InstallMethod.DirectInstallToInactiveSlot -> confirmDialog.showConfirm(dialogTitle, dialogContent) + is InstallMethod.AnyKernel -> onSelectAnyKernel() } } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallMiuix.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallMiuix.kt index d1d09d80dd94..f0e8532310e7 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallMiuix.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallMiuix.kt @@ -4,6 +4,8 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.interaction.MutableInteractionSource @@ -118,6 +120,7 @@ internal fun InstallScreenMiuix( state = uiState, onSelected = actions.onSelectMethod, onSelectBootImage = actions.onSelectBootImage, + onSelectAnyKernel = actions.onSelectAnyKernel, ) } AnimatedVisibility( @@ -146,6 +149,11 @@ internal fun InstallScreenMiuix( ) } } + AnimatedVisibility( + visible = uiState.showInstallOptions, + enter = fadeIn() + expandVertically(), + exit = fadeOut() + shrinkVertically() + ) { Card( modifier = Modifier .fillMaxWidth() @@ -230,6 +238,7 @@ internal fun InstallScreenMiuix( } } } + } TextButton( modifier = Modifier .fillMaxWidth() @@ -256,6 +265,7 @@ private fun SelectInstallMethod( state: InstallUiState, onSelected: (InstallMethod) -> Unit, onSelectBootImage: () -> Unit, + onSelectAnyKernel: () -> Unit, ) { val confirmDialog = rememberConfirmDialog( onConfirm = { @@ -270,6 +280,7 @@ private fun SelectInstallMethod( is InstallMethod.SelectFile -> onSelectBootImage() is InstallMethod.DirectInstall -> onSelected(option) is InstallMethod.DirectInstallToInactiveSlot -> confirmDialog.showConfirm(dialogTitle, dialogContent) + is InstallMethod.AnyKernel -> onSelectAnyKernel() } } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallScreen.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallScreen.kt index e2ffa3016542..482b0df616ff 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallScreen.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallScreen.kt @@ -63,6 +63,7 @@ fun InstallScreen() { add(InstallMethod.DirectInstall) if (isAbDevice) add(InstallMethod.DirectInstallToInactiveSlot) } + if (rootAvailable) add(InstallMethod.AnyKernel()) } } @@ -87,6 +88,10 @@ fun InstallScreen() { val onInstall = { installMethod?.let { method -> + if (method is InstallMethod.AnyKernel) { + method.uri?.let { uri -> navigator.push(Route.Flash(FlashIt.FlashAnyKernel(uri))) } + return@let + } navigator.push( Route.Flash( FlashIt.FlashBoot( @@ -136,6 +141,13 @@ fun InstallScreen() { } } } + val selectAnyKernelLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult() + ) { + if (it.resultCode == Activity.RESULT_OK) { + it.data?.data?.let { uri -> installMethod = InstallMethod.AnyKernel(uri) } + } + } val state = InstallUiState( installMethod = installMethod, @@ -146,6 +158,7 @@ fun InstallScreen() { slotSuffix = slotSuffix, installMethodOptions = installMethodOptions, canSelectPartition = installMethod is InstallMethod.DirectInstall || installMethod is InstallMethod.DirectInstallToInactiveSlot, + showInstallOptions = installMethod != null && installMethod !is InstallMethod.AnyKernel, advancedOptionsShown = advancedOptionsShown, allowShell = allowShell, enableAdb = enableAdb, @@ -156,6 +169,16 @@ fun InstallScreen() { onSelectBootImage = { selectImageLauncher.launch(Intent(Intent.ACTION_GET_CONTENT).apply { type = "application/octet-stream" }) }, + onSelectAnyKernel = { + selectAnyKernelLauncher.launch(Intent(Intent.ACTION_GET_CONTENT).apply { + type = "application/zip" + putExtra( + Intent.EXTRA_MIME_TYPES, + arrayOf("application/zip", "application/x-zip-compressed", "application/octet-stream") + ) + addCategory(Intent.CATEGORY_OPENABLE) + }) + }, onUploadLkm = { selectLkmLauncher.launch(Intent(Intent.ACTION_GET_CONTENT).apply { type = "application/octet-stream" }) }, @@ -168,7 +191,8 @@ fun InstallScreen() { val isLkmSelected = lkmSelection != LkmSelection.KmiNone val isKmiUnknown = currentKmi.isBlank() val isSelectFileMode = installMethod is InstallMethod.SelectFile - if (!isLkmSelected && (isKmiUnknown || isSelectFileMode)) { + val isAnyKernelMode = installMethod is InstallMethod.AnyKernel + if (!isAnyKernelMode && !isLkmSelected && (isKmiUnknown || isSelectFileMode)) { showChooseKmiDialog.value = true } else { onInstall() diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallUiState.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallUiState.kt index ab0911ccba38..b200484cc3a7 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallUiState.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallUiState.kt @@ -13,6 +13,7 @@ internal data class InstallUiState( val slotSuffix: String, val installMethodOptions: List, val canSelectPartition: Boolean, + val showInstallOptions: Boolean, val advancedOptionsShown: Boolean, val allowShell: Boolean, val enableAdb: Boolean, @@ -23,6 +24,7 @@ internal data class InstallScreenActions( val onBack: () -> Unit, val onSelectMethod: (InstallMethod) -> Unit, val onSelectBootImage: () -> Unit, + val onSelectAnyKernel: () -> Unit, val onUploadLkm: () -> Unit, val onClearLkm: () -> Unit, val onSelectPartition: (Int) -> Unit, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallUtils.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallUtils.kt index f0d210508638..9cc5cb94fc86 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallUtils.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/install/InstallUtils.kt @@ -27,6 +27,12 @@ internal sealed class InstallMethod : Parcelable { get() = R.string.install_inactive_slot } + data class AnyKernel( + val uri: Uri? = null, + override val label: Int = R.string.anykernel_install, + override val summary: String? = null + ) : InstallMethod() + abstract val label: Int @IgnoredOnParcel diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/module/ModuleMaterial.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/module/ModuleMaterial.kt index 661cb3b98278..b4b8cf6c6fc6 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/module/ModuleMaterial.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/module/ModuleMaterial.kt @@ -111,7 +111,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalResources -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.role @@ -133,6 +132,7 @@ import me.weishu.kernelsu.ui.component.material.SearchAppBar import me.weishu.kernelsu.ui.component.material.TonalCard import me.weishu.kernelsu.ui.component.rebootlistpopup.RebootListPopup import me.weishu.kernelsu.ui.component.statustag.StatusTag +import me.weishu.kernelsu.ui.util.AppInfo import me.weishu.kernelsu.ui.util.LocalSnackbarHost import me.weishu.kernelsu.ui.util.reboot @@ -546,7 +546,7 @@ private fun ModuleShortcutSheet( .background(Color.White) ) Image( - painter = painterResource(id = R.drawable.ic_launcher_foreground), + painter = AppInfo.appIconForeground(), contentDescription = null, contentScale = FixedScale(1.5f) ) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/module/ModuleMiuix.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/module/ModuleMiuix.kt index a533400f7949..dab04d0f806e 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/module/ModuleMiuix.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/module/ModuleMiuix.kt @@ -84,7 +84,6 @@ import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.font.FontWeight @@ -110,6 +109,7 @@ import me.weishu.kernelsu.ui.component.miuix.SearchPager import me.weishu.kernelsu.ui.component.rebootlistpopup.RebootListPopupMiuix import me.weishu.kernelsu.ui.theme.LocalEnableBlur import me.weishu.kernelsu.ui.theme.isInDarkTheme +import me.weishu.kernelsu.ui.util.AppInfo import me.weishu.kernelsu.ui.util.BlurredBar import me.weishu.kernelsu.ui.util.getFileName import me.weishu.kernelsu.ui.util.rememberBlurBackdrop @@ -602,7 +602,7 @@ private fun ModuleShortcutDialog( .background(Color.White) ) Image( - painter = painterResource(id = R.drawable.ic_launcher_foreground), + painter = AppInfo.appIconForeground(), contentDescription = null, contentScale = FixedScale(1.5f) ) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsMaterial.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsMaterial.kt index 2a69f43c1ad4..b88a04b48080 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsMaterial.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsMaterial.kt @@ -15,9 +15,11 @@ import androidx.compose.material.icons.automirrored.filled.Article import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.Adb import androidx.compose.material.icons.filled.BugReport +import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.ContactPage import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.DeveloperMode +import androidx.compose.material.icons.filled.EditNote import androidx.compose.material.icons.filled.ElectricalServices import androidx.compose.material.icons.filled.Fence import androidx.compose.material.icons.filled.FolderDelete @@ -97,15 +99,15 @@ fun SettingPagerMaterial( SegmentedColumn( modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), content = listOf( - { - SegmentedSwitchItem( - icon = Icons.Filled.Update, - title = stringResource(id = R.string.settings_check_update), - summary = stringResource(id = R.string.settings_check_update_summary), - checked = uiState.checkUpdate, - onCheckedChange = actions.onSetCheckUpdate - ) - }, +// { +// SegmentedSwitchItem( +// icon = Icons.Filled.Update, +// title = stringResource(id = R.string.settings_check_update), +// summary = stringResource(id = R.string.settings_check_update_summary), +// checked = uiState.checkUpdate, +// onCheckedChange = actions.onSetCheckUpdate +// ) +// }, { SegmentedSwitchItem( icon = Icons.Rounded.UploadFile, @@ -170,6 +172,56 @@ fun SettingPagerMaterial( ) } + if (uiState.isToolkitInstalled || uiState.isKpatchNextInstalled) KsuIsValid { + SegmentedColumn( + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + content = buildList { + if (uiState.isToolkitInstalled) add { + SegmentedListItem( + onClick = { + actions.onOpenWebUi("ksu_toolkit", "KernelSU Toolkit") + }, + headlineContent = { Text(stringResource(R.string.settings_kernelsu_toolkit)) }, + supportingContent = { Text(stringResource(R.string.settings_kernelsu_toolkit_summary)) }, + leadingContent = { + Icon( + Icons.Filled.Build, + stringResource(R.string.settings_kernelsu_toolkit) + ) + }, + trailingContent = { + Icon( + Icons.AutoMirrored.Filled.KeyboardArrowRight, + null + ) + } + ) + } + if (uiState.isKpatchNextInstalled) add { + SegmentedListItem( + onClick = { + actions.onOpenWebUi("KPatch-Next", "KPatch-Next") + }, + headlineContent = { Text(stringResource(R.string.settings_kpatch_next)) }, + supportingContent = { Text(stringResource(R.string.settings_kpatch_next_summary)) }, + leadingContent = { + Icon( + Icons.Filled.Build, + stringResource(R.string.settings_kpatch_next) + ) + }, + trailingContent = { + Icon( + Icons.AutoMirrored.Filled.KeyboardArrowRight, + null + ) + } + ) + } + } + ) + } + KsuIsValid { val suCompatModeItems = listOf( stringResource(id = R.string.settings_mode_enable_by_default), @@ -241,6 +293,21 @@ fun SettingPagerMaterial( onCheckedChange = actions.onSetAdbRootEnabled ) }, + { + val avcSpoofSummary = when (uiState.avcSpoofStatus) { + "unsupported" -> stringResource(id = R.string.feature_status_unsupported_summary) + "managed" -> stringResource(id = R.string.feature_status_managed_summary) + else -> stringResource(id = R.string.settings_avc_spoof_summary) + } + SegmentedSwitchItem( + icon = Icons.Filled.EditNote, + title = stringResource(id = R.string.settings_avc_spoof), + summary = avcSpoofSummary, + enabled = uiState.avcSpoofStatus == "supported", + checked = uiState.isAvcSpoofEnabled, + onCheckedChange = actions.onSetAvcSpoofEnabled + ) + }, ) ) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsMiuix.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsMiuix.kt index 722b5dd418e5..c9f6310b2156 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsMiuix.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsMiuix.kt @@ -15,12 +15,14 @@ import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.rounded.Article +import androidx.compose.material.icons.rounded.Build import androidx.compose.material.icons.rounded.Adb import androidx.compose.material.icons.rounded.BugReport import androidx.compose.material.icons.rounded.ContactPage import androidx.compose.material.icons.rounded.Dashboard import androidx.compose.material.icons.rounded.Delete import androidx.compose.material.icons.rounded.DeveloperMode +import androidx.compose.material.icons.rounded.EditNote import androidx.compose.material.icons.rounded.ElectricalServices import androidx.compose.material.icons.rounded.Fence import androidx.compose.material.icons.rounded.FolderDelete @@ -109,20 +111,20 @@ fun SettingPagerMiuix( .padding(top = 12.dp) .fillMaxWidth(), ) { - SwitchPreference( - title = stringResource(id = R.string.settings_check_update), - summary = stringResource(id = R.string.settings_check_update_summary), - startAction = { - Icon( - Icons.Rounded.Update, - modifier = Modifier.padding(end = 6.dp), - contentDescription = stringResource(id = R.string.settings_check_update), - tint = colorScheme.onBackground - ) - }, - checked = uiState.checkUpdate, - onCheckedChange = actions.onSetCheckUpdate - ) +// SwitchPreference( +// title = stringResource(id = R.string.settings_check_update), +// summary = stringResource(id = R.string.settings_check_update_summary), +// startAction = { +// Icon( +// Icons.Rounded.Update, +// modifier = Modifier.padding(end = 6.dp), +// contentDescription = stringResource(id = R.string.settings_check_update), +// tint = colorScheme.onBackground +// ) +// }, +// checked = uiState.checkUpdate, +// onCheckedChange = actions.onSetCheckUpdate +// ) KsuIsValid { SwitchPreference( title = stringResource(id = R.string.settings_module_check_update), @@ -199,6 +201,49 @@ fun SettingPagerMiuix( } } + if (uiState.isToolkitInstalled || uiState.isKpatchNextInstalled) KsuIsValid { + Card( + modifier = Modifier + .padding(top = 12.dp) + .fillMaxWidth(), + ) { + if (uiState.isToolkitInstalled) { + ArrowPreference( + title = stringResource(R.string.settings_kernelsu_toolkit), + summary = stringResource(R.string.settings_kernelsu_toolkit_summary), + startAction = { + Icon( + Icons.Rounded.Build, + modifier = Modifier.padding(end = 6.dp), + contentDescription = stringResource(id = R.string.settings_kernelsu_toolkit), + tint = colorScheme.onBackground + ) + }, + onClick = { + actions.onOpenWebUi("ksu_toolkit", "KernelSU Toolkit") + } + ) + } + if (uiState.isKpatchNextInstalled) { + ArrowPreference( + title = stringResource(R.string.settings_kpatch_next), + summary = stringResource(R.string.settings_kpatch_next_summary), + startAction = { + Icon( + Icons.Rounded.Build, + modifier = Modifier.padding(end = 6.dp), + contentDescription = stringResource(id = R.string.settings_kpatch_next), + tint = colorScheme.onBackground + ) + }, + onClick = { + actions.onOpenWebUi("KPatch-Next", "KPatch-Next") + } + ) + } + } + } + KsuIsValid { Card( modifier = Modifier @@ -295,6 +340,27 @@ fun SettingPagerMiuix( checked = uiState.isAdbRootEnabled, onCheckedChange = actions.onSetAdbRootEnabled ) + + val avcSpoofSummary = when (uiState.avcSpoofStatus) { + "unsupported" -> stringResource(id = R.string.feature_status_unsupported_summary) + "managed" -> stringResource(id = R.string.feature_status_managed_summary) + else -> stringResource(id = R.string.settings_avc_spoof_summary) + } + SwitchPreference( + title = stringResource(id = R.string.settings_avc_spoof), + summary = avcSpoofSummary, + startAction = { + Icon( + Icons.Rounded.EditNote, + modifier = Modifier.padding(end = 6.dp), + contentDescription = stringResource(id = R.string.settings_avc_spoof), + tint = colorScheme.onBackground + ) + }, + enabled = uiState.avcSpoofStatus == "supported", + checked = uiState.isAvcSpoofEnabled, + onCheckedChange = actions.onSetAvcSpoofEnabled + ) } Card( diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsScreen.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsScreen.kt index 38d9a866c870..3c64e625a00b 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsScreen.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsScreen.kt @@ -1,9 +1,14 @@ package me.weishu.kernelsu.ui.screen.settings +import android.content.Intent +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.Dp import androidx.lifecycle.compose.LifecycleResumeEffect +import androidx.core.net.toUri import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import me.weishu.kernelsu.ui.LocalUiMode @@ -11,14 +16,19 @@ import me.weishu.kernelsu.ui.UiMode import me.weishu.kernelsu.ui.navigation3.Navigator import me.weishu.kernelsu.ui.navigation3.Route import me.weishu.kernelsu.ui.viewmodel.SettingsViewModel +import me.weishu.kernelsu.ui.webui.WebUIActivity @Composable fun SettingPager( navigator: Navigator, bottomInnerPadding: Dp ) { + val context = LocalContext.current val viewModel = viewModel() val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val webUILauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult() + ) { } LifecycleResumeEffect(Unit) { viewModel.refresh() @@ -37,9 +47,18 @@ fun SettingPager( onSetKernelUmountEnabled = viewModel::setKernelUmountEnabled, onSetSulogEnabled = viewModel::setSulogEnabled, onSetAdbRootEnabled = viewModel::setAdbRootEnabled, + onSetAvcSpoofEnabled = viewModel::setAvcSpoofEnabled, onSetDefaultUmountModules = viewModel::setDefaultUmountModules, onSetEnableWebDebugging = viewModel::setEnableWebDebugging, onSetAutoJailbreak = viewModel::setAutoJailbreak, + onOpenWebUi = { id, name -> + webUILauncher.launch( + Intent(context, WebUIActivity::class.java) + .setData("kernelsu://webui/$id".toUri()) + .putExtra("id", id) + .putExtra("name", name) + ) + }, onOpenAbout = { navigator.push(Route.About) }, ) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsUiState.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsUiState.kt index a154129bc913..374b7363e952 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsUiState.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/settings/SettingsUiState.kt @@ -15,7 +15,11 @@ data class SettingsUiState( val keyColor: Int = 0, val colorStyle: String = PaletteStyle.TonalSpot.name, val colorSpec: String = ColorSpec.SpecVersion.Default.name, - val enablePredictiveBack: Boolean = false, + val enableOfficialLauncher: Boolean = false, + val classicUi: Boolean = false, + val showSwitchIcon: Boolean = false, + val scrollAnimation: Boolean = false, + val enablePredictiveBack: Boolean = true, val enableBlur: Boolean = true, val enableFloatingBottomBar: Boolean = false, val enableFloatingBottomBarBlur: Boolean = false, @@ -23,6 +27,10 @@ data class SettingsUiState( val enableWebDebugging: Boolean = false, val enableSmoothCorner: Boolean = true, + // WebUI Modules shortcut entry + val isToolkitInstalled: Boolean = false, + val isKpatchNextInstalled: Boolean = false, + // Su Compat val suCompatStatus: String = "", val suCompatMode: Int = 0, // 0: enable default, 1: disable until reboot, 2: disable always @@ -36,6 +44,10 @@ data class SettingsUiState( val sulogStatus: String = "", val isSulogEnabled: Boolean = false, + // Avc spoof + val avcSpoofStatus: String = "", + val isAvcSpoofEnabled: Boolean = true, + // Umount Modules val isDefaultUmountModules: Boolean = false, @@ -61,8 +73,10 @@ data class SettingsScreenActions( val onSetKernelUmountEnabled: (Boolean) -> Unit, val onSetSulogEnabled: (Boolean) -> Unit, val onSetAdbRootEnabled: (Boolean) -> Unit, + val onSetAvcSpoofEnabled: (Boolean) -> Unit, val onSetDefaultUmountModules: (Boolean) -> Unit, val onSetEnableWebDebugging: (Boolean) -> Unit, val onSetAutoJailbreak: (Boolean) -> Unit, + val onOpenWebUi: (String, String) -> Unit, val onOpenAbout: () -> Unit, ) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/MaterialTheme.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/MaterialTheme.kt index e40bb32266f4..1e0ab21655ff 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/MaterialTheme.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/MaterialTheme.kt @@ -1,12 +1,15 @@ package me.weishu.kernelsu.ui.theme import android.app.Activity +import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialExpressiveTheme import androidx.compose.material3.MotionScheme +import androidx.compose.material3.darkColorScheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.expressiveLightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.graphics.Color @@ -30,9 +33,14 @@ fun MaterialKernelSUTheme( val colorSpec = appSettings.colorSpec val colorScheme = if (dynamicColor) { - val baseScheme = if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + val baseScheme = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + else -> + if (darkTheme) darkColorScheme() else expressiveLightColorScheme() + } rememberDynamicColorScheme( - seedColor = Color.Unspecified, + seedColor = baseScheme.primary, isDark = darkTheme, isAmoled = amoledMode, style = colorStyle, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt index 242457fc6618..e2e61314d183 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/theme/Theme.kt @@ -3,6 +3,7 @@ package me.weishu.kernelsu.ui.theme import android.content.Context import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.platform.LocalContext @@ -10,6 +11,8 @@ import com.materialkolor.PaletteStyle import com.materialkolor.dynamiccolor.ColorSpec import me.weishu.kernelsu.ui.LocalUiMode import me.weishu.kernelsu.ui.UiMode +import me.weishu.kernelsu.ui.util.LocalScrollAnimation +import me.weishu.kernelsu.ui.util.LocalShowSwitchIcon enum class ColorMode(val value: Int) { SYSTEM(0), @@ -50,6 +53,10 @@ data class AppSettings( val paletteStyle: PaletteStyle, val colorSpec: ColorSpec.SpecVersion, val enableSmoothCorner: Boolean, + val enableOfficialLauncher: Boolean, + val classicUi: Boolean, + val showSwitchIcon: Boolean, + val scrollAnimation: Boolean, ) object ThemeController { @@ -86,8 +93,12 @@ object ThemeController { } val enableSmoothCorner = prefs.getBoolean("enable_smooth_corner", true) + val enableOfficialLauncher = prefs.getBoolean("enable_official_launcher", false) + val classicUi = prefs.getBoolean("classic_ui", false) + val showSwitchIcon = prefs.getBoolean("show_switch_icon", false) + val scrollAnimation = prefs.getBoolean("scroll_animation", false) - return AppSettings(colorMode, keyColor, paletteStyle, colorSpec, enableSmoothCorner) + return AppSettings(colorMode, keyColor, paletteStyle, colorSpec, enableSmoothCorner, enableOfficialLauncher, classicUi, showSwitchIcon, scrollAnimation) } } @@ -100,16 +111,24 @@ fun KernelSUTheme( val context = LocalContext.current val currentAppSettings = appSettings ?: ThemeController.getAppSettings(context) - when (uiMode) { - UiMode.Miuix -> MiuixKernelSUTheme( - appSettings = currentAppSettings, - content = content - ) - - UiMode.Material -> MaterialKernelSUTheme( - appSettings = currentAppSettings, - content = content - ) + CompositionLocalProvider( + LocalColorMode provides currentAppSettings.colorMode.value, + LocalEnableOfficialLauncher provides currentAppSettings.enableOfficialLauncher, + LocalClassicUi provides currentAppSettings.classicUi, + LocalShowSwitchIcon provides currentAppSettings.showSwitchIcon, + LocalScrollAnimation provides currentAppSettings.scrollAnimation, + ) { + when (uiMode) { + UiMode.Miuix -> MiuixKernelSUTheme( + appSettings = currentAppSettings, + content = content + ) + + UiMode.Material -> MaterialKernelSUTheme( + appSettings = currentAppSettings, + content = content + ) + } } } @@ -126,6 +145,10 @@ fun isInDarkTheme(): Boolean { val LocalColorMode = staticCompositionLocalOf { 0 } +val LocalEnableOfficialLauncher = staticCompositionLocalOf { false } + +val LocalClassicUi = staticCompositionLocalOf { false } + val LocalEnableBlur = staticCompositionLocalOf { false } val LocalEnableFloatingBottomBar = staticCompositionLocalOf { false } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/AppInfo.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/AppInfo.kt new file mode 100644 index 000000000000..ad36919357a0 --- /dev/null +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/AppInfo.kt @@ -0,0 +1,39 @@ +package me.weishu.kernelsu.ui.util + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import me.weishu.kernelsu.R +import me.weishu.kernelsu.ui.theme.LocalEnableOfficialLauncher + +object AppInfo { + @Composable + fun appName(): String { + return if (LocalEnableOfficialLauncher.current) { + stringResource(R.string.app_name) + } else { + stringResource(R.string.app_name_kowsu) + } + } + + @Composable + fun appIconRes(): Int { + return if (LocalEnableOfficialLauncher.current) { + R.drawable.ic_launcher_foreground + } else { + R.drawable.ic_launcher_kowsu + } + } + + @Composable + fun appIconForeground() = painterResource(id = appIconRes()) + + @Composable + fun appIconMonochrome() = painterResource( + id = if (LocalEnableOfficialLauncher.current) { + R.drawable.ic_launcher_monochrome + } else { + R.drawable.ic_launcher_kowsu + } + ) +} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/CompositionProvider.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/CompositionProvider.kt index 29279ebd8316..1a0afa7dfed0 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/CompositionProvider.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/CompositionProvider.kt @@ -6,3 +6,7 @@ import androidx.compose.runtime.compositionLocalOf val LocalSnackbarHost = compositionLocalOf { error("CompositionLocal LocalSnackbarHost not present") } + +val LocalShowSwitchIcon = compositionLocalOf { false } + +val LocalScrollAnimation = compositionLocalOf { false } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/DownloadManager.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/DownloadManager.kt index a2b9097de11b..fd831473ed5b 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/DownloadManager.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/DownloadManager.kt @@ -21,6 +21,9 @@ object DownloadManager { val id: Int, val fileName: String, val url: String, + val targetPath: String? = null, + val mimeType: String? = null, + val completionAction: DownloadCompletionAction = DownloadCompletionAction.INSTALL_MODULE, val progress: Int = 0, val status: Status = Status.PENDING, val resultUri: Uri? = null, @@ -34,19 +37,54 @@ object DownloadManager { private val completionCallbacks = ConcurrentHashMap Unit>() private val mainHandler = Handler(Looper.getMainLooper()) + internal fun registerLocalSave( + fileName: String, + targetPath: String, + mimeType: String? = null, + completionAction: DownloadCompletionAction = DownloadCompletionAction.OPEN_FILE, + ): Int { + val id = idCounter.incrementAndGet() + val state = DownloadState( + id = id, + fileName = fileName, + url = targetPath, + targetPath = targetPath, + mimeType = mimeType, + completionAction = completionAction, + ) + _downloads.update { it + (id to state) } + return id + } + fun enqueue( context: Context, url: String, fileName: String, + targetPath: String? = null, + mimeType: String? = null, + cookie: String? = null, + userAgent: String? = null, + completionAction: DownloadCompletionAction = DownloadCompletionAction.INSTALL_MODULE, onCompleted: ((Uri) -> Unit)? = null, ): Int { val existing = _downloads.value.values.find { - it.url == url && (it.status == Status.PENDING || it.status == Status.DOWNLOADING) + it.url == url && + it.fileName == fileName && + it.targetPath == targetPath && + it.completionAction == completionAction && + (it.status == Status.PENDING || it.status == Status.DOWNLOADING) } if (existing != null) return existing.id val id = idCounter.incrementAndGet() - val state = DownloadState(id = id, fileName = fileName, url = url) + val state = DownloadState( + id = id, + fileName = fileName, + url = url, + targetPath = targetPath, + mimeType = mimeType, + completionAction = completionAction, + ) _downloads.update { it + (id to state) } if (onCompleted != null) { @@ -58,6 +96,11 @@ object DownloadManager { putExtra(DownloadService.EXTRA_DOWNLOAD_ID, id) putExtra(DownloadService.EXTRA_URL, url) putExtra(DownloadService.EXTRA_FILE_NAME, fileName) + putExtra(DownloadService.EXTRA_TARGET_PATH, targetPath) + putExtra(DownloadService.EXTRA_MIME_TYPE, mimeType) + putExtra(DownloadService.EXTRA_COOKIE, cookie) + putExtra(DownloadService.EXTRA_USER_AGENT, userAgent) + putExtra(DownloadService.EXTRA_COMPLETION_ACTION, completionAction.name) } ContextCompat.startForegroundService(context, intent) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/DownloadService.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/DownloadService.kt index 419e9171baff..c62dfec92d7a 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/DownloadService.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/DownloadService.kt @@ -11,6 +11,7 @@ import android.os.Build import android.os.Environment import android.os.IBinder import androidx.core.app.NotificationCompat +import androidx.core.content.FileProvider import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -18,6 +19,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.launch +import me.weishu.kernelsu.BuildConfig import me.weishu.kernelsu.R import me.weishu.kernelsu.ksuApp import me.weishu.kernelsu.ui.MainActivity @@ -25,8 +27,23 @@ import okhttp3.Request import java.io.File import java.io.FileOutputStream import java.io.IOException +import java.net.URLConnection import java.util.concurrent.ConcurrentHashMap +enum class DownloadCompletionAction { + INSTALL_MODULE, + OPEN_FILE, +} + +internal fun resolveDownloadMimeType(fileName: String, providedMimeType: String?): String { + val explicitMimeType = providedMimeType?.trim().orEmpty() + if (explicitMimeType.isNotEmpty()) { + return explicitMimeType + } + + return URLConnection.guessContentTypeFromName(fileName) ?: "application/octet-stream" +} + class DownloadService : Service() { companion object { @@ -40,6 +57,12 @@ class DownloadService : Service() { const val EXTRA_DOWNLOAD_ID = "downloadId" const val EXTRA_MODULE_URI = "moduleUri" const val EXTRA_FILE_PATH = "filePath" + const val EXTRA_TARGET_PATH = "targetPath" + const val EXTRA_MIME_TYPE = "mimeType" + const val EXTRA_COOKIE = "cookie" + const val EXTRA_USER_AGENT = "userAgent" + const val EXTRA_COMPLETION_ACTION = "completionAction" + const val EXTRA_DELETE_FILE_ON_DISMISS = "deleteFileOnDismiss" private const val COMPLETION_NOTIFICATION_ID_BASE = 100000 } @@ -62,6 +85,13 @@ class DownloadService : Service() { val url = intent.getStringExtra(EXTRA_URL) ?: return START_NOT_STICKY val fileName = intent.getStringExtra(EXTRA_FILE_NAME) ?: return START_NOT_STICKY val downloadId = intent.getIntExtra(EXTRA_DOWNLOAD_ID, -1) + val targetPath = intent.getStringExtra(EXTRA_TARGET_PATH) + val mimeType = intent.getStringExtra(EXTRA_MIME_TYPE) + val cookie = intent.getStringExtra(EXTRA_COOKIE) + val userAgent = intent.getStringExtra(EXTRA_USER_AGENT) + val completionAction = intent.getStringExtra(EXTRA_COMPLETION_ACTION) + ?.let(DownloadCompletionAction::valueOf) + ?: DownloadCompletionAction.INSTALL_MODULE if (downloadId == -1) return START_NOT_STICKY val notification = buildProgressNotification(downloadId, fileName, 0) @@ -74,7 +104,7 @@ class DownloadService : Service() { startForeground(downloadId, notification) } - startDownload(downloadId, url, fileName) + startDownload(downloadId, url, fileName, targetPath, mimeType, cookie, userAgent, completionAction) } ACTION_CANCEL -> { @@ -91,10 +121,11 @@ class DownloadService : Service() { ACTION_DISMISS_DOWNLOAD -> { val downloadId = intent.getIntExtra(EXTRA_DOWNLOAD_ID, -1) val filePath = intent.getStringExtra(EXTRA_FILE_PATH) + val deleteFileOnDismiss = intent.getBooleanExtra(EXTRA_DELETE_FILE_ON_DISMISS, false) if (downloadId != -1) { notificationManager.cancel(COMPLETION_NOTIFICATION_ID_BASE + downloadId) } - if (!filePath.isNullOrEmpty()) { + if (deleteFileOnDismiss && !filePath.isNullOrEmpty()) { File(filePath).delete() } } @@ -102,16 +133,34 @@ class DownloadService : Service() { return START_NOT_STICKY } - private fun startDownload(id: Int, url: String, fileName: String) { + private fun startDownload( + id: Int, + url: String, + fileName: String, + targetPath: String?, + mimeType: String?, + cookie: String?, + userAgent: String?, + completionAction: DownloadCompletionAction, + ) { val job = serviceScope.launch { try { - val target = File( + val target = targetPath?.let(::File) ?: File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName ) target.parentFile?.mkdirs() - ksuApp.okhttpClient.newCall(Request.Builder().url(url).build()).execute() + val request = Request.Builder().url(url).apply { + if (!cookie.isNullOrEmpty()) { + addHeader("Cookie", cookie) + } + if (!userAgent.isNullOrEmpty()) { + addHeader("User-Agent", userAgent) + } + }.build() + + ksuApp.okhttpClient.newCall(request).execute() .use { resp -> if (!resp.isSuccessful) throw IOException("HTTP ${resp.code}") val body = resp.body @@ -153,7 +202,7 @@ class DownloadService : Service() { notificationManager.cancel(id) notificationManager.notify( COMPLETION_NOTIFICATION_ID_BASE + id, - buildCompletionNotification(id, fileName, uri) + buildCompletionNotification(id, fileName, target, uri, mimeType, completionAction) ) } catch (e: CancellationException) { throw e @@ -194,7 +243,10 @@ class DownloadService : Service() { private fun buildCompletionNotification( id: Int, fileName: String, - uri: Uri + targetFile: File, + uri: Uri, + mimeType: String?, + completionAction: DownloadCompletionAction, ): android.app.Notification { val builder = NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle(getString(R.string.download_complete_title)) @@ -202,36 +254,64 @@ class DownloadService : Service() { .setSmallIcon(android.R.drawable.stat_sys_download_done) .setAutoCancel(true) - // Add "Install" action button - val installIntent = Intent(this, MainActivity::class.java).apply { - action = ACTION_INSTALL_MODULE - putExtra(EXTRA_MODULE_URI, uri.toString()) - putExtra(EXTRA_DOWNLOAD_ID, id) - addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) - } - val installPendingIntent = PendingIntent.getActivity( - this, - id, - installIntent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - builder.addAction( - android.R.drawable.ic_menu_save, - getString(R.string.download_install), - installPendingIntent - ) - builder.setContentIntent(installPendingIntent) + val deleteFileOnDismiss = completionAction == DownloadCompletionAction.INSTALL_MODULE - // Add "Cancel" action button - val dismissIntent = Intent(this, DownloadService::class.java).apply { - action = ACTION_DISMISS_DOWNLOAD - putExtra(EXTRA_DOWNLOAD_ID, id) - putExtra(EXTRA_FILE_PATH, uri.path) + val primaryPendingIntent = when (completionAction) { + DownloadCompletionAction.INSTALL_MODULE -> PendingIntent.getActivity( + this, + id, + Intent(this, MainActivity::class.java).apply { + action = ACTION_INSTALL_MODULE + putExtra(EXTRA_MODULE_URI, uri.toString()) + putExtra(EXTRA_DOWNLOAD_ID, id) + addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + }, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ).also { pendingIntent -> + builder.addAction( + android.R.drawable.ic_menu_save, + getString(R.string.download_install), + pendingIntent + ) + } + + DownloadCompletionAction.OPEN_FILE -> PendingIntent.getActivity( + this, + id, + Intent.createChooser( + Intent(Intent.ACTION_VIEW).apply { + val contentUri = FileProvider.getUriForFile( + this@DownloadService, + "${BuildConfig.APPLICATION_ID}.fileprovider", + targetFile + ) + setDataAndType(contentUri, resolveDownloadMimeType(fileName, mimeType)) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + }, + getString(R.string.open) + ).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + }, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ).also { pendingIntent -> + builder.addAction( + android.R.drawable.ic_menu_view, + getString(R.string.open), + pendingIntent + ) + } } + builder.setContentIntent(primaryPendingIntent) + val dismissPendingIntent = PendingIntent.getService( this, COMPLETION_NOTIFICATION_ID_BASE + id, - dismissIntent, + Intent(this, DownloadService::class.java).apply { + action = ACTION_DISMISS_DOWNLOAD + putExtra(EXTRA_DOWNLOAD_ID, id) + putExtra(EXTRA_FILE_PATH, targetFile.absolutePath) + putExtra(EXTRA_DELETE_FILE_ON_DISMISS, deleteFileOnDismiss) + }, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) builder.addAction( @@ -273,7 +353,7 @@ class DownloadService : Service() { } private fun stopForegroundIfIdle() { - if (activeJobs.isEmpty() || activeJobs.values.none { it.isActive }) { + if (activeJobs.isEmpty()) { stopForeground(STOP_FOREGROUND_REMOVE) stopSelf() } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt index 32d785c0b9cf..3c944d9b5814 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt @@ -13,6 +13,7 @@ import android.util.Log import com.topjohnwu.superuser.CallbackList import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils +import com.topjohnwu.superuser.io.SuFile import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize @@ -21,12 +22,16 @@ import me.weishu.kernelsu.Natives import me.weishu.kernelsu.ksuApp import org.json.JSONArray import java.io.File +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale /** * @author weishu * @date 2023/1/1. */ private const val TAG = "KsuCli" +private const val BUSYBOX = "/data/adb/ksu/bin/busybox" private fun getKsuDaemonPath(): String { return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libksud.so" @@ -169,6 +174,52 @@ fun uninstallModule(id: String): Boolean { return result } +private fun processUiPrintLine(s: String?): Pair { + if (s == null) { + return Pair(1,null) + } + + val check1 = s.startsWith("ui_print") + val trimmed = s.trim() + val check2 = trimmed.startsWith("ui_print") + if (!check1 && check2) return Pair(1,null) + + return if(check1) { + Pair(1,trimmed.drop(8).dropWhile { it.isWhitespace() }) + } + else { + Pair(2, trimmed) + } +} + +private fun flashWithIoAk3( + cmd: String, + onStdout: (String) -> Unit, + onStderr: (String) -> Unit +): Shell.Result { + + val stdoutCallback: CallbackList = object : CallbackList() { + override fun onAddElement(s: String?) { + val (type, text) = processUiPrintLine(s) + if(type == 1) { + text?.let(onStdout) + } else { + text?.let(onStderr) + } + } + } + + val stderrCallback: CallbackList = object : CallbackList() { + override fun onAddElement(s: String?) { + onStderr(s ?: "") + } + } + + return withNewRootShell { + newJob().add(cmd).to(stdoutCallback, stderrCallback).exec() + } +} + private fun flashWithIO( cmd: String, onStdout: (String) -> Unit, @@ -371,6 +422,54 @@ fun reboot(reason: String = "") { ShellUtils.fastCmd(shell, "/system/bin/svc power reboot $reason || /system/bin/reboot $reason") } +fun flashAnyKernelZip( + uri: Uri, + onStdout: (String) -> Unit, + onStderr: (String) -> Unit +): FlashResult { + val resolver = ksuApp.contentResolver + + val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) + val tmpFile = File(ksuApp.cacheDir, "anykernel_${timestamp}.zip") + resolver.openInputStream(uri).use { input -> + tmpFile.outputStream().use { out -> + input?.copyTo(out) + } + } + + val destZip = tmpFile.absolutePath + val destZipName = File(destZip).name + val destDirFile = File(ksuApp.cacheDir, "anykernel3_${timestamp}") + val destDir = destDirFile.absolutePath + + val cmd = """ + mkdir -p '$destDir' && \ + $BUSYBOX unzip -p -o '$destZip' "META-INF/com/google/android/update-binary" > '$destDir/update-binary' 2>/dev/null && \ + cp '$destZip' '$destDir/$destZipName' 2>/dev/null || true && \ + $BUSYBOX chmod 755 '$destDir/update-binary' && \ + $BUSYBOX chown root:root '$destDir/update-binary' && \ + (cd '$destDir' && \ + if [ -f './update-binary' ] && grep -q "AnyKernel3" './update-binary'; then \ + AKHOME='$destDir/tmp' $BUSYBOX ash '$destDir/update-binary' 3 1 '$destDir/$destZipName'; \ + else \ + echo 'No installer script found' >&2; exit 1; \ + fi) + """.trimIndent().replace(Regex("\\s+\\\\\\s*"), " ") + + val result = flashWithIoAk3(cmd, onStdout, onStderr) + try { + return FlashResult(result, result.isSuccess) + } finally { + try { + runCatching { + createRootShell(true).use { sh -> + sh.newJob().add("rm -rf '$destDir' '$destZip'").exec() + } + } + } catch (_: Throwable) { } + } +} + fun rootAvailable(): Boolean { val shell = getRootShell() return shell.isRoot @@ -504,3 +603,7 @@ fun restartApp(packageName: String, userId: Int? = null) { forceStopApp(packageName, userId) launchApp(packageName, userId) } + +fun isWebuiModuleInstalled(modId: String): Boolean { + return SuFile("/data/adb/modules/$modId/webroot/index.html").exists() +} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/Shortcut.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/Shortcut.kt index f2e7338ef540..be608f3ec95e 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/Shortcut.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/module/Shortcut.kt @@ -1,16 +1,20 @@ package me.weishu.kernelsu.ui.util.module import android.app.AppOpsManager +import android.content.ComponentName import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.graphics.BitmapFactory +import android.graphics.Canvas import android.net.Uri import android.provider.Settings import android.util.Log import android.widget.Toast +import androidx.core.content.ContextCompat import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat +import androidx.core.graphics.createBitmap import androidx.core.graphics.drawable.IconCompat import androidx.core.graphics.scale import androidx.core.net.toUri @@ -35,7 +39,8 @@ object Shortcut { iconUri: String? ) { val shortcutId = "module_action_$moduleId" - val shortcutIntent = Intent(context, MainActivity::class.java).apply { + val shortcutIntent = Intent().apply { + component = getLauncherComponent(context) action = Intent.ACTION_VIEW putExtra("shortcut_type", "module_action") putExtra("module_id", moduleId) @@ -90,7 +95,7 @@ object Shortcut { Log.d(TAG, "$logPrefix: shortcutId=$shortcutId, hasPinned=$hasPinned") val iconCompat = createShortcutIcon(context, iconUri) - val finalIcon = iconCompat ?: IconCompat.createWithResource(context, R.mipmap.ic_launcher) + val finalIcon = iconCompat ?: getDefaultIconBitmap(context)?.let { IconCompat.createWithBitmap(it) } val shortcut = ShortcutInfoCompat.Builder(context, shortcutId) .setShortLabel(name) @@ -275,6 +280,32 @@ object Shortcut { } } + fun getDefaultIconBitmap(context: Context): Bitmap? { + val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE) + val isOfficial = prefs.getBoolean("enable_official_launcher", false) + val resId = if (isOfficial) R.mipmap.ic_launcher_official else R.mipmap.ic_launcher_kowsu + return getBitmapFromVectorDrawable(context, resId) + } + + fun getLauncherComponent(context: Context): ComponentName { + val prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE) + val isOfficial = prefs.getBoolean("enable_official_launcher", false) + return if (isOfficial) { + ComponentName(context, "me.weishu.kernelsu.MainActivityOfficial") + } else { + ComponentName(context, MainActivity::class.java) + } + } + + private fun getBitmapFromVectorDrawable(context: Context, drawableId: Int): Bitmap? { + val drawable = ContextCompat.getDrawable(context, drawableId) ?: return null + val bitmap = createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight) + val canvas = Canvas(bitmap) + drawable.setBounds(0, 0, canvas.width, canvas.height) + drawable.draw(canvas) + return bitmap + } + private enum class ShortcutPermissionState { Granted, Denied, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/HomeViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/HomeViewModel.kt index e47b8d441b8a..e4ff13d5ed44 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/HomeViewModel.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/HomeViewModel.kt @@ -1,81 +1,106 @@ -package me.weishu.kernelsu.ui.viewmodel - -import android.content.Context -import android.os.Build -import android.system.Os -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import me.weishu.kernelsu.BuildConfig -import me.weishu.kernelsu.Natives -import me.weishu.kernelsu.getKernelVersion -import me.weishu.kernelsu.ksuApp -import me.weishu.kernelsu.ui.screen.home.HomeUiState -import me.weishu.kernelsu.ui.screen.home.SystemInfo -import me.weishu.kernelsu.ui.screen.home.getManagerVersion -import me.weishu.kernelsu.ui.util.checkNewVersion -import me.weishu.kernelsu.ui.util.getModuleCount -import me.weishu.kernelsu.ui.util.getSELinuxStatusRaw -import me.weishu.kernelsu.ui.util.getSuperuserCount -import me.weishu.kernelsu.ui.util.module.LatestVersionInfo -import me.weishu.kernelsu.ui.util.rootAvailable - -class HomeViewModel : ViewModel() { - - private val _uiState = MutableStateFlow(buildState()) - val uiState: StateFlow = _uiState.asStateFlow() - - fun refresh() { - viewModelScope.launch { - val baseState = withContext(Dispatchers.IO) { buildState() } - _uiState.update { baseState } - if (baseState.checkUpdateEnabled) { - val latestVersionInfo = withContext(Dispatchers.IO) { checkNewVersion() } - _uiState.update { it.copy(latestVersionInfo = latestVersionInfo) } - } - } - } - - private fun buildState(): HomeUiState { - val kernelVersion = getKernelVersion() - val isManager = Natives.isManager - val ksuVersion = if (isManager) Natives.version else null - val lkmMode = ksuVersion?.let { if (kernelVersion.isGKI()) Natives.isLkmMode else null } - val isRootAvailable = rootAvailable() - val managerVersion = getManagerVersion(ksuApp) - - return HomeUiState( - kernelVersion = kernelVersion, - ksuVersion = ksuVersion, - lkmMode = lkmMode, - isManager = isManager, - isManagerPrBuild = BuildConfig.IS_PR_BUILD, - isKernelPrBuild = Natives.isPrBuild, - requiresNewKernel = isManager && Natives.requireNewKernel(), - isRootAvailable = isRootAvailable, - isSafeMode = Natives.isSafeMode, - isLateLoadMode = Natives.isLateLoadMode, - checkUpdateEnabled = ksuApp.getSharedPreferences("settings", Context.MODE_PRIVATE) - .getBoolean("check_update", true), - latestVersionInfo = LatestVersionInfo(), - currentManagerVersionCode = managerVersion.versionCode, - superuserCount = getSuperuserCount(), - moduleCount = getModuleCount(), - systemInfo = SystemInfo( - kernelVersion = Os.uname().release, - managerVersion = "${managerVersion.versionName} (${managerVersion.versionCode})", - fingerprint = Build.FINGERPRINT, - selinuxStatus = getSELinuxStatusRaw(), - seccompStatus = runCatching { - Os.prctl(21 /* PR_GET_SECCOMP */, 0, 0, 0, 0) - }.getOrDefault(-1), - ), - ) - } -} +package me.weishu.kernelsu.ui.viewmodel + +import android.content.Context +import android.content.SharedPreferences +import android.os.Build +import android.system.Os +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import me.weishu.kernelsu.BuildConfig +import me.weishu.kernelsu.Natives +import me.weishu.kernelsu.R +import me.weishu.kernelsu.getKernelVersion +import me.weishu.kernelsu.ksuApp +import me.weishu.kernelsu.ui.screen.home.HomeUiState +import me.weishu.kernelsu.ui.screen.home.SystemInfo +import me.weishu.kernelsu.ui.screen.home.getManagerVersion +import me.weishu.kernelsu.ui.util.checkNewVersion +import me.weishu.kernelsu.ui.util.getModuleCount +import me.weishu.kernelsu.ui.util.getSELinuxStatusRaw +import me.weishu.kernelsu.ui.util.getSuperuserCount +import me.weishu.kernelsu.ui.util.module.LatestVersionInfo +import me.weishu.kernelsu.ui.util.rootAvailable + +class HomeViewModel : ViewModel() { + + private val prefs = ksuApp.getSharedPreferences("settings", Context.MODE_PRIVATE) + private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> + when (key) { + "enable_official_launcher" -> _uiState.update { it.copy(appName = buildState().appName) } + "classic_ui" -> _uiState.update { it.copy(classicUi = buildState().classicUi) } + } + } + + private val _uiState = MutableStateFlow(buildState()) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + prefs.registerOnSharedPreferenceChangeListener(listener) + } + + override fun onCleared() { + prefs.unregisterOnSharedPreferenceChangeListener(listener) + super.onCleared() + } + + fun refresh() { + viewModelScope.launch { + val baseState = withContext(Dispatchers.IO) { buildState() } + _uiState.update { baseState } + if (baseState.checkUpdateEnabled) { + val latestVersionInfo = withContext(Dispatchers.IO) { checkNewVersion() } + _uiState.update { it.copy(latestVersionInfo = latestVersionInfo) } + } + } + } + + private fun buildState(): HomeUiState { + val prefs = ksuApp.getSharedPreferences("settings", Context.MODE_PRIVATE) + val isOfficial = prefs.getBoolean("enable_official_launcher", false) + val classicUi = prefs.getBoolean("classic_ui", false) + val appName = if (isOfficial) ksuApp.getString(R.string.app_name) else ksuApp.getString(R.string.app_name_kowsu) + val kernelVersion = getKernelVersion() + val isManager = Natives.isManager + val ksuVersion = if (isManager) Natives.version else null + val lkmMode = ksuVersion?.let { if (kernelVersion.isGKI()) Natives.isLkmMode else null } + val isRootAvailable = rootAvailable() + val managerVersion = getManagerVersion(ksuApp) + + return HomeUiState( + appName = appName, + classicUi = classicUi, + kernelVersion = kernelVersion, + ksuVersion = ksuVersion, + lkmMode = lkmMode, + isManager = isManager, + isManagerPrBuild = BuildConfig.IS_PR_BUILD, + isKernelPrBuild = Natives.isPrBuild, + requiresNewKernel = isManager && Natives.requireNewKernel(), + isRootAvailable = isRootAvailable, + isSafeMode = Natives.isSafeMode, + isLateLoadMode = Natives.isLateLoadMode, + checkUpdateEnabled = ksuApp.getSharedPreferences("settings", Context.MODE_PRIVATE) + .getBoolean("check_update", true), + latestVersionInfo = LatestVersionInfo(), + currentManagerVersionCode = managerVersion.versionCode, + superuserCount = getSuperuserCount(), + moduleCount = getModuleCount(), + systemInfo = SystemInfo( + kernelVersion = Os.uname().release, + managerVersion = "${managerVersion.versionName} (${managerVersion.versionCode})", + fingerprint = Build.FINGERPRINT, + selinuxStatus = getSELinuxStatusRaw(), + seccompStatus = runCatching { + Os.prctl(21 /* PR_GET_SECCOMP */, 0, 0, 0, 0) + }.getOrDefault(-1), + ), + ) + } +} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/MainActivityViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/MainActivityViewModel.kt index 75a6215f3088..120de7e32b89 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/MainActivityViewModel.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/MainActivityViewModel.kt @@ -52,6 +52,10 @@ class MainActivityViewModel : ViewModel() { "key_color", "color_style", "color_spec", + "enable_official_launcher", + "classic_ui", + "show_switch_icon", + "scroll_animation", "page_scale", "enable_blur", "enable_floating_bottom_bar", diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt index cf8a3acbac2e..2dbb66554e85 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt @@ -217,7 +217,7 @@ class ModuleViewModel( }, { if (state.sortEnabledFirst) !it.enabled else 0 }, { if (state.sortActionFirst) !(it.hasWebUi || it.hasActionScript) else 0 }, - ).thenBy(Collator.getInstance(Locale.getDefault()), Module::id) + ).thenBy(Collator.getInstance(Locale.getDefault()), Module::name) } suspend fun loadModuleList() { diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SettingsViewModel.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SettingsViewModel.kt index f2ea1b2f25c9..bfd041f53e70 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SettingsViewModel.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SettingsViewModel.kt @@ -13,6 +13,7 @@ import me.weishu.kernelsu.data.repository.SettingsRepository import me.weishu.kernelsu.data.repository.SettingsRepositoryImpl import me.weishu.kernelsu.ui.screen.settings.SettingsUiState import me.weishu.kernelsu.ui.theme.ColorMode +import me.weishu.kernelsu.ui.util.isWebuiModuleInstalled class SettingsViewModel( private val repo: SettingsRepository = SettingsRepositoryImpl() @@ -39,10 +40,18 @@ class SettingsViewModel( val pageScale = repo.pageScale val enableWebDebugging = repo.enableWebDebugging val enableSmoothCorner = repo.enableSmoothCorner + val enableOfficialLauncher = repo.enableOfficialLauncher + val classicUi = repo.classicUi + val showSwitchIcon = repo.showSwitchIcon + val scrollAnimation = repo.scrollAnimation val colorStyle = repo.colorStyle val colorSpec = repo.colorSpec val isLkmMode = repo.isLkmMode() + // WebUI modules shortcut entry + val isToolkitInstalled = isWebuiModuleInstalled("ksu_toolkit") + val isKpatchNextInstalled = isWebuiModuleInstalled("KPatch-Next") + // Async loading for natives/features val suCompatStatus = repo.getSuCompatStatus() val suCompatPersistValue = repo.getSuCompatPersistValue() @@ -56,6 +65,8 @@ class SettingsViewModel( val isSulogEnabled = repo.getSulogPersistValue() == 1L val adbRootStatus = repo.getAdbRootStatus() val isAdbRootEnabled = repo.getAdbRootPersistValue() == 1L + val avcSpoofStatus = repo.getAvcSpoofStatus() + val isAvcSpoofEnabled = repo.isAvcSpoofEnabled() val isDefaultUmountModules = repo.isDefaultUmountModules() val uiMode = repo.uiMode val autoJailbreak = repo.autoJailbreak @@ -69,6 +80,10 @@ class SettingsViewModel( themeMode = themeMode, miuixMonet = miuixMonet, keyColor = keyColor, + enableOfficialLauncher = enableOfficialLauncher, + classicUi = classicUi, + showSwitchIcon = showSwitchIcon, + scrollAnimation = scrollAnimation, enablePredictiveBack = enablePredictiveBack, enableBlur = enableBlur, enableFloatingBottomBar = enableFloatingBottomBar, @@ -78,6 +93,8 @@ class SettingsViewModel( enableSmoothCorner = enableSmoothCorner, colorStyle = colorStyle, colorSpec = colorSpec, + isToolkitInstalled = isToolkitInstalled, + isKpatchNextInstalled = isKpatchNextInstalled, suCompatStatus = suCompatStatus, suCompatMode = suCompatMode, isSuEnabled = isSuEnabled, @@ -87,6 +104,8 @@ class SettingsViewModel( isKernelUmountEnabled = isKernelUmountEnabled, sulogStatus = sulogStatus, isSulogEnabled = isSulogEnabled, + avcSpoofStatus = avcSpoofStatus, + isAvcSpoofEnabled = isAvcSpoofEnabled, isDefaultUmountModules = isDefaultUmountModules, isLkmMode = isLkmMode, autoJailbreak = autoJailbreak, @@ -180,6 +199,26 @@ class SettingsViewModel( _uiState.update { it.copy(colorSpec = spec) } } + fun setEnableOfficialLauncher(enabled: Boolean) { + repo.enableOfficialLauncher = enabled + _uiState.update { it.copy(enableOfficialLauncher = enabled) } + } + + fun setClassicUi(enabled: Boolean) { + repo.classicUi = enabled + _uiState.update { it.copy(classicUi = enabled) } + } + + fun setShowSwitchIcon(enabled: Boolean) { + repo.showSwitchIcon = enabled + _uiState.update { it.copy(showSwitchIcon = enabled) } + } + + fun setScrollAnimation(enabled: Boolean) { + repo.scrollAnimation = enabled + _uiState.update { it.copy(scrollAnimation = enabled) } + } + fun setEnablePredictiveBack(enabled: Boolean) { repo.enablePredictiveBack = enabled _uiState.update { it.copy(enablePredictiveBack = enabled) } @@ -252,6 +291,15 @@ class SettingsViewModel( } } + fun setAvcSpoofEnabled(enabled: Boolean) { + viewModelScope.launch(Dispatchers.IO) { + if (repo.setAvcSpoofEnabled(enabled)) { + repo.execKsudFeatureSave() + _uiState.update { it.copy(isAvcSpoofEnabled = enabled) } + } + } + } + fun setAutoJailbreak(enabled: Boolean) { repo.autoJailbreak = enabled _uiState.update { it.copy(autoJailbreak = enabled) } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/Download.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/Download.kt new file mode 100644 index 000000000000..6b2d097f7be7 --- /dev/null +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/Download.kt @@ -0,0 +1,53 @@ +package me.weishu.kernelsu.ui.webui + +import java.io.File +import java.io.FileOutputStream +import java.io.InputStream +import java.io.OutputStream + +private const val DEFAULT_WEBUI_DOWNLOAD_NAME = "download.bin" + +internal fun resolveWebUIDownloadFile(downloadsDir: File, requestedFileName: String?): File { + val fileName = sanitizeWebUIDownloadFileName(requestedFileName) + return File(downloadsDir, fileName) +} + +internal fun sanitizeWebUIDownloadFileName(requestedFileName: String?): String { + val trimmed = requestedFileName?.trim().orEmpty() + if (trimmed.isEmpty()) return DEFAULT_WEBUI_DOWNLOAD_NAME + + val candidate = trimmed + .substringAfterLast('/') + .substringAfterLast('\\') + .trim() + + if (candidate.isEmpty() || candidate == "." || candidate == "..") { + return DEFAULT_WEBUI_DOWNLOAD_NAME + } + + return candidate +} + +internal fun writeWebUIDownload( + target: File, + source: InputStream, + outputStreamFactory: (File) -> OutputStream = ::FileOutputStream, + onBytesWritten: (Long) -> Unit = {}, +): Long { + target.parentFile?.mkdirs() + outputStreamFactory(target).buffered(64 * 1024).use { output -> + val buffer = ByteArray(8 * 1024) + var total = 0L + while (true) { + val read = source.read(buffer) + if (read == -1) { + break + } + output.write(buffer, 0, read) + total += read + onBytesWritten(total) + } + output.flush() + return total + } +} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java index 8b28be1f0a1b..fb8b576df5e7 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/SuFilePathHandler.java @@ -196,7 +196,7 @@ public WebResourceResponse handle(@NonNull String path) { if ("internal/colors.css".equals(path)) { SharedPreferences prefs = mContext.getSharedPreferences("settings", Context.MODE_PRIVATE); int colorMode = prefs.getInt("color_mode", 0); - String uiMode = prefs.getString("ui_mode", "miuix"); + String uiMode = prefs.getString("ui_mode", "material"); String css = ""; if ((colorMode >= 3 && colorMode <= 6) || "material".equals(uiMode)) { css = MonetColorsProvider.INSTANCE.getColorsCss(); diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIScreen.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIScreen.kt index 7028ebb2f4c5..986674727aae 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIScreen.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIScreen.kt @@ -13,11 +13,13 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.ime import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.union import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -54,21 +56,22 @@ fun WebUIScreen(webUIState: WebUIState) { val density = LocalDensity.current val layoutDirection = LocalLayoutDirection.current val drawingInsets = WindowInsets.safeDrawing - val systemBarsInsets = WindowInsets.systemBars + val deviceInsets = WindowInsets.systemBars.union(WindowInsets.displayCutout) val imeInsets = WindowInsets.ime val innerPadding = if (webUIState.isInsetsEnabled) imeInsets.asPaddingValues() else drawingInsets.asPaddingValues() val fileLauncher = rememberFileLauncher(webUIState) - LaunchedEffect(density, layoutDirection, systemBarsInsets, webUIState.isInsetsEnabled) { + LaunchedEffect(density, layoutDirection, deviceInsets, webUIState.isInsetsEnabled) { if (!webUIState.isInsetsEnabled) { return@LaunchedEffect } snapshotFlow { - val top = (systemBarsInsets.getTop(density) / density.density).toInt() - val bottom = (systemBarsInsets.getBottom(density) / density.density).toInt() - val left = (systemBarsInsets.getLeft(density, layoutDirection) / density.density).toInt() - val right = (systemBarsInsets.getRight(density, layoutDirection) / density.density).toInt() - Insets(top, bottom, left, right) + Insets( + top = (deviceInsets.getTop(density) / density.density).toInt(), + bottom = (deviceInsets.getBottom(density) / density.density).toInt(), + left = (deviceInsets.getLeft(density, layoutDirection) / density.density).toInt(), + right = (deviceInsets.getRight(density, layoutDirection) / density.density).toInt() + ) }.collect { newInsets -> if (webUIState.currentInsets != newInsets) { webUIState.currentInsets = newInsets diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIState.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIState.kt index 75b448a50956..81deb2e04c64 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIState.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebUIState.kt @@ -26,11 +26,14 @@ sealed class WebUIEvent { class WebUIState { var webView: WebView? = null var rootShell: Shell? = null + var webViewInterface: WebViewInterface? = null + var downloadInterface: WebUIDownloadInterface? = null lateinit var modDir: String var moduleName: String = "" var uiEvent by mutableStateOf(WebUIEvent.Loading) var isUrlLoaded = false + @Volatile var currentInsets: Insets = Insets(0, 0, 0, 0) var isInsetsEnabled by mutableStateOf(false) var webCanGoBack by mutableStateOf(false) @@ -72,11 +75,18 @@ class WebUIState { fun dispose(activity: Activity) { activity.setTaskDescription(activity.getString(R.string.app_name)) + downloadInterface?.destroy() + downloadInterface = null + webViewInterface?.destroy() + webViewInterface = null webView?.let { view -> (view.parent as? android.view.ViewGroup)?.removeView(view) view.destroy() } webView = null + filePathCallback?.onReceiveValue(null) + filePathCallback = null rootShell?.close() + rootShell = null } } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewHelper.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewHelper.kt index 2400b4a5ba14..420f301196a6 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewHelper.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewHelper.kt @@ -25,6 +25,59 @@ import me.weishu.kernelsu.ui.util.createRootShell import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel import java.io.File +private const val WEB_DOMAIN = "mui.kernelsu.org" +private const val KSU_SCHEME = "ksu" +private const val ICON_HOST = "icon" +private const val DOWNLOAD_JS = """ + (function() { + if (window.ksu_download_enabled) return; + window.ksu_download_enabled = true; + const blobMap = new Map(); + const originalCreateObjectURL = URL.createObjectURL; + URL.createObjectURL = (obj) => { + const url = originalCreateObjectURL(obj); + if (obj instanceof Blob) blobMap.set(url, obj); + return url; + }; + const originalRevokeObjectURL = URL.revokeObjectURL; + URL.revokeObjectURL = (url) => { + setTimeout(() => blobMap.delete(url), 10000); + return originalRevokeObjectURL(url); + }; + const handleDownload = async (anchor) => { + const url = new URL(anchor.href, location.href); + const fileName = anchor.download || url.pathname.split("/").pop().split("?")[0] || "download.bin"; + const isInternal = url.hostname === 'mui.kernelsu.org'; + if (url.protocol === 'blob:' || url.protocol === 'data:' || isInternal) { + const blob = (url.protocol === 'blob:' && blobMap.has(url.href)) ? blobMap.get(url.href) : await (await fetch(url.href, { credentials: 'include' })).blob(); + const base64 = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result.split(',')[1] || ''); + reader.onerror = () => reject(reader.error || new Error('Failed to read blob')); + reader.readAsDataURL(blob); + }); + ksu_download.save(base64, fileName); + return; + } + ksu_download.download(url.href, fileName, anchor.type || null); + }; + document.addEventListener('click', (event) => { + const anchor = event.target.closest('a[download]'); + if (!anchor || !anchor.href) return; + event.preventDefault(); + handleDownload(anchor).catch((error) => console.error('KernelSU download failed', error)); + }, true); + const originalClick = HTMLAnchorElement.prototype.click; + HTMLAnchorElement.prototype.click = function() { + if (this.hasAttribute('download') && this.href) { + handleDownload(this).catch((error) => console.error('KernelSU download failed', error)); + return; + } + return originalClick.apply(this, arguments); + }; + })(); +""" + fun Activity.setTaskDescription(label: String) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { @Suppress("DEPRECATION") @@ -55,7 +108,7 @@ internal suspend fun prepareWebView( return@withContext } - if (!moduleInfo.hasWebUi || !moduleInfo.enabled || moduleInfo.update || moduleInfo.remove) { + if (!moduleInfo.hasWebUi || !moduleInfo.enabled || moduleInfo.remove) { withContext(Dispatchers.Main) { webUIState.uiEvent = WebUIEvent.Error(activity.getString(R.string.module_unavailable, moduleInfo.name)) } @@ -78,7 +131,8 @@ internal suspend fun prepareWebView( webView.setBackgroundColor(Color.TRANSPARENT) val prefs = activity.getSharedPreferences("settings", Context.MODE_PRIVATE) - WebView.setWebContentsDebuggingEnabled(prefs.getBoolean("enable_web_debugging", false)) + val enableWebDebugging = prefs.getBoolean("enable_web_debugging", false) + WebView.setWebContentsDebuggingEnabled(enableWebDebugging) webView.settings.apply { javaScriptEnabled = true @@ -88,7 +142,7 @@ internal suspend fun prepareWebView( val webRoot = File("${webUIState.modDir}/webroot") val webViewAssetLoader = WebViewAssetLoader.Builder() - .setDomain("mui.kernelsu.org") + .setDomain(WEB_DOMAIN) .addPathHandler( "/", SuFilePathHandler( @@ -104,9 +158,9 @@ internal suspend fun prepareWebView( webView.webViewClient = object : WebViewClient() { override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? { val url = request.url - if (url.scheme.equals("ksu", ignoreCase = true) && url.host.equals("icon", ignoreCase = true)) { + if (url.scheme.equals(KSU_SCHEME, ignoreCase = true) && url.host.equals(ICON_HOST, ignoreCase = true)) { val packageName = url.path?.substring(1) - if (!packageName.isNullOrEmpty()) { + if (!packageName.isNullOrEmpty() && packageName.matches(Regex("[a-zA-Z0-9._]+"))) { val icon = AppIconUtil.loadAppIconSync(activity, packageName, 512) if (icon != null) { val stream = java.io.ByteArrayOutputStream() @@ -122,9 +176,17 @@ internal suspend fun prepareWebView( return webViewAssetLoader.shouldInterceptRequest(url) } + override fun onPageFinished(view: WebView?, url: String?) { + if (enableWebDebugging) { + view?.evaluateJavascript(erudaConsole(activity), null) + view?.evaluateJavascript("eruda.init();", null) + } + } + override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) { webUIState.webCanGoBack = view?.canGoBack() ?: false if (webUIState.isInsetsEnabled) webUIState.webView?.evaluateJavascript(webUIState.currentInsets.js, null) + view?.evaluateJavascript(DOWNLOAD_JS, null) super.doUpdateVisitedHistory(view, url, isReload) } } @@ -172,9 +234,22 @@ internal suspend fun prepareWebView( // JS Interface val webviewInterface = WebViewInterface(webUIState) + val downloadInterface = WebUIDownloadInterface(webUIState) + webUIState.webViewInterface = webviewInterface + webUIState.downloadInterface = downloadInterface webUIState.webView = webView webView.addJavascriptInterface(webviewInterface, "ksu") + webView.addJavascriptInterface(downloadInterface, "ksu_download") + webView.setDownloadListener { url, _, contentDisposition, mimetype, _ -> + val fileName = android.webkit.URLUtil.guessFileName(url, contentDisposition, mimetype) + downloadInterface.download(url, fileName, mimetype) + } + webView.evaluateJavascript(DOWNLOAD_JS, null) webUIState.uiEvent = WebUIEvent.WebViewReady } } -} \ No newline at end of file +} + +private fun erudaConsole(context: Context): String { + return context.assets.open("eruda.min.js").bufferedReader().use { it.readText() } +} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt index f3cdbe937838..4c2fa451f9bd 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/WebViewInterface.kt @@ -1,25 +1,50 @@ package me.weishu.kernelsu.ui.webui import android.app.Activity +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Intent +import android.net.Uri +import android.os.Environment +import android.util.Base64 +import android.util.Log import android.content.pm.ApplicationInfo import android.os.Handler import android.os.Looper import android.text.TextUtils import android.view.Window +import android.webkit.CookieManager import android.webkit.JavascriptInterface +import android.webkit.WebSettings import android.widget.Toast +import androidx.core.app.NotificationCompat +import androidx.core.content.FileProvider import androidx.core.content.pm.PackageInfoCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat import com.topjohnwu.superuser.CallbackList import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.internal.UiThreadHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import me.weishu.kernelsu.BuildConfig +import me.weishu.kernelsu.R +import me.weishu.kernelsu.ui.util.DownloadCompletionAction +import me.weishu.kernelsu.ui.util.DownloadManager +import me.weishu.kernelsu.ui.util.DownloadService import me.weishu.kernelsu.ui.util.createRootShell import me.weishu.kernelsu.ui.util.listModules +import me.weishu.kernelsu.ui.util.resolveDownloadMimeType import me.weishu.kernelsu.ui.util.withNewRootShell import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel +import me.weishu.kernelsu.ui.webui.file.KsuIO import org.json.JSONArray import org.json.JSONObject +import java.io.ByteArrayInputStream import java.io.File import java.util.concurrent.CompletableFuture @@ -38,9 +63,7 @@ class WebViewInterface(private val state: WebUIState) { } private fun processOptions(sb: StringBuilder, options: String?) { - val opts = if (options == null) JSONObject() else { - JSONObject(options) - } + val opts = if (options == null) JSONObject() else JSONObject(options) val cwd = opts.optString("cwd") if (!TextUtils.isEmpty(cwd)) { @@ -87,13 +110,11 @@ class WebViewInterface(private val state: WebUIState) { processOptions(finalCommand, options) - if (!TextUtils.isEmpty(args)) { + if (args.isNotEmpty()) { finalCommand.append(command).append(" ") - JSONArray(args).let { argsArray -> - for (i in 0 until argsArray.length()) { - finalCommand.append(argsArray.getString(i)) - finalCommand.append(" ") - } + val argsArray = JSONArray(args) + for (i in 0 until argsArray.length()) { + finalCommand.append(argsArray.getString(i)).append(" ") } } else { finalCommand.append(command) @@ -241,7 +262,7 @@ class WebViewInterface(private val state: WebUIState) { obj.put("versionName", pkg.versionName ?: "") obj.put("versionCode", PackageInfoCompat.getLongVersionCode(pkg)) obj.put("appLabel", appInfo.label) - obj.put("isSystem", if (app != null) ((app.flags and ApplicationInfo.FLAG_SYSTEM) != 0) else JSONObject.NULL) + obj.put("isSystem", app?.let { (it.flags and ApplicationInfo.FLAG_SYSTEM) != 0 } ?: JSONObject.NULL) obj.put("uid", app?.uid ?: JSONObject.NULL) jsonArray.put(obj) } else { @@ -258,6 +279,168 @@ class WebViewInterface(private val state: WebUIState) { fun exit() { state.requestExit() } + + @JavascriptInterface + fun io() = KsuIO + + fun destroy() { + KsuIO.destroy() + } +} + +class WebUIDownloadInterface(private val state: WebUIState) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + private val webView get() = state.webView + + @JavascriptInterface + fun download(url: String, fileName: String?, mimeType: String?) { + val currentWebView = webView ?: return + val context = currentWebView.context + val target = resolveDownloadTarget(fileName) + val cookie = CookieManager.getInstance().getCookie(url) + val userAgent = WebSettings.getDefaultUserAgent(context) + DownloadManager.enqueue( + context = context, + url = url, + fileName = target.name, + targetPath = target.absolutePath, + mimeType = mimeType, + cookie = cookie, + userAgent = userAgent, + completionAction = DownloadCompletionAction.OPEN_FILE, + ) + } + + @JavascriptInterface + fun save(base64: String, fileName: String?) { + val currentWebView = webView ?: return + val target = resolveDownloadTarget(fileName) + val context = currentWebView.context + val notificationManager = context.getSystemService(NotificationManager::class.java) + val downloadId = DownloadManager.registerLocalSave( + fileName = target.name, + targetPath = target.absolutePath, + completionAction = DownloadCompletionAction.OPEN_FILE, + ) + + ensureNotificationChannel(notificationManager, context) + notificationManager.notify(downloadId, buildProgressNotification(context, target.name, 0)) + + scope.launch { + runCatching { + val decoded = Base64.decode(base64, Base64.DEFAULT) + var lastProgress = -1 + ByteArrayInputStream(decoded).use { input -> + writeWebUIDownload(target, input) { written -> + val progress = if (decoded.isEmpty()) 100 else ((written * 100L) / decoded.size.toLong()).toInt().coerceIn(0, 100) + DownloadManager.updateProgress(downloadId, progress) + if (progress - lastProgress >= 2 || progress == 100) { + notificationManager.notify(downloadId, buildProgressNotification(context, target.name, progress)) + lastProgress = progress + } + } + } + }.onSuccess { + val uri = Uri.fromFile(target) + DownloadManager.markCompleted(downloadId, uri) + notificationManager.notify( + downloadId, + buildCompletionNotification(context, downloadId, target) + ) + postToast(currentWebView.context.getString(R.string.download_complete_content, target.name)) + }.onFailure { throwable -> + Log.e("WebUIDownload", "Failed to save ${target.absolutePath}", throwable) + DownloadManager.markFailed(downloadId, throwable.message ?: "Unknown error") + notificationManager.notify(downloadId, buildFailureNotification(context, target.name)) + postToast(currentWebView.context.getString(R.string.download_failed_content, target.name)) + } + } + } + + fun destroy() { + scope.cancel() + } + + private fun postToast(message: String) { + webView?.let { currentWebView -> + currentWebView.post { + Toast.makeText(currentWebView.context, message, Toast.LENGTH_SHORT).show() + } + } + } + + private fun resolveDownloadTarget(fileName: String?): File { + val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + return resolveWebUIDownloadFile(downloadsDir, fileName) + } + + private fun ensureNotificationChannel(notificationManager: NotificationManager, context: android.content.Context) { + notificationManager.createNotificationChannel( + NotificationChannel( + DownloadService.CHANNEL_ID, + context.getString(R.string.download_channel_name), + NotificationManager.IMPORTANCE_LOW, + ) + ) + } + + private fun buildProgressNotification( + context: android.content.Context, + fileName: String, + progress: Int, + ) = NotificationCompat.Builder(context, DownloadService.CHANNEL_ID) + .setContentTitle(context.getString(R.string.download_progress_title, fileName)) + .setContentText("$progress%") + .setSmallIcon(android.R.drawable.stat_sys_download) + .setProgress(100, progress, progress == 0) + .setOngoing(true) + .setSilent(true) + .build() + + private fun buildCompletionNotification( + context: android.content.Context, + downloadId: Int, + target: File, + ): android.app.Notification { + val contentUri = FileProvider.getUriForFile( + context, + "${BuildConfig.APPLICATION_ID}.fileprovider", + target, + ) + val openIntent = Intent.createChooser( + Intent(Intent.ACTION_VIEW).apply { + setDataAndType(contentUri, resolveDownloadMimeType(target.name, null)) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK) + }, + context.getString(R.string.open), + ).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + val pendingIntent = PendingIntent.getActivity( + context, + downloadId, + openIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + return NotificationCompat.Builder(context, DownloadService.CHANNEL_ID) + .setContentTitle(context.getString(R.string.download_complete_title)) + .setContentText(context.getString(R.string.download_complete_content, target.name)) + .setSmallIcon(android.R.drawable.stat_sys_download_done) + .setAutoCancel(true) + .setContentIntent(pendingIntent) + .addAction(android.R.drawable.ic_menu_view, context.getString(R.string.open), pendingIntent) + .build() + } + + private fun buildFailureNotification( + context: android.content.Context, + fileName: String, + ) = NotificationCompat.Builder(context, DownloadService.CHANNEL_ID) + .setContentTitle(context.getString(R.string.download_failed_title)) + .setContentText(context.getString(R.string.download_failed_content, fileName)) + .setSmallIcon(android.R.drawable.stat_notify_error) + .setAutoCancel(true) + .build() } fun hideSystemUI(window: Window) = diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/FileInputStreamInterface.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/FileInputStreamInterface.kt new file mode 100644 index 000000000000..4f2d084a8cba --- /dev/null +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/FileInputStreamInterface.kt @@ -0,0 +1,106 @@ +package me.weishu.kernelsu.ui.webui.file + +import android.util.Base64 +import android.util.Log +import android.webkit.JavascriptInterface +import com.topjohnwu.superuser.io.SuFileInputStream +import java.io.BufferedInputStream +import java.io.InputStream + +class FileInputStreamInterface { + @JavascriptInterface + fun open(path: String): String = runCatching { + val stream = ManagedInputStream(SuFileInputStream.open(path)) + val id = java.util.UUID.randomUUID().toString() + KsuIO.openInputStreams[id] = stream + id + }.onFailure { Log.e(TAG, "FileInputStream open failed", it) }.getOrElse { "" } + + @JavascriptInterface + fun read(id: String): String = runCatching { + val stream = KsuIO.openInputStreams[id] ?: return "" + val bytesRead = stream.readInto() + if (bytesRead > 0) { + Base64.encodeToString(stream.buffer(), 0, bytesRead, Base64.NO_WRAP) + } else { + "" + } + }.onFailure { Log.e(TAG, "FileInputStream read failed", it) }.getOrElse { "" } + + @JavascriptInterface + fun read(id: String, maxBytes: Int): String = runCatching { + val stream = KsuIO.openInputStreams[id] ?: return "" + val bytesRead = stream.readInto(maxBytes) + if (bytesRead > 0) { + Base64.encodeToString(stream.buffer(), 0, bytesRead, Base64.NO_WRAP) + } else { + "" + } + }.onFailure { Log.e(TAG, "FileInputStream read(maxBytes) failed", it) }.getOrElse { "" } + + @JavascriptInterface + fun available(id: String): Int = runCatching { + val stream = KsuIO.openInputStreams[id] ?: return 0 + stream.available() + }.getOrDefault(0) + + @JavascriptInterface + fun close(id: String): Boolean { + val stream = KsuIO.openInputStreams.remove(id) ?: return false + return runCatching { + stream.close() + true + }.getOrElse { + Log.e(TAG, "FileInputStream close failed", it) + false + } + } + + fun closeAll() { + while (true) { + val entry = KsuIO.openInputStreams.entries.firstOrNull() ?: break + val id = entry.key + val stream = entry.value + if (!KsuIO.openInputStreams.remove(id, stream)) { + continue + } + runCatching { + stream.close() + }.onFailure { Log.e(TAG, "closeAll failed for $id", it) } + } + } +} + +internal class ManagedInputStream( + inputStream: InputStream, + private val defaultChunkSize: Int = DEFAULT_CHUNK_SIZE, + private val maxChunkSize: Int = MAX_CHUNK_SIZE, +) : AutoCloseable { + private val stream = BufferedInputStream(inputStream, maxChunkSize) + private var buffer = ByteArray(defaultChunkSize) + + @Synchronized + fun readInto(maxBytes: Int = defaultChunkSize): Int { + val requestedSize = maxBytes.coerceIn(1, maxChunkSize) + if (buffer.size < requestedSize) { + buffer = ByteArray(requestedSize) + } + return stream.read(buffer, 0, requestedSize) + } + + @Synchronized + fun buffer(): ByteArray = buffer + + @Synchronized + fun available(): Int = stream.available() + + @Synchronized + override fun close() { + stream.close() + } + + companion object { + const val DEFAULT_CHUNK_SIZE = 8 * 1024 + const val MAX_CHUNK_SIZE = 64 * 1024 + } +} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/FileInterface.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/FileInterface.kt new file mode 100644 index 000000000000..e0b27730c0f8 --- /dev/null +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/FileInterface.kt @@ -0,0 +1,154 @@ +package me.weishu.kernelsu.ui.webui.file + +import android.util.Log +import android.webkit.JavascriptInterface +import com.topjohnwu.superuser.io.SuFile +import java.io.BufferedOutputStream + +class FileInterface(private val path: String) { + private val suFile: SuFile = SuFile(path) + + @JavascriptInterface + fun exists(): Boolean = runCatching { suFile.exists() }.getOrDefault(false) + + @JavascriptInterface + fun isFile(): Boolean = runCatching { suFile.isFile }.getOrDefault(false) + + @JavascriptInterface + fun isDirectory(): Boolean = runCatching { suFile.isDirectory }.getOrDefault(false) + + @JavascriptInterface + fun canRead(): Boolean = runCatching { suFile.canRead() }.getOrDefault(false) + + @JavascriptInterface + fun canWrite(): Boolean = runCatching { suFile.canWrite() }.getOrDefault(false) + + @JavascriptInterface + fun canExecute(): Boolean = runCatching { suFile.canExecute() }.getOrDefault(false) + + @JavascriptInterface + fun createNewFile(): Boolean = runCatching { suFile.createNewFile() }.getOrDefault(false) + + @JavascriptInterface + fun delete(): Boolean = runCatching { suFile.delete() }.getOrDefault(false) + + @JavascriptInterface + fun deleteRecursive(): Boolean = runCatching { suFile.deleteRecursive() }.getOrDefault(false) + + @JavascriptInterface + fun mkdir(): Boolean = runCatching { suFile.mkdir() }.getOrDefault(false) + + @JavascriptInterface + fun mkdirs(): Boolean = runCatching { suFile.mkdirs() }.getOrDefault(false) + + @JavascriptInterface + fun renameTo(destPath: String): Boolean = runCatching { + suFile.renameTo(SuFile(destPath)) + }.getOrDefault(false) + + @JavascriptInterface + fun list(): Array = runCatching { suFile.list() ?: emptyArray() }.getOrDefault(emptyArray()) + + @JavascriptInterface + fun listFiles(): Array = runCatching { + suFile.listFiles()?.map { it.absolutePath }?.toTypedArray() ?: emptyArray() + }.getOrDefault(emptyArray()) + + @JavascriptInterface + fun length(): Long = runCatching { suFile.length() }.getOrDefault(-1L) + + @JavascriptInterface + fun lastModified(): Long = runCatching { suFile.lastModified() }.getOrDefault(-1L) + + @JavascriptInterface + fun setLastModified(time: Long): Boolean = runCatching { suFile.setLastModified(time) }.getOrDefault(false) + + @JavascriptInterface + fun getAbsolutePath(): String = runCatching { suFile.absolutePath }.getOrDefault(path) + + @JavascriptInterface + fun getCanonicalPath(): String = runCatching { suFile.canonicalPath }.getOrDefault(path) + + @JavascriptInterface + fun getParent(): String? = runCatching { suFile.parent }.getOrNull() + + @JavascriptInterface + fun getPath(): String = path + + @JavascriptInterface + fun getName(): String = runCatching { suFile.name }.getOrDefault("") + + @JavascriptInterface + fun isHidden(): Boolean = runCatching { suFile.isHidden }.getOrDefault(false) + + @JavascriptInterface + fun isBlock(): Boolean = runCatching { suFile.isBlock }.getOrDefault(false) + + @JavascriptInterface + fun isCharacter(): Boolean = runCatching { suFile.isCharacter }.getOrDefault(false) + + @JavascriptInterface + fun isSymlink(): Boolean = runCatching { suFile.isSymlink }.getOrDefault(false) + + @JavascriptInterface + fun createNewSymlink(target: String): Boolean = runCatching { + suFile.createNewSymlink(target) + }.getOrDefault(false) + + @JavascriptInterface + fun createNewLink(existing: String): Boolean = runCatching { + suFile.createNewLink(existing) + }.getOrDefault(false) + + @JavascriptInterface + fun clear(): Boolean = runCatching { suFile.clear() }.getOrDefault(false) + + @JavascriptInterface + fun setReadOnly(): Boolean = runCatching { suFile.setReadOnly() }.getOrDefault(false) + + @JavascriptInterface + fun setReadable(readable: Boolean, ownerOnly: Boolean): Boolean = + runCatching { suFile.setReadable(readable, ownerOnly) }.getOrDefault(false) + + @JavascriptInterface + fun setWritable(writable: Boolean, ownerOnly: Boolean): Boolean = + runCatching { suFile.setWritable(writable, ownerOnly) }.getOrDefault(false) + + @JavascriptInterface + fun setExecutable(executable: Boolean, ownerOnly: Boolean): Boolean = + runCatching { suFile.setExecutable(executable, ownerOnly) }.getOrDefault(false) + + @JavascriptInterface + fun getFreeSpace(): Long = runCatching { suFile.freeSpace }.getOrDefault(-1L) + + @JavascriptInterface + fun getTotalSpace(): Long = runCatching { suFile.totalSpace }.getOrDefault(-1L) + + @JavascriptInterface + fun getUsableSpace(): Long = runCatching { suFile.usableSpace }.getOrDefault(-1L) + + @JavascriptInterface + fun newInputStream(): String { + return runCatching { + val stream = ManagedInputStream(suFile.newInputStream()) + val id = java.util.UUID.randomUUID().toString() + KsuIO.openInputStreams[id] = stream + id + }.onFailure { Log.e(TAG, "newInputStream failed", it) }.getOrElse { "" } + } + + @JavascriptInterface + fun newOutputStream(append: Boolean): String { + return runCatching { + val stream = suFile.newOutputStream(append) + val id = java.util.UUID.randomUUID().toString() + KsuIO.openOutputStreams[id] = BufferedOutputStream(stream, ManagedInputStream.MAX_CHUNK_SIZE) + id + }.onFailure { Log.e(TAG, "newOutputStream failed", it) }.getOrElse { "" } + } + + @JavascriptInterface + fun newOutputStream(): String = newOutputStream(false) + + override fun toString(): String = path +} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/FileOutputStreamInterface.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/FileOutputStreamInterface.kt new file mode 100644 index 000000000000..75666096496f --- /dev/null +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/FileOutputStreamInterface.kt @@ -0,0 +1,68 @@ +package me.weishu.kernelsu.ui.webui.file + +import android.util.Base64 +import android.util.Log +import android.webkit.JavascriptInterface +import com.topjohnwu.superuser.io.SuFileOutputStream +import java.io.BufferedOutputStream +import java.util.UUID + +class FileOutputStreamInterface { + @JavascriptInterface + fun open(path: String, append: Boolean): String = runCatching { + val file = com.topjohnwu.superuser.io.SuFile(path) + val fos = SuFileOutputStream.open(file, append) + val bos = BufferedOutputStream(fos, 64 * 1024) + val id = UUID.randomUUID().toString() + KsuIO.openOutputStreams[id] = bos + id + }.onFailure { Log.e(TAG, "FileOutputStream open failed", it) }.getOrElse { "" } + + @JavascriptInterface + fun open(path: String): String = open(path, false) + + @JavascriptInterface + fun writeByte(id: String, b: Int): Boolean = runCatching { + val bos = KsuIO.openOutputStreams[id] ?: return false + synchronized(bos) { bos.write(b) } + true + }.onFailure { Log.e(TAG, "writeByte failed", it) }.getOrElse { false } + + @JavascriptInterface + fun write(id: String, base64: String): Boolean = runCatching { + val bos = KsuIO.openOutputStreams[id] ?: return false + val data = Base64.decode(base64, Base64.NO_WRAP) + synchronized(bos) { bos.write(data) } + true + }.onFailure { Log.e(TAG, "write failed", it) }.getOrElse { false } + + @JavascriptInterface + fun flush(id: String): Boolean = runCatching { + val bos = KsuIO.openOutputStreams[id] ?: return false + synchronized(bos) { bos.flush() } + true + }.onFailure { Log.e(TAG, "flush failed", it) }.getOrElse { false } + + @JavascriptInterface + fun close(id: String): Boolean { + val bos = KsuIO.openOutputStreams.remove(id) ?: return false + return runCatching { + synchronized(bos) { bos.close() } + true + }.onFailure { Log.e(TAG, "close failed", it) }.getOrElse { false } + } + + fun closeAll() { + while (true) { + val entry = KsuIO.openOutputStreams.entries.firstOrNull() ?: break + val id = entry.key + val bos = entry.value + if (!KsuIO.openOutputStreams.remove(id, bos)) { + continue + } + runCatching { + synchronized(bos) { bos.close() } + }.onFailure { Log.e(TAG, "closeAll failed for $id", it) } + } + } +} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/KsuIO.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/KsuIO.kt new file mode 100644 index 000000000000..ca8225e32f1f --- /dev/null +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/KsuIO.kt @@ -0,0 +1,34 @@ +package me.weishu.kernelsu.ui.webui.file + +import android.webkit.JavascriptInterface +import java.io.OutputStream +import java.util.concurrent.ConcurrentHashMap + +const val TAG = "KsuIO" + +object KsuIO { + internal val openInputStreams = ConcurrentHashMap() + internal val openOutputStreams = ConcurrentHashMap() + + private val fileOutputStream = FileOutputStreamInterface() + private val fileInputStream = FileInputStreamInterface() + private val randomAccessFile = RandomAccessFileInterface() + + @JavascriptInterface + fun File(path: String): FileInterface = FileInterface(path) + + @JavascriptInterface + fun FileInputStream(): FileInputStreamInterface = fileInputStream + + @JavascriptInterface + fun FileOutputStream(): FileOutputStreamInterface = fileOutputStream + + @JavascriptInterface + fun RandomAccessFile(): RandomAccessFileInterface = randomAccessFile + + fun destroy() { + fileInputStream.closeAll() + fileOutputStream.closeAll() + randomAccessFile.closeAll() + } +} diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/RandomAccessFileInterface.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/RandomAccessFileInterface.kt new file mode 100644 index 000000000000..90345adc1c7f --- /dev/null +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/webui/file/RandomAccessFileInterface.kt @@ -0,0 +1,196 @@ +package me.weishu.kernelsu.ui.webui.file + +import android.util.Base64 +import android.util.Log +import android.webkit.JavascriptInterface +import com.topjohnwu.superuser.io.SuRandomAccessFile +import java.util.concurrent.ConcurrentHashMap + +class RandomAccessFileInterface { + private val openFiles = ConcurrentHashMap() + + @JavascriptInterface + fun open(path: String, mode: String): String = runCatching { + val raf = SuRandomAccessFile.open(path, mode) + val id = java.util.UUID.randomUUID().toString() + openFiles[id] = raf + id + }.onFailure { Log.e(TAG, "RandomAccessFile open failed", it) }.getOrElse { "" } + + @JavascriptInterface + fun read(id: String): Int = runCatching { + val raf = openFiles[id] ?: return -1 + synchronized(raf) { raf.read() } + }.onFailure { Log.e(TAG, "RandomAccessFile read() failed", it) }.getOrElse { -1 } + + @JavascriptInterface + fun readBytes(id: String, len: Int): String = runCatching { + val raf = openFiles[id] ?: return "" + val buffer = ByteArray(len) + val bytesRead = synchronized(raf) { raf.read(buffer) } + if (bytesRead > 0) { + Base64.encodeToString(buffer, 0, bytesRead, Base64.NO_WRAP) + } else { + "" + } + }.onFailure { Log.e(TAG, "RandomAccessFile readBytes failed", it) }.getOrElse { "" } + + @JavascriptInterface + fun readBoolean(id: String): Boolean = runCatching { + val raf = openFiles[id] ?: return false + synchronized(raf) { raf.readBoolean() } + }.onFailure { Log.e(TAG, "RandomAccessFile readBoolean failed", it) }.getOrElse { false } + + @JavascriptInterface + fun readByte(id: String): Byte = runCatching { + val raf = openFiles[id] ?: return 0 + synchronized(raf) { raf.readByte() } + }.onFailure { Log.e(TAG, "RandomAccessFile readByte failed", it) }.getOrElse { 0 } + + @JavascriptInterface + fun readInt(id: String): Int = runCatching { + val raf = openFiles[id] ?: return 0 + synchronized(raf) { raf.readInt() } + }.onFailure { Log.e(TAG, "RandomAccessFile readInt failed", it) }.getOrElse { 0 } + + @JavascriptInterface + fun readLong(id: String): Long = runCatching { + val raf = openFiles[id] ?: return 0L + synchronized(raf) { raf.readLong() } + }.onFailure { Log.e(TAG, "RandomAccessFile readLong failed", it) }.getOrElse { 0L } + + @JavascriptInterface + fun readShort(id: String): Short = runCatching { + val raf = openFiles[id] ?: return 0.toShort() + synchronized(raf) { raf.readShort() } + }.onFailure { Log.e(TAG, "RandomAccessFile readShort failed", it) }.getOrElse { 0.toShort() } + + @JavascriptInterface + fun readFloat(id: String): Float = runCatching { + val raf = openFiles[id] ?: return 0f + synchronized(raf) { raf.readFloat() } + }.onFailure { Log.e(TAG, "RandomAccessFile readFloat failed", it) }.getOrElse { 0f } + + @JavascriptInterface + fun readDouble(id: String): Double = runCatching { + val raf = openFiles[id] ?: return 0.0 + synchronized(raf) { raf.readDouble() } + }.onFailure { Log.e(TAG, "RandomAccessFile readDouble failed", it) }.getOrElse { 0.0 } + + @JavascriptInterface + fun readUTF(id: String): String = runCatching { + val raf = openFiles[id] ?: return "" + synchronized(raf) { raf.readUTF() } + }.onFailure { Log.e(TAG, "RandomAccessFile readUTF failed", it) }.getOrElse { "" } + + @JavascriptInterface + fun readLine(id: String): String? = runCatching { + val raf = openFiles[id] ?: return null + synchronized(raf) { raf.readLine() } + }.onFailure { Log.e(TAG, "RandomAccessFile readLine failed", it) }.getOrNull() + + @JavascriptInterface + fun write(id: String, b: Int): Unit = runCatching { + val raf = openFiles[id] ?: return + synchronized(raf) { raf.write(b) } + }.onFailure { Log.e(TAG, "RandomAccessFile write failed", it) }.let { } + + @JavascriptInterface + fun writeBase64(id: String, data: String): Unit = runCatching { + val raf = openFiles[id] ?: return + val bytes = Base64.decode(data, Base64.NO_WRAP) + synchronized(raf) { raf.write(bytes) } + }.onFailure { Log.e(TAG, "RandomAccessFile writeBase64 failed", it) }.let { } + + @JavascriptInterface + fun writeBoolean(id: String, v: Boolean): Unit = runCatching { + val raf = openFiles[id] ?: return + synchronized(raf) { raf.writeBoolean(v) } + }.onFailure { Log.e(TAG, "RandomAccessFile writeBoolean failed", it) }.let { } + + @JavascriptInterface + fun writeByte(id: String, v: Int): Unit = runCatching { + val raf = openFiles[id] ?: return + synchronized(raf) { raf.writeByte(v) } + }.onFailure { Log.e(TAG, "RandomAccessFile writeByte failed", it) }.let { } + + @JavascriptInterface + fun writeInt(id: String, v: Int): Unit = runCatching { + val raf = openFiles[id] ?: return + synchronized(raf) { raf.writeInt(v) } + }.onFailure { Log.e(TAG, "RandomAccessFile writeInt failed", it) }.let { } + + @JavascriptInterface + fun writeLong(id: String, v: Long): Unit = runCatching { + val raf = openFiles[id] ?: return + synchronized(raf) { raf.writeLong(v) } + }.onFailure { Log.e(TAG, "RandomAccessFile writeLong failed", it) }.let { } + + @JavascriptInterface + fun writeShort(id: String, v: Int): Unit = runCatching { + val raf = openFiles[id] ?: return + synchronized(raf) { raf.writeShort(v) } + }.onFailure { Log.e(TAG, "RandomAccessFile writeShort failed", it) }.let { } + + @JavascriptInterface + fun writeFloat(id: String, v: Float): Unit = runCatching { + val raf = openFiles[id] ?: return + synchronized(raf) { raf.writeFloat(v) } + }.onFailure { Log.e(TAG, "RandomAccessFile writeFloat failed", it) }.let { } + + @JavascriptInterface + fun writeDouble(id: String, v: Double): Unit = runCatching { + val raf = openFiles[id] ?: return + synchronized(raf) { raf.writeDouble(v) } + }.onFailure { Log.e(TAG, "RandomAccessFile writeDouble failed", it) }.let { } + + @JavascriptInterface + fun writeUTF(id: String, str: String): Unit = runCatching { + val raf = openFiles[id] ?: return + synchronized(raf) { raf.writeUTF(str) } + }.onFailure { Log.e(TAG, "RandomAccessFile writeUTF failed", it) }.let { } + + @JavascriptInterface + fun seek(id: String, pos: Long): Boolean = runCatching { + val raf = openFiles[id] ?: return false + synchronized(raf) { raf.seek(pos) } + true + }.onFailure { Log.e(TAG, "RandomAccessFile seek failed", it) }.getOrElse { false } + + @JavascriptInterface + fun getFilePointer(id: String): Long = runCatching { + val raf = openFiles[id] ?: return -1L + synchronized(raf) { raf.getFilePointer() } + }.onFailure { Log.e(TAG, "RandomAccessFile getFilePointer failed", it) }.getOrElse { -1L } + + @JavascriptInterface + fun length(id: String): Long = runCatching { + val raf = openFiles[id] ?: return -1L + synchronized(raf) { raf.length() } + }.onFailure { Log.e(TAG, "RandomAccessFile length failed", it) }.getOrElse { -1L } + + @JavascriptInterface + fun setLength(id: String, newLength: Long): Boolean = runCatching { + val raf = openFiles[id] ?: return false + synchronized(raf) { raf.setLength(newLength) } + true + }.onFailure { Log.e(TAG, "RandomAccessFile setLength failed", it) }.getOrElse { false } + + @JavascriptInterface + fun close(id: String): Boolean { + val raf = openFiles.remove(id) ?: return false + return runCatching { + synchronized(raf) { raf.close() } + true + }.onFailure { Log.e(TAG, "RandomAccessFile close failed", it) }.getOrElse { false } + } + + fun closeAll() { + openFiles.forEach { (id, raf) -> + runCatching { + synchronized(raf) { raf.close() } + }.onFailure { Log.e(TAG, "closeAll failed for $id", it) } + } + openFiles.clear() + } +} diff --git a/manager/app/src/main/res/drawable/anykernel_foreground.xml b/manager/app/src/main/res/drawable/anykernel_foreground.xml new file mode 100644 index 000000000000..d1d954c0305a --- /dev/null +++ b/manager/app/src/main/res/drawable/anykernel_foreground.xml @@ -0,0 +1,9 @@ + + + diff --git a/manager/app/src/main/res/drawable/ic_launcher_kowsu.xml b/manager/app/src/main/res/drawable/ic_launcher_kowsu.xml new file mode 100644 index 000000000000..585830efcf95 --- /dev/null +++ b/manager/app/src/main/res/drawable/ic_launcher_kowsu.xml @@ -0,0 +1,41 @@ + + + + + + + + + + \ No newline at end of file diff --git a/manager/app/src/main/res/drawable/module_foreground.xml b/manager/app/src/main/res/drawable/module_foreground.xml new file mode 100644 index 000000000000..5be168b1b933 --- /dev/null +++ b/manager/app/src/main/res/drawable/module_foreground.xml @@ -0,0 +1,9 @@ + + + diff --git a/manager/app/src/main/res/mipmap-anydpi/anykernel.xml b/manager/app/src/main/res/mipmap-anydpi/anykernel.xml new file mode 100644 index 000000000000..1c7de6e5837c --- /dev/null +++ b/manager/app/src/main/res/mipmap-anydpi/anykernel.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/manager/app/src/main/res/mipmap-anydpi/ic_launcher_kowsu.xml b/manager/app/src/main/res/mipmap-anydpi/ic_launcher_kowsu.xml new file mode 100644 index 000000000000..cdc9f2a66b10 --- /dev/null +++ b/manager/app/src/main/res/mipmap-anydpi/ic_launcher_kowsu.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/manager/app/src/main/res/mipmap-anydpi/ic_launcher_official.xml similarity index 100% rename from manager/app/src/main/res/mipmap-anydpi/ic_launcher.xml rename to manager/app/src/main/res/mipmap-anydpi/ic_launcher_official.xml diff --git a/manager/app/src/main/res/mipmap-anydpi/module.xml b/manager/app/src/main/res/mipmap-anydpi/module.xml new file mode 100644 index 000000000000..f64849ddfc70 --- /dev/null +++ b/manager/app/src/main/res/mipmap-anydpi/module.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/manager/app/src/main/res/values-ar/strings.xml b/manager/app/src/main/res/values-ar/strings.xml index e7bbac3ee577..fd0e3ea9e345 100644 --- a/manager/app/src/main/res/values-ar/strings.xml +++ b/manager/app/src/main/res/values-ar/strings.xml @@ -5,6 +5,8 @@ إضغط للتثبيت يعمل الإصدار: %d + مستخدمين الجذر: %d + الإضافات: %d غير مدعوم KernelSU يدعم GKI kernels فقط إصدار النواة diff --git a/manager/app/src/main/res/values-az/strings.xml b/manager/app/src/main/res/values-az/strings.xml index d6469a6f37c2..4a83e4489da6 100644 --- a/manager/app/src/main/res/values-az/strings.xml +++ b/manager/app/src/main/res/values-az/strings.xml @@ -1,11 +1,13 @@ Ana səhifə + Super istifadəçilər: %d Nüvə Yüklənmədi Yükləmək üçün toxunun İşləyir Versiya: %d + Modullar: %d Hal-hazırda KernelSU yalnız GKI nüvələrini dəstəkləyir Dəstəklənmir Yüklə diff --git a/manager/app/src/main/res/values-bg/strings.xml b/manager/app/src/main/res/values-bg/strings.xml index 9ecc56c6c69c..1954b25eb4fb 100644 --- a/manager/app/src/main/res/values-bg/strings.xml +++ b/manager/app/src/main/res/values-bg/strings.xml @@ -5,6 +5,8 @@ Натиснете да инсталирате Работи Версия: %d + Суперпотребители: %d + Модули: %d Неподдържано KernelSU само поддържа GKI кернели за сега. Версия на кернела diff --git a/manager/app/src/main/res/values-bn-rBD/strings.xml b/manager/app/src/main/res/values-bn-rBD/strings.xml index 21416a1db4b8..409ba348fa31 100644 --- a/manager/app/src/main/res/values-bn-rBD/strings.xml +++ b/manager/app/src/main/res/values-bn-rBD/strings.xml @@ -6,6 +6,7 @@ মোডিউল ইনেবল করা যায়নি: %s ইন্সটল করটে চাপুন কাজ করছে + মোডিউল: %d অমূলক কর্নেল ম্যানেজার ভারসন @@ -31,6 +32,7 @@ মোডিউল ডিসেবল করা যায়নি: %s কোনো মোডিউল ইন্সটল করা নেই সংস্করণ: %d + সুপার ইউজার: %d নেইম স্পেস মাউন্ট ইনহেরিটেড ইন্ডিভিজুয়াল diff --git a/manager/app/src/main/res/values-bn/strings.xml b/manager/app/src/main/res/values-bn/strings.xml index 50d91ca4cb0c..f4e86d0c0ba1 100644 --- a/manager/app/src/main/res/values-bn/strings.xml +++ b/manager/app/src/main/res/values-bn/strings.xml @@ -5,6 +5,8 @@ ইনস্টল করার জন্য ক্লিক করুন ওয়ার্কিং ওয়ার্কিং সংস্করণ: %d + সুপার ইউজার: %d + মডিউল: %d অসমর্থিত KernelSU শুধুমাত্র GKI কার্নেল সমর্থন করে কার্নেল সংস্করণ diff --git a/manager/app/src/main/res/values-bs/strings.xml b/manager/app/src/main/res/values-bs/strings.xml index 0f47c42f67f4..23163d44719e 100644 --- a/manager/app/src/main/res/values-bs/strings.xml +++ b/manager/app/src/main/res/values-bs/strings.xml @@ -24,6 +24,8 @@ Početna Nije instalirano Kliknite da instalirate + Superkorisnici: %d + Module: %d Nepodržano KernelSU samo podržava GKI kernele sad Verzija Upravitelja diff --git a/manager/app/src/main/res/values-da/strings.xml b/manager/app/src/main/res/values-da/strings.xml index bb386fe9ad8c..732cba3e4de4 100644 --- a/manager/app/src/main/res/values-da/strings.xml +++ b/manager/app/src/main/res/values-da/strings.xml @@ -1,6 +1,7 @@ Arbejder + Moduler: %d Ikke understøttet Kernel-version KernelSU understøtter nu kun GKI-kerner. @@ -53,6 +54,7 @@ Version: %d Hjem Ikke installeret + Superbrugere: %d Fingeraftryk Ukendt Aktivering af modul fejlede: %s diff --git a/manager/app/src/main/res/values-de/strings.xml b/manager/app/src/main/res/values-de/strings.xml index 9451397bf084..e81bc2d2c7d1 100644 --- a/manager/app/src/main/res/values-de/strings.xml +++ b/manager/app/src/main/res/values-de/strings.xml @@ -7,6 +7,7 @@ Version: %d Superuser Tippe zum Installieren + Superuser: %d Unbekannt Erzwingen In den Bootloader-Modus neustarten @@ -39,6 +40,7 @@ Neue Version %s verfügbar, tippen zum Aktualisieren! Stopp erzwingen Neustarten + Module: %d Manager-Version SELinux Status Deaktiviert diff --git a/manager/app/src/main/res/values-es/strings.xml b/manager/app/src/main/res/values-es/strings.xml index 048f3733b5af..c5b767639660 100644 --- a/manager/app/src/main/res/values-es/strings.xml +++ b/manager/app/src/main/res/values-es/strings.xml @@ -5,6 +5,8 @@ Haz clic para instalar Funcionando Versión: %d + Superusuarios: %d + Módulos: %d Sin soporte KernelSU solo admite kernels GKI por ahora Versión del kernel diff --git a/manager/app/src/main/res/values-et/strings.xml b/manager/app/src/main/res/values-et/strings.xml index 294a68ea871a..66bf1e3ad52c 100644 --- a/manager/app/src/main/res/values-et/strings.xml +++ b/manager/app/src/main/res/values-et/strings.xml @@ -2,6 +2,7 @@ Töötamine Versioon: %d + Mooduleid: %d Tuum Manageri versioon Sõrmejälg @@ -33,6 +34,7 @@ Klõpsa paigaldamiseks Pole paigaldatud Mittetoetatud + Superkasutajaid: %d KernelSU toetab hetkel vaid GSI tuumasid SELinuxi olek Keelatud diff --git a/manager/app/src/main/res/values-fa/strings.xml b/manager/app/src/main/res/values-fa/strings.xml index 8000037eb778..f54fa5e5ab41 100644 --- a/manager/app/src/main/res/values-fa/strings.xml +++ b/manager/app/src/main/res/values-fa/strings.xml @@ -5,6 +5,8 @@ برای نصب ضربه بزنید به درستی کار می‌کند نسخه: %d + برنامه های با دسترسی روت: %d + ماژول‌ها: %d پشتیبانی نشده کرنل اس یو فقط هسته های gki را پشتیبانی میکند هسته diff --git a/manager/app/src/main/res/values-fil/strings.xml b/manager/app/src/main/res/values-fil/strings.xml index 22d911c0a642..f84912fd973e 100644 --- a/manager/app/src/main/res/values-fil/strings.xml +++ b/manager/app/src/main/res/values-fil/strings.xml @@ -10,6 +10,7 @@ Gumagana Bersyon: %d Hindi matukoy + Mga Modyul: %d Hindi Suportado Sinusuportahan lamang ng KernelSU ang mga GKI na kernel. Nabigong paganahin ang module: %s @@ -63,6 +64,7 @@ Minana Ang pangkalahatang default na halaga para sa \"Umount modules\" sa Mga Profile ng App. Kung pinagana, aalisin nito ang lahat ng mga pagbabago sa modyul sa system para sa mga aplikasyon na walang hanay ng Profile. I-save ang mga Log + Mga Superuser: %d Bersyon ng kernel Fingerprint Superuser diff --git a/manager/app/src/main/res/values-fr/strings.xml b/manager/app/src/main/res/values-fr/strings.xml index 74c33b45e84c..f1ba81a07dfb 100644 --- a/manager/app/src/main/res/values-fr/strings.xml +++ b/manager/app/src/main/res/values-fr/strings.xml @@ -3,6 +3,8 @@ Non installé Fonctionnel Version : %d + Super-utilisateurs : %d + Modules : %d KernelSU prend désormais en charge seulement les noyaux GKI, mais vous pouvez patcher l\'image pour les appareils GKI. Version du noyau Empreinte diff --git a/manager/app/src/main/res/values-hi/strings.xml b/manager/app/src/main/res/values-hi/strings.xml index d8e0db9657ef..231d6f289435 100644 --- a/manager/app/src/main/res/values-hi/strings.xml +++ b/manager/app/src/main/res/values-hi/strings.xml @@ -22,9 +22,11 @@ EDL मोड में रिबूट करें फिर से चालू करें क्षमताएं + सुपरयूजर : %d %s की डाउनलोडिंग स्टार्ट करें Global ऐप प्रोफाइल में \"अनमाउंट मॉड्यूल\" के लिए ग्लोबल डिफ़ॉल्ट वैल्यू। यदि चालू किया गया है, तो यह एप्लीकेशंस के लिऐ सिस्टम के सभी मॉड्यूल मोडिफिकेशन को हटा देगा जिनकी प्रोफ़ाइल सेट नहीं है। + मॉड्यूल्स : %d एनफोर्सिंग SELinux context फिंगरप्रिंट diff --git a/manager/app/src/main/res/values-hr/strings.xml b/manager/app/src/main/res/values-hr/strings.xml index bd6da57bb9ab..46578d539f29 100644 --- a/manager/app/src/main/res/values-hr/strings.xml +++ b/manager/app/src/main/res/values-hr/strings.xml @@ -10,6 +10,8 @@ Verzija: %d Kliknite da instalirate Radi + Superkorisnici: %d + Moduli: %d Nepodržano KernelSU sada samo podržava GKI kernele. Verzija kernela diff --git a/manager/app/src/main/res/values-hu/strings.xml b/manager/app/src/main/res/values-hu/strings.xml index b25111cb5ba4..08f1cd0717ea 100644 --- a/manager/app/src/main/res/values-hu/strings.xml +++ b/manager/app/src/main/res/values-hu/strings.xml @@ -2,6 +2,7 @@ Működik Verzió: %d + Modulok: %d A KernelSU jelenleg csak GKI kerneleket támogat Kernel Alkalmazás verziója @@ -45,6 +46,7 @@ Csatlakozzon a %2$s csatornánkhoz Kezdőlap Nincs telepítve Kattintson a telepítéshez + Engedélyezett alkalmazások: %d Nem támogatott SELinux állapot Kényszerített diff --git a/manager/app/src/main/res/values-in/strings.xml b/manager/app/src/main/res/values-in/strings.xml index 968d8b09b40b..2014395ca2e7 100644 --- a/manager/app/src/main/res/values-in/strings.xml +++ b/manager/app/src/main/res/values-in/strings.xml @@ -5,6 +5,8 @@ Ketuk untuk memasang Berfungsi Versi: %d + Superuser: %d + Modul: %d Tidak didukung KernelSU sekarang hanya mendukung kernel GKI, tetapi Anda dapat menambal image untuk perangkat GKI. Versi kernel @@ -47,7 +49,7 @@ Dukung Kami KernelSU akan selalu menjadi aplikasi gratis dan serta bersumber terbuka. Bagaimanapun juga, Anda dapat menunjukan kepedulian Anda kepada kami dengan memberikan sedikit donasi. Gabung saluran %2$s kami]]> - Profil Apl + Profil Aplikasi Default Templat Khusus @@ -69,6 +71,8 @@ Perbarui Mengunduh modul: %s Mulai mengunduh: %s + Mulai mengunduh + Gagal mengunduh: %s Versi baru %s tersedia, ketuk untuk memperbarui! Luncurkan Paksa berhenti @@ -99,6 +103,8 @@ Dapat digunakan untuk mendebug WebUI. Harap aktifkan hanya saat diperlukan. %1$s partisi image disarankan Pilih KMI + Pasang modul + Pasang AnyKernel Selanjutnya Perangkat Anda akan **DIPAKSA** untuk boot ke slot nonaktif saat ini setelah mulai ulang! \nGunakan hanya setelah proses OTA selesai. \nLanjutkan? Langsung pasang (Disarankan) @@ -134,6 +140,8 @@ Mengizinkan akses root melalui /system/bin/su, pada proses baru yang dibuat. Umount kernel Unmount modul dari kernel pada Profil Aplikasi. + Spoof Log AVC + Memperbaiki kebocoran konteks SELinux akibat penolakan AVC yang tercatat di log audit Memproses… Tarik ke bawah untuk menyegarkan Lepas untuk menyegarkan @@ -159,6 +167,10 @@ Gelap Warna utama Default + Gunakan ikon aplikasi resmi + Tampilan beranda klasik + Beralih ikon tombol + Gunakan animasi gulir Biru Merah Hijau @@ -177,6 +189,10 @@ Aktif (Default) Nonaktif hingga mulai ulang Selalu nonaktif + KernelSU Toolkit + Alat bantu untuk fitur tambahan KernelSU + KPatch Next + Implementasi mandiri dukungan KPM Buat pintasan Nama pintasan Pilih ikon khusus diff --git a/manager/app/src/main/res/values-it/strings.xml b/manager/app/src/main/res/values-it/strings.xml index 53f9a5819204..02fb380857f6 100644 --- a/manager/app/src/main/res/values-it/strings.xml +++ b/manager/app/src/main/res/values-it/strings.xml @@ -5,6 +5,8 @@ Clicca per installare In esecuzione Versione: %d + Applicazioni con accesso root: %d + Moduli installati: %d Non supportato KernelSU ora supporta solo i kernel GKI Kernel diff --git a/manager/app/src/main/res/values-iw/strings.xml b/manager/app/src/main/res/values-iw/strings.xml index b64a08016faf..8f6e4e65d776 100644 --- a/manager/app/src/main/res/values-iw/strings.xml +++ b/manager/app/src/main/res/values-iw/strings.xml @@ -22,9 +22,11 @@ הפעלה מחדש למצב EDL איתחול יכולת + משתמשי על: %d מפעיל מודל: %s גלובלי ערך ברירת המחדל הגלובלי עבור \"טעינת מודולים\" בפרופילי אפליקציה. אם מופעל, זה יסיר את כל שינויי המודול למערכת עבור יישומים שאין להם ערכת פרופיל. + מודלים:%d אכיפה הקשר SELinux טביעת אצבע diff --git a/manager/app/src/main/res/values-ja/strings.xml b/manager/app/src/main/res/values-ja/strings.xml index 0ea2348d116b..44d57809b540 100644 --- a/manager/app/src/main/res/values-ja/strings.xml +++ b/manager/app/src/main/res/values-ja/strings.xml @@ -5,6 +5,8 @@ タップしてインストール 動作中 バージョン: %d + スーパーユーザー: %d + モジュール: %d 非対応 KernelSU は現在 GKI カーネルのみをサポートしています。ただし、GKI デバイス向けにイメージにパッチを適用することは可能です。 カーネル diff --git a/manager/app/src/main/res/values-kn/strings.xml b/manager/app/src/main/res/values-kn/strings.xml index db651c171fbe..dbf65531f1bd 100644 --- a/manager/app/src/main/res/values-kn/strings.xml +++ b/manager/app/src/main/res/values-kn/strings.xml @@ -19,9 +19,11 @@ ಫೋರ್ಸ್ ಸ್ಟಾಪ್ EDL ಗೆ ರೀಬೂಟ್ ಸಾಮರ್ಥ್ಯಗಳು + ಸೂಪರ್‌ಯೂಸರ್‌ಗಳು: %d ಡೌನ್‌ಲೋಡ್ ಮಾಡುವುದನ್ನು ಪ್ರಾರಂಭಿಸಿ: %s ಜಾಗತಿಕ ಅಪ್ಲಿಕೇಶನ್ ಪ್ರೊಫೈಲ್‌ಗಳಲ್ಲಿ \"Umount ಮಾಡ್ಯೂಲ್\" ಗಾಗಿ ಜಾಗತಿಕ ಡೀಫಾಲ್ಟ್ ಮೌಲ್ಯ. ಸಕ್ರಿಯಗೊಳಿಸಿದರೆ, ಪ್ರೊಫೈಲ್ ಸೆಟ್ ಅನ್ನು ಹೊಂದಿರದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಸಿಸ್ಟಮ್‌ಗೆ ಎಲ್ಲಾ ಮಾಡ್ಯೂಲ್ ಮಾರ್ಪಾಡುಗಳನ್ನು ಇದು ತೆಗೆದುಹಾಕುತ್ತದೆ. + ಮಾಡ್ಯೂಲ್‌ಗಳು: %d SELinux ಸಂದರ್ಭ ಡೀಫಾಲ್ಟ್ ಲಾಂಚ್ diff --git a/manager/app/src/main/res/values-ko/strings.xml b/manager/app/src/main/res/values-ko/strings.xml index 48f7e177714f..da70294534b9 100644 --- a/manager/app/src/main/res/values-ko/strings.xml +++ b/manager/app/src/main/res/values-ko/strings.xml @@ -5,6 +5,8 @@ 이 곳을 눌러 설치하기 작동 중 버전: %d + 슈퍼유저: %d개 + 모듈: %d개 지원되지 않음 KernelSU는 현재 GKI 커널만 지원합니다. 커널 버전 diff --git a/manager/app/src/main/res/values-lt/strings.xml b/manager/app/src/main/res/values-lt/strings.xml index 15a2e8d937ab..d9fb6ddcafd8 100644 --- a/manager/app/src/main/res/values-lt/strings.xml +++ b/manager/app/src/main/res/values-lt/strings.xml @@ -58,8 +58,10 @@ KernelSU dabar palaiko tik GKI branduolius Spustelėkite norėdami įdiegti Veikia + Supernaudotojai: %d Versija: %d Nepalaikoma + Moduliai: %d Tvarkyklės versija Branduolys SELinux statusas diff --git a/manager/app/src/main/res/values-lv/strings.xml b/manager/app/src/main/res/values-lv/strings.xml index 6eeb688413d9..bc04972d74a0 100644 --- a/manager/app/src/main/res/values-lv/strings.xml +++ b/manager/app/src/main/res/values-lv/strings.xml @@ -13,6 +13,8 @@ Noklikšķiniet, lai uzstādītu Darbojas Versija: %d + Superlietotāji: %d + Moduļi: %d Neatbalstīts KernelSU pagaidām atbalsta tikai GKI kodolus Kodols diff --git a/manager/app/src/main/res/values-mr/strings.xml b/manager/app/src/main/res/values-mr/strings.xml index b1d37a5f91bb..651e710f810e 100644 --- a/manager/app/src/main/res/values-mr/strings.xml +++ b/manager/app/src/main/res/values-mr/strings.xml @@ -5,6 +5,8 @@ इंस्टॉल साठी क्लिक करा कार्यरत आवृत्ती: %d + मॉड्यूल्स: %d + सुपरयूझर: %d असमर्थित KernelSU आता फक्त GKI कर्नलचे समर्थन करते कर्नल diff --git a/manager/app/src/main/res/values-ms/strings.xml b/manager/app/src/main/res/values-ms/strings.xml index a2834bbd0b74..418d60d8a359 100644 --- a/manager/app/src/main/res/values-ms/strings.xml +++ b/manager/app/src/main/res/values-ms/strings.xml @@ -6,6 +6,8 @@ Reboot ke Download Modul tidak berjaya diaktifkan: %s Reboot ke EDL + Superusers: %d + Modul: %d Enforcing Cap Jari Reboot ke Recovery diff --git a/manager/app/src/main/res/values-nl/strings.xml b/manager/app/src/main/res/values-nl/strings.xml index 6797165e43dc..59a8f72034e1 100644 --- a/manager/app/src/main/res/values-nl/strings.xml +++ b/manager/app/src/main/res/values-nl/strings.xml @@ -5,6 +5,8 @@ Tik om te installeren Werkend Versie: %d + Supergebruikers: %d + Modules: %d Niet ondersteund KernelSU ondersteunt momenteel alleen GKI-kernels, maar je kunt de image patchen voor GKI-apparaten. Kernel version diff --git a/manager/app/src/main/res/values-pl/strings.xml b/manager/app/src/main/res/values-pl/strings.xml index 955d25900674..e9ac4c446259 100644 --- a/manager/app/src/main/res/values-pl/strings.xml +++ b/manager/app/src/main/res/values-pl/strings.xml @@ -1,11 +1,12 @@ - KernelSU Strona główna Nie zainstalowano Kliknij, aby zainstalować Działa Wersja: %d + Superużytkownicy: %d + Moduły: %d Nieobsługiwany KernelSU obsługuje obecnie tylko jądra GKI. Wersja jądra diff --git a/manager/app/src/main/res/values-pt-rBR/strings.xml b/manager/app/src/main/res/values-pt-rBR/strings.xml index f0d3b21f9829..1b88f049b18a 100644 --- a/manager/app/src/main/res/values-pt-rBR/strings.xml +++ b/manager/app/src/main/res/values-pt-rBR/strings.xml @@ -5,6 +5,8 @@ Clique para instalar Em execução Versão: %d + SuperUsuários: %d + Módulos: %d Sem suporte KernelSU suporta apenas kernels GKI agora Versão do kernel diff --git a/manager/app/src/main/res/values-pt/strings.xml b/manager/app/src/main/res/values-pt/strings.xml index 8fe87b18415f..6be35525ac08 100644 --- a/manager/app/src/main/res/values-pt/strings.xml +++ b/manager/app/src/main/res/values-pt/strings.xml @@ -4,6 +4,8 @@ Início Clique para instalar Funcionando + Super Usuário: %d + Módulos: %d Versão: %d Kernel Instalar diff --git a/manager/app/src/main/res/values-ro/strings.xml b/manager/app/src/main/res/values-ro/strings.xml index f0f0a1553078..f3e0381a98ec 100644 --- a/manager/app/src/main/res/values-ro/strings.xml +++ b/manager/app/src/main/res/values-ro/strings.xml @@ -5,6 +5,8 @@ Click pentru a instala Funcționează Versiune: %d + Super-utilizatori: %d + Module: %d Necompatibil KernelSU suportă doar nuclee GKI acum Nucleu diff --git a/manager/app/src/main/res/values-ru/strings.xml b/manager/app/src/main/res/values-ru/strings.xml index 9d15cbf3cee7..9395e02f81d2 100644 --- a/manager/app/src/main/res/values-ru/strings.xml +++ b/manager/app/src/main/res/values-ru/strings.xml @@ -5,7 +5,9 @@ Нажмите, чтобы установить Работает Версия: %d + Суперюзеры: %d + Модули: %d Не поддерживается Теперь KernelSU поддерживает только ядра GKI, однако вы всё ещё можете пропатчить образ для GKI-устройств. Версия ядра @@ -204,4 +206,86 @@ Янтарный Серо-голубой Сакура + Версия менеджера (%1$d) и версия драйвера KernelSU (%2$d) не совпадают. + Состояние Seccomp + Не поддерживается + Отключено + Строгий + Фильтр + Неизвестно + Файлы логов + Не удалось загрузить sulog + SU log не включен + SU log не поддерживается + Включить + Фильтр по типу + Очистить лог + Root execve + Классический SU + Выдача root доступа + Перезапуск демона + Неизвестное событие + Перехвачен запрос /system/bin/su + Запрос на выдачу root доступа + Выдан root доступ через KernelSU ioctl + Демон перезапущен + Отброшенные события + Мягкая перезагрузка + Режим jailbreak + Jailbreak + Jailbreak может быть неудачным, пожалуйста, проверьте логи + KernelSU Toolkit + Вспомогательный инструмент для дополнительных функций KernelSU. + KPatch Next + Самостоятельная реализация KPM. + Предиктивный жест назад + Включить поддержку предиктивного жеста назад + Это PR debug build. НЕ используйте его в production! + Ядро было собрано с поддержкой PR подписи. Это не production ядро! + Прошить модуль + Прошить AnyKernel + Вы в **Jailbreak mode**. Прошивка раздела на устройстве с **заблокированным загрузчиком** приведет к нарушению AVB (Android Verified Boot) и может вызвать сбой загрузки устройства.\n\nУбедитесь, что ваш загрузчик разблокирован перед продолжением! + Продолжить (%1$d) + SU Log + Записывать события, связанные с root-доступом, в файлы sulog KernelSU. + Подмена логов AVC + Исправить утечку selinux context, вызванную avc denial в audit log. + Включить Monet + Стиль интерфейса + Выберите стиль интерфейса. + Масштаб страницы + Задать глобальный масштаб отображения. + Использовать официальную иконку приложения + Цветовая спецификация + Цветовой стиль + Классический интерфейс домашнего экрана + Иконка переключателя + Использовать анимацию прокрутки + Размытие + Включить эффект размытия для верхней и нижней панелей. + Плавающая нижняя панель + Использовать стиль плавающей нижней панели Apple. + Жидкое стекло + Включить эффект жидкого стекла для плавающей нижней панели. + Сглаженные углы + Включить глобальные сглаженные закругленные углы. + Показывать только приложения основного пользователя + Автоматический jailbreak + Автоматически использовать Magica для повышения привилегий при обнаружении Permissive SELinux при загрузке. Требуется предоставление разрешения на автозапуск этому приложению. + Всегда предоставлять root для Shell + Всегда позволять adb shell вызывать su. Не включайте это, если только это абсолютно необходимо. + Принудительно включить adb при загрузке + Принудительно включить USB-отладку и отключить аутентификацию adb. Не включайте это, если только это абсолютно необходимо. + Продвинутые параметры + Развернуть + Скачивание модулей + Скачивание %s + Скачивание завершено + %s успешно скачан + Скачивание не удалось + Не удалось скачать %s + Скачать + Отмена + Установить + Запустить adbd демон с правами root diff --git a/manager/app/src/main/res/values-sl/strings.xml b/manager/app/src/main/res/values-sl/strings.xml index 12ed20d393be..361b423c0470 100644 --- a/manager/app/src/main/res/values-sl/strings.xml +++ b/manager/app/src/main/res/values-sl/strings.xml @@ -3,6 +3,7 @@ Klikni za namestitev V obdelavi Verzija: %d + Superuporabniki: %d KernelSU podpira samo GKI kernele Kernel Verzija upravitelja @@ -45,6 +46,7 @@ Dnevnik sprememb Predloga za aplikacijski profil Domov + Moduli: %d Ne podpira SuperUporabnik Napaka pri omogočanju modula: %s diff --git a/manager/app/src/main/res/values-sr/strings.xml b/manager/app/src/main/res/values-sr/strings.xml index 05693945d20d..0ed3db73ec6f 100644 --- a/manager/app/src/main/res/values-sr/strings.xml +++ b/manager/app/src/main/res/values-sr/strings.xml @@ -1,5 +1,7 @@ + Superkorisnici + Moduli: %d Додирните да бисте инсталирали Почетна Није инсталирано diff --git a/manager/app/src/main/res/values-te/strings.xml b/manager/app/src/main/res/values-te/strings.xml index 515cb6257146..24cdd12359d6 100644 --- a/manager/app/src/main/res/values-te/strings.xml +++ b/manager/app/src/main/res/values-te/strings.xml @@ -15,6 +15,8 @@ ఇన్‌స్టాల్ చేయడానికి క్లిక్ చేయండి పని చేస్తోంది వెర్షన్: %d + సూపర్‌యూజర్‌లు: %d + మాడ్యూల్స్: %d లాగ్‌లు సేవ్ చేయండి su బైనరీని మళ్ళించండి యాప్ ప్రొఫైల్‌లో సూపర్‌యూజర్ అనుమతి ఉన్న యాప్‌ల కోసం /system/bin/su ని ksud కి మళ్ళించండి; కొత్త ప్రాసెస్‌లకు మాత్రమే పని చేస్తుంది. diff --git a/manager/app/src/main/res/values-th/strings.xml b/manager/app/src/main/res/values-th/strings.xml index 2231943a0aae..1568603ad28f 100644 --- a/manager/app/src/main/res/values-th/strings.xml +++ b/manager/app/src/main/res/values-th/strings.xml @@ -6,6 +6,8 @@ กำลังทำงาน เวอร์ชัน: %d เวอร์ชันตัวจัดการ + สิทธิ์ผู้ใช้ขั้นสูง: %d + โมดูล: %d ไม่รองรับ Enforcing รีบูตเข้าสู่โหมดกู้คืน diff --git a/manager/app/src/main/res/values-tr/strings.xml b/manager/app/src/main/res/values-tr/strings.xml index 93860d457783..c4bf1d69e963 100644 --- a/manager/app/src/main/res/values-tr/strings.xml +++ b/manager/app/src/main/res/values-tr/strings.xml @@ -1,11 +1,12 @@ - KernelSU Ana Sayfa Kurulmadı Yüklemek için dokunun Çalışıyor Sürüm: %d + Süper kullanıcılar: %d + Modüller: %d Desteklenmiyor KernelSU şimdilik sadece GKI çekirdeklerini destekliyor Çekirdek Versiyonu diff --git a/manager/app/src/main/res/values-uk/strings.xml b/manager/app/src/main/res/values-uk/strings.xml index 02c20b14a692..12f97d370ca5 100644 --- a/manager/app/src/main/res/values-uk/strings.xml +++ b/manager/app/src/main/res/values-uk/strings.xml @@ -5,6 +5,8 @@ Натисніть щоб встановити Працює Версія: %d + Суперкористувачі: %d + Модулі: %d Не підтримується KernelSU зараз підтримує лише ядра GKI. Версія ядра diff --git a/manager/app/src/main/res/values-vi/strings.xml b/manager/app/src/main/res/values-vi/strings.xml index 428452d8f4fa..834715230564 100644 --- a/manager/app/src/main/res/values-vi/strings.xml +++ b/manager/app/src/main/res/values-vi/strings.xml @@ -13,6 +13,8 @@ Cập nhật Đang tải xuống module: %s Bắt đầu tải xuống: %s + Bắt đầu tải xuống + Tải xuống thất bại: %s Phiên bản mới %s đã có sẵn, nhấn để cập nhật! Tìm hiểu về KernelSU Tìm hiểu cách cài đặt KernelSU và sử dụng các module. @@ -61,6 +63,8 @@ Chế độ An toàn Khởi động lại để có hiệu lực https://kernelsu.org/guide/what-is-kernelsu.html + Superuser: %d + Module: %d Tên miền Quy tắc Khởi chạy @@ -87,6 +91,10 @@ Nhập/Xuất Lưu mẫu thất bại Chỉnh sửa mẫu + Hộp công cụ KernelSU + Các tính năng bổ sung của KernelSU. + KPatch Next + Triển khai hệ thống hỗ trợ KPM. Mẫu Hồ sơ ứng dụng Mô tả Lưu @@ -105,6 +113,8 @@ Thiết bị của bạn sẽ **BUỘC** phải khởi động vào phân vùng không hoạt động hiện tại sau khi khởi động lại!\nChỉ dùng tùy chọn này khi cập nhật OTA đã hoàn tất!\nTiếp tục? Gỡ cài đặt tạm thời KernelSU, khôi phục lại trạng thái ban đầu sau lần khởi động lại tiếp theo. Chọn KMI + Flashing AnyKernel + Flashing Module Kế tiếp Cài đặt trực tiếp (Khuyến nghị) Chọn file @@ -134,6 +144,8 @@ Cho phép truy cập root thông qua /system/bin/su, trong các tiến trình mới. Kernel umount Umount modules khỏi Kernel trong Hồ sơ ứng dụng. + Giả mạo nhật ký AVC + Khắc phục lỗi rò rỉ ngữ cảnh SELinux do từ chối AVC trong nhật ký. Đang xử lý… Kéo xuống để làm mới Thả để làm mới @@ -152,6 +164,10 @@ Sáng Tối Mặc định + Biểu tượng Bàn cờ + Trang chủ cổ điển + Công tắc hiện đại + Trượt để chuyển tab Xanh dương Đỏ Xanh lục diff --git a/manager/app/src/main/res/values-zh-rCN/strings.xml b/manager/app/src/main/res/values-zh-rCN/strings.xml index 173295fdfe15..0e5c289ebad6 100644 --- a/manager/app/src/main/res/values-zh-rCN/strings.xml +++ b/manager/app/src/main/res/values-zh-rCN/strings.xml @@ -5,6 +5,7 @@ 点击安装 工作中 版本:%d + 超级用户数:%d 不支持 KernelSU 现在只支持 GKI 内核,但是你可以为 GKI 设备补丁镜像。 管理器版本 (%1$d) 与 KernelSU 驱动版本 (%2$d) 不匹配。 @@ -59,6 +60,7 @@ 处于安全模式下,禁止安装模块 重启生效 因与 Magisk 有冲突,所有模块不可用! + 模块数:%d 了解 KernelSU https://kernelsu.org/zh_CN/guide/what-is-kernelsu.html 了解如何安装 KernelSU 以及如何开发模块 @@ -95,6 +97,10 @@ 为 %s 更新 SELinux 策略失败 无法授予 %s 超级用户权限 更新日志 + KernelSU 工具箱 + KernelSU 的附加功能。 + KPatch Next + KPM 支持的独立实现。 App Profile 模版 管理本地和在线的 App Profile 模版 创建模版 @@ -131,6 +137,8 @@ 选择一个文件 安装到未使用的槽位(OTA 后) 将在重启后强制切换到另一个槽位!注意只能在 OTA 更新完成后的重启之前使用 + 刷入模块 + 刷入 AnyKernel 当前处于**越狱模式**。在**未解锁 Bootloader** 的设备上刷写分区会破坏 AVB(Android 验证启动),可能导致设备**无法开机**。\n\n请确保 Bootloader 已解锁后再继续操作! 继续 (%1$d) 下一步 @@ -159,6 +167,8 @@ 允许通过 /system/bin/su 获取 Root 权限 卸载模块(内核级) 在内核给需要的应用卸载模块。 + avc 日志伪装 + 修复日志中 avc denial 导致的 selinux 上下文泄漏 将安装以下模块:%1$s 确认 处理中… @@ -184,6 +194,9 @@ 调整全局显示比例 色彩标准 色彩风格 + 经典主页样式 + 开关图表 + 使用滚动动画 蓝色 红色 绿色 diff --git a/manager/app/src/main/res/values-zh-rHK/strings.xml b/manager/app/src/main/res/values-zh-rHK/strings.xml index 56db2fb7528a..a036225d72d2 100644 --- a/manager/app/src/main/res/values-zh-rHK/strings.xml +++ b/manager/app/src/main/res/values-zh-rHK/strings.xml @@ -5,6 +5,8 @@ 按一下開始安裝 運作中 KernelSU 版本:%d + 超級使用者:%d 個 + 已安裝模組:%d 個 不支援 KernelSU 現僅支援 GKI 核心,但仍可修補 GKI 裝置映像。 核心版本 diff --git a/manager/app/src/main/res/values-zh-rTW/strings.xml b/manager/app/src/main/res/values-zh-rTW/strings.xml index 38c23c8af6b8..a6b1e0fffe08 100644 --- a/manager/app/src/main/res/values-zh-rTW/strings.xml +++ b/manager/app/src/main/res/values-zh-rTW/strings.xml @@ -5,6 +5,7 @@ 點選開始安裝 已開始運作 版本:%d + 授權:%d 個應用程式 未受支援 KernelSU 目前僅支援 GKI 核心 核心版本 @@ -41,6 +42,7 @@ 安全模式 將在重新啟動時生效 與 Magisk 發生衝突,無法使用模組功能! + 掛載:%d 個模組 深入瞭解 KernelSU https://kernelsu.org/zh_TW/guide/what-is-kernelsu.html 知曉安裝、使用 KernelSU 本體與其模組功能的方法 diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index a0cf291d7d97..105536998607 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -1,11 +1,14 @@ KernelSU + KowSU Home Not installed Tap to install Working Version: %d + Superusers: %d + Modules: %d Unsupported KernelSU only supports GKI kernels now, but you can patch the image for GKI devices. Manager version (%1$d) and KernelSU driver version (%2$d) mismatch. @@ -117,6 +120,10 @@ Failed to update SELinux rules for %s Couldn\'t grant Superuser access to %s Changelog + KernelSU Toolkit + Utility tool for KernelSU extra feature. + KPatch Next + Standalone implementation of KPM support. App Profile template Manage local and online template of App Profile. Create template @@ -153,6 +160,8 @@ Select a file Install to inactive slot (After OTA) Your device will be **FORCED** to boot to the current inactive slot after a reboot!\nOnly use this option after OTA is done.\nContinue? + Flash module + Flash AnyKernel You are in **Jailbreak mode**. Flashing a partition on a device with a **locked bootloader** will break AVB (Android Verified Boot) and may cause the device to **fail to boot**.\n\nMake sure your bootloader is unlocked before proceeding! Continue (%1$d) Next @@ -180,6 +189,8 @@ Unmount modules from kernel in App Profile. SU Log Record root-related events into KernelSU sulog files. + Avc log spoofing + Fix selinux context leak caused by avc denial in audit log. Kernel does not support this feature This feature is managed by a module Enable (Default) @@ -206,8 +217,12 @@ Choose the interface style. Page Scale Adjust the global display scale. + Use official app icon Color Spec Color Style + Classic Home UI + Switch icon + Use scroll animation Blue Red Green diff --git a/manager/build.gradle.kts b/manager/build.gradle.kts index 5fe66cec533d..ada71384c1ab 100644 --- a/manager/build.gradle.kts +++ b/manager/build.gradle.kts @@ -4,7 +4,7 @@ plugins { alias(libs.plugins.compose.compiler) apply false } -val androidMinSdkVersion by extra(31) +val androidMinSdkVersion by extra(29) val androidTargetSdkVersion by extra(37) val androidCompileSdkVersion by extra(37) val androidCompileSdkVersionMinor by extra(0) diff --git a/manager/scripts/update_binary.sh b/manager/scripts/update_binary.sh new file mode 100644 index 000000000000..d1fe0f20f6ee --- /dev/null +++ b/manager/scripts/update_binary.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +TMPDIR=/dev/tmp +rm -rf $TMPDIR +mkdir -p $TMPDIR 2>/dev/null + +ARCH="$(getprop ro.product.cpu.abi)" +OUTFD=/proc/self/fd/$2 + +ui_print() { + echo -e "ui_print $1\nui_print" >> $OUTFD +} + +if [ ! "$ARCH" = "arm64-v8a" ]; then + ui_print "- Unsupported architecture: $ARCH" + exit 1 +fi + +# Extract ksud and magiskboot +unzip -o "$3" "lib/$ARCH/libksud.so" "lib/$ARCH/libmagiskboot.so" -d $TMPDIR >&2 + +KSUD="$TMPDIR/lib/$ARCH/libksud.so" +MAGISKBOOT="$TMPDIR/lib/$ARCH/libmagiskboot.so" + +chmod 755 "$KSUD" "$MAGISKBOOT" + +# use ksud to install or uninstall +case "$3" in + *uninstall*|*Uninstall*) + ui_print "- Uninstalling KernelSU..." + "$KSUD" uninstall --magiskboot "$MAGISKBOOT" 2>&1 | while read -r line; do + ui_print "$line" + done + ;; + *) + ui_print "- Installing KernelSU..." + "$KSUD" boot-patch --magiskboot "$MAGISKBOOT" --flash 2>&1 | while read -r line; do + ui_print "$line" + done + ;; +esac + +true diff --git a/manager/scripts/updater_script.sh b/manager/scripts/updater_script.sh new file mode 100644 index 000000000000..ef91f34318f8 --- /dev/null +++ b/manager/scripts/updater_script.sh @@ -0,0 +1 @@ +# KernelSU installer/uninstaller script diff --git a/scripts/ksubot.py b/scripts/ksubot.py index 80604094d248..1dc63e427630 100644 --- a/scripts/ksubot.py +++ b/scripts/ksubot.py @@ -1,110 +1,161 @@ -import asyncio -import os -import sys -from telethon import TelegramClient -from telethon.tl.functions.help import GetConfigRequest - -API_ID = 611335 -API_HASH = "d524b414d21f4d37f08684c1df41ac9c" - - -BOT_TOKEN = os.environ.get("BOT_TOKEN") -CHAT_ID = os.environ.get("CHAT_ID") -MESSAGE_THREAD_ID = os.environ.get("MESSAGE_THREAD_ID") -COMMIT_URL = os.environ.get("COMMIT_URL") -COMMIT_MESSAGE = os.environ.get("COMMIT_MESSAGE") -RUN_URL = os.environ.get("RUN_URL") -TITLE = os.environ.get("TITLE") -VERSION = os.environ.get("VERSION") -BRANCH = os.environ.get("BRANCH") -MSG_TEMPLATE = """ -**{title}** -Branch: {branch} -#ci_{version} -``` -{commit_message} -``` -[Commit]({commit_url}) -[Workflow run]({run_url}) -""".strip() - - -def get_caption(): - msg = MSG_TEMPLATE.format( - title=TITLE, - branch=BRANCH, - version=VERSION, - commit_message=COMMIT_MESSAGE, - commit_url=COMMIT_URL, - run_url=RUN_URL, - ) - if len(msg) > 1024: - msg = COMMIT_URL - if BRANCH == "dev": - msg += "\n⚠️⚠️**DEV VERSION, PLEASE BACKUP BEFORE INSTALLATION**⚠️⚠️" - msg += "\n⚠️⚠️**测试版,安装前请备份**⚠️⚠️" - return msg - - -def check_environ(): - global CHAT_ID, MESSAGE_THREAD_ID - if BOT_TOKEN is None: - print("[-] Invalid BOT_TOKEN") - exit(1) - if CHAT_ID is None: - print("[-] Invalid CHAT_ID") - exit(1) - else: - CHAT_ID = int(CHAT_ID) - if COMMIT_URL is None: - print("[-] Invalid COMMIT_URL") - exit(1) - if COMMIT_MESSAGE is None: - print("[-] Invalid COMMIT_MESSAGE") - exit(1) - if RUN_URL is None: - print("[-] Invalid RUN_URL") - exit(1) - if TITLE is None: - print("[-] Invalid TITLE") - exit(1) - if VERSION is None: - print("[-] Invalid VERSION") - exit(1) - if BRANCH is None: - print("[-] Invalid BRANCH") - exit(1) - if MESSAGE_THREAD_ID is None: - print("[-] Invaild MESSAGE_THREAD_ID") - exit(1) - else: - MESSAGE_THREAD_ID = int(MESSAGE_THREAD_ID) - - -async def main(): - print("[+] Uploading to telegram") - check_environ() - files = sys.argv[1:] - print("[+] Files:", files) - if len(files) <= 0: - print("[-] No files to upload") - exit(1) - print("[+] Logging in Telegram with bot") - script_dir = os.path.dirname(os.path.abspath(sys.argv[0])) - session_dir = os.path.join(script_dir, "ksubot") - async with await TelegramClient(session=session_dir, api_id=API_ID, api_hash=API_HASH).start(bot_token=BOT_TOKEN) as bot: - caption = [""] * len(files) - caption[-1] = get_caption() - print("[+] Caption: ") - print("---") - print(caption) - print("---") - print("[+] Sending") - await bot.send_file(entity=CHAT_ID, file=files, caption=caption, reply_to=MESSAGE_THREAD_ID, parse_mode="markdown") - print("[+] Done!") - -if __name__ == "__main__": - try: - asyncio.run(main()) - except Exception as e: - print(f"[-] An error occurred: {e}") +import asyncio +import os +import sys +from telethon import TelegramClient +import json +import re + +API_ID = 611335 +API_HASH = "d524b414d21f4d37f08684c1df41ac9c" + + +BOT_TOKEN = os.environ.get("BOT_TOKEN") +CHAT_ID = os.environ.get("CHAT_ID") +MESSAGE_THREAD_ID = os.environ.get("MESSAGE_THREAD_ID") +TITLE = os.environ.get("TITLE") +VERSION = os.environ.get("VERSION") +BRANCH = os.environ.get("BRANCH") +RUN_URL = os.environ.get("RUN_URL") + +GITHUB_EVENT = json.loads(os.environ.get("GITHUB_EVENT")) + +commit_message = '' +commit_line = '' +upstream_diff = None +try: + if 'commits' in GITHUB_EVENT: + commits = GITHUB_EVENT['commits'] + commit_message = '' + i = len(commits) + for commit in commits[::-1]: + msg_line = commit['message'].split('\n') + msg = msg_line[0].strip() + if len(msg_line) > 1: + msg += ' [..]' + if len(msg) > 100: + msg = msg[:97] + '...' + msg += ' by ' + commit['author']['username'] + if len(msg) + 1 + len(commit_message) > 600: + commit_message = f'(other {i} commits)\n{commit_message}' + break + else: + commit_message = f'{msg}\n{commit_message}' + i -= 1 + commit_message = f'```{commit_message.strip()}\n```' + last_commit = commits[-1] + r = re.search(r'sync with upstream\s+https://github.com/tiann/KernelSU/commit/(.*)\s*', last_commit['message']) + if r is not None: + upstream_commit = r.group(1) + before_commit = GITHUB_EVENT['before'] + repo_url = GITHUB_EVENT['repository']['html_url'] + upstream_diff = f'[Upstream Update]({repo_url}/compare/{before_commit}...{upstream_commit})\n' + elif 'head_commit' in GITHUB_EVENT: + msg = GITHUB_EVENT["head_commt"]["msg"] + if len(msg) > 256: + msg = msg[:253] + '...' + commit_message = f'```\n{msg.strip()}\n```\n' + else: + commit_message = '' +except: + from traceback import print_exc + print_exc() + +if 'compare' in GITHUB_EVENT: + commit_url = GITHUB_EVENT['compare'] + commit_line = '[Compare](' + commit_url + ')\n' +elif 'head_commit' in GITHUB_EVENT: + commit_url = GITHUB_EVENT['head_commit']['url'] + commit_line = '[Commit](' + commit_url + ')\n' +else: + commit_line = '' + +if upstream_diff is not None: + commit_message += upstream_diff + +MSG_TEMPLATE = """ +**{title}** +Branch: {branch} +#ci_{version} +{commit_message}{commit_url}[Workflow run]({run_url}) +""".strip() + + +def get_caption(): + msg = MSG_TEMPLATE.format( + title=TITLE, + branch=BRANCH, + version=VERSION, + commit_message=commit_message, + commit_url=commit_line, + run_url=RUN_URL, + ) + if len(msg) > 1024: + msg = COMMIT_URL + if BRANCH == "dev": + msg += "\n⚠️⚠️**DEV VERSION, PLEASE BACKUP BEFORE INSTALLATION**⚠️⚠️" + msg += "\n⚠️⚠️**测试版,安装前请备份**⚠️⚠️" + return msg + + +def check_environ(): + global CHAT_ID, MESSAGE_THREAD_ID + if BOT_TOKEN is None: + print("[-] Invalid BOT_TOKEN") + exit(1) + if CHAT_ID is None: + print("[-] Invalid CHAT_ID") + exit(1) + else: + try: + CHAT_ID = int(CHAT_ID) + except: + pass + if RUN_URL is None: + print("[-] Invalid RUN_URL") + exit(1) + if TITLE is None: + print("[-] Invalid TITLE") + exit(1) + if VERSION is None: + print("[-] Invalid VERSION") + exit(1) + if BRANCH is None: + print("[-] Invalid BRANCH") + exit(1) + if MESSAGE_THREAD_ID is not None and MESSAGE_THREAD_ID != "": + try: + MESSAGE_THREAD_ID = int(MESSAGE_THREAD_ID) + except: + print("[-] Invaild MESSAGE_THREAD_ID") + exit(1) + else: + MESSAGE_THREAD_ID = None + + +async def main(): + print("[+] Uploading to telegram") + check_environ() + files = sys.argv[1:] + print("[+] Files:", files) + if len(files) <= 0: + print("[-] No files to upload") + exit(1) + print("[+] Logging in Telegram with bot") + script_dir = os.path.dirname(os.path.abspath(sys.argv[0])) + session_dir = os.path.join(script_dir, "ksubot") + async with await TelegramClient(session=session_dir, api_id=API_ID, api_hash=API_HASH).start(bot_token=BOT_TOKEN) as bot: + caption = [""] * len(files) + caption[-1] = get_caption() + print("[+] Caption: ") + print("---") + print(caption) + print("---") + print("[+] Sending") + await bot.send_file(entity=CHAT_ID, file=files, caption=caption, reply_to=MESSAGE_THREAD_ID, parse_mode="markdown") + print("[+] Done!") + +if __name__ == "__main__": + try: + asyncio.run(main()) + except Exception as e: + print(f"[-] An error occurred: {e}") diff --git a/uapi/feature.h b/uapi/feature.h index cacff4615b89..1c0550320020 100644 --- a/uapi/feature.h +++ b/uapi/feature.h @@ -7,6 +7,8 @@ enum ksu_feature_id { KSU_FEATURE_SULOG = 2, KSU_FEATURE_ADB_ROOT = 3, + KSU_FEATURE_AVC_SPOOF = 10003, + KSU_FEATURE_MAX }; diff --git a/userspace/ksud/bin/arm/busybox b/userspace/ksud/bin/arm/busybox new file mode 100755 index 000000000000..aded8cfaec78 Binary files /dev/null and b/userspace/ksud/bin/arm/busybox differ diff --git a/userspace/ksud/src/assets.rs b/userspace/ksud/src/assets.rs index 8218409ce42d..13bf8f7f4c41 100644 --- a/userspace/ksud/src/assets.rs +++ b/userspace/ksud/src/assets.rs @@ -36,13 +36,18 @@ mod android { #[cfg(target_os = "android")] pub use android::*; +#[cfg(all(target_arch = "arm", target_os = "android"))] +#[derive(RustEmbed)] +#[folder = "bin/arm"] +struct Asset; + #[cfg(all(target_arch = "x86_64", target_os = "android"))] #[derive(RustEmbed)] #[folder = "bin/x86_64"] struct Asset; -// IF NOT x86_64 ANDROID, ie. macos, linux, windows, always use aarch64 -#[cfg(not(all(target_arch = "x86_64", target_os = "android")))] +// IF NOT x86_64 or arm ANDROID, ie. macos, linux, windows, always use aarch64 +#[cfg(all(not(all(target_arch = "x86_64", target_os = "android")), not(target_arch = "arm")))] #[derive(RustEmbed)] #[folder = "bin/aarch64"] struct Asset; diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs index a5835893a9d1..aff412c63b74 100644 --- a/userspace/ksud/src/cli.rs +++ b/userspace/ksud/src/cli.rs @@ -58,7 +58,7 @@ enum Commands { kmi: Option, /// manager package name - #[arg(long, default_value_t = String::from("me.weishu.kernelsu"))] + #[arg(long, default_value_t = String::from("com.kowx712.supermanager"))] package_name: String, }, @@ -92,7 +92,7 @@ enum Commands { #[arg(long, default_value = None)] magiskboot: Option, - #[arg(long, default_value_t = String::from("me.weishu.kernelsu"))] + #[arg(long, default_value_t = String::from("com.kowx712.supermanager"))] package_name: String, }, @@ -175,7 +175,7 @@ enum Debug { /// Set the manager app, kernel CONFIG_KSU_DEBUG should be enabled. SetManager { /// manager package name - #[arg(default_value_t = String::from("me.weishu.kernelsu"))] + #[arg(default_value_t = String::from("com.kowx712.supermanager"))] apk: String, }, diff --git a/userspace/ksud/src/feature.rs b/userspace/ksud/src/feature.rs index 7c838d238f4d..e244a35eb80d 100644 --- a/userspace/ksud/src/feature.rs +++ b/userspace/ksud/src/feature.rs @@ -20,6 +20,7 @@ pub enum FeatureId { KernelUmount = 1, Sulog = 2, AdbRoot = 3, + AvcSpoof = 10003, } impl FeatureId { @@ -29,6 +30,7 @@ impl FeatureId { 1 => Some(Self::KernelUmount), 2 => Some(Self::Sulog), 3 => Some(Self::AdbRoot), + 10003 => Some(Self::AvcSpoof), _ => None, } } @@ -39,6 +41,7 @@ impl FeatureId { Self::KernelUmount => "kernel_umount", Self::Sulog => "sulog", Self::AdbRoot => "adb_root", + Self::AvcSpoof => "avc_spoof", } } @@ -54,6 +57,9 @@ impl FeatureId { "SU Log - streams kernel sulog events to userspace and persists them to disk" } Self::AdbRoot => "ADB Root - Enable adbd root", + Self::AvcSpoof => { + "AVC Spoof - fix selinux context leak due to avc denial" + } } } } @@ -64,6 +70,7 @@ fn parse_feature_id(name: &str) -> Result { "kernel_umount" | "1" => Ok(FeatureId::KernelUmount), "sulog" | "2" => Ok(FeatureId::Sulog), "adb_root" | "3" => Ok(FeatureId::AdbRoot), + "avc_spoof" | "10003" => Ok(FeatureId::AvcSpoof), _ => bail!("Unknown feature: {name}"), } } @@ -309,6 +316,7 @@ pub fn list_features() { FeatureId::KernelUmount, FeatureId::Sulog, FeatureId::AdbRoot, + FeatureId::AvcSpoof, ]; for feature_id in &all_features { @@ -371,6 +379,7 @@ pub fn save_config() -> Result<()> { FeatureId::KernelUmount, FeatureId::Sulog, FeatureId::AdbRoot, + FeatureId::AvcSpoof, ]; for feature_id in &all_features {