[
  {
    "path": ".gitattributes",
    "content": "# Set the default behavior, in case people don't have core.autocrlf set.\n* text eol=lf\n\n# Explicitly declare text files you want to always be normalized and converted\n# to native line endings on checkout.\n# *.c text\n# *.h text\n\n# Declare files that will always have CRLF line endings on checkout.\n*.cmd text eol=crlf\n*.bat text eol=crlf\n\n# Denote all files that are truly binary and should not be modified.\ntools/** binary\n*.jar binary\n*.exe binary\n*.apk binary\n*.png binary\n*.jpg binary\n*.ttf binary\n*.so binary\n\n# Help GitHub detect languages\nnative/jni/external/** linguist-vendored\nnative/jni/systemproperties/** linguist-language=C++\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug report | 反馈 Bug\ndescription: Report bugs or unexpected behavior | 报告错误或未预料的行为\nlabels: [bug]\n\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for reporting issues of APatch!\n        To better assist you, please provide the following information.\n        To avoid duplicate issues, please use English in the title.\n        For KernelPatch specific issues (e.g., patching failures, kernel panics, etc.), please report them at: [KernelPatch](https://github.com/bmax121/KernelPatch)\n\n        感谢给 APatch 汇报问题！\n        为了使我们更好地帮助你，请提供以下信息。\n        为了防止重复汇报，标题请务必使用英文。\n        如果是 KernelPatch 的问题（例如修补失败，内核崩溃等），请移步 [KernelPatch 仓库](https://github.com/bmax121/KernelPatch)。\n        \n\n  - type: checkboxes\n    attributes:\n       label: Please check before submitting an issue | 在提交 Issue 前请检查\n       options:\n          - label: I searched the issues and didn't found anything relevant | 我已经搜索了 Issues 列表，没有发现于本问题相关内容\n            required: true\n\n          - label: If the patch fails or the image cannot be booted after flashing the new boot.img, visit KernelPatch to clarify your doubts | 修复失败或刷入修补后镜像不能启动，请前往 KernelPatch 提问\n            required: true\n\n          - label: I will upload the bug report file in APatch Manager > Settings > Send logs | 我会上传 Bug Report 文件从 APatch 管理器 > 设置 > 发送日志\n            required: true\n\n          - label: I know how to reproduce the issue, which might not be specific to my device | 我知道如何重新复现这个问题\n            required: false\n\n  - type: checkboxes\n    id: latest\n    attributes:\n      label: Version requirements | 版本要求\n      options:\n        - label: I'm using the latest CI version of APatch Manager | 我正在使用最新 CI 版本\n          required: true\n\n  - type: textarea\n    attributes:\n        label: Bug description | 描述 Bug\n        description: |\n          Please enter a clear and concise description of the bug.  \n          对 Bug 的清晰简洁的描述。\n    validations:\n        required: true\n\n  - type: textarea\n    attributes:\n        label: Reproduce method | 复现方法\n        description: |\n          Steps to reproduce the bug.  \n          复现的步骤。\n        placeholder: |\n          - 1. Go to...\n          - 2. Click on...\n          - 3. Scroll down to...\n          - 4. See error\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n        label: Expected behavior | 预期行为\n        description: |\n          Please enter a clear and concise description of what you expected to happen.  \n          对你期望发生的行为进行清晰简洁的描述。\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n        label: Actual behavior | 实际行为\n        description: |\n          Tell us what actually happened.  \n          告诉我们实际发生了什么。\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n        label: Screenshots | 截图\n        description: |\n          If possible, add screenshots to help explain your issue.  \n          如果可以的话，添加截图可以帮你解释问题。\n\n  - type: textarea\n    attributes:\n        label: Logs | 日志\n        description: |\n          If possible, add the crash log to help us find your issue.  \n          如果可以的话，添加崩溃日志可以帮助我们找到问题。\n\n  - type: input\n    attributes:\n      label: Device name | 设备名称\n    validations:\n      required: true\n\n  - type: input\n    attributes:\n      label: OS version | 系统版本\n    validations:\n      required: true\n\n  - type: input\n    attributes:\n      label: APatch version | APatch 版本\n    validations:\n      required: true\n\n  - type: input\n    attributes:\n      label: Kernel version | 内核版本\n    validations:\n      required: true\n\n  - type: input\n    attributes:\n      label: KernelPatch version | KernelPatch 版本\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n        label: Other information | 其他信息\n        description: |\n          Add any information about the issue.  \n          添加关于问题的任何信息。\n        placeholder: |\n          Upload logs in .zip format by clicking the bottom bar. Uploading logs to other websites or using external links isn't allowed  \n          点击文本框底栏上传日志压缩包，禁止上传到其它网站或使用外链提供日志\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Ask a question | 提问\n    url: https://github.com/bmax121/APatch/discussions/new?category=Q-A\n    about: If you've any questions, ask them here | 如果有任何疑问请在这里提问\n  - name: Official Telegram channel | 官方 Telegram 频道\n    url: https://t.me/APatchChannel\n    about: Subscribe to receive releases and announcements | 可以订阅通知和发行版\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "---\nname: Feature request | 新特性请求\ndescription: Suggest an idea for this project | 提出建议\nlabels: [enhancement]\n\nbody:\n  - type: textarea\n    attributes:\n      label: Is your request related to a specific issue? | 你的请求是否与某个问题相关？\n      description: |\n        Please enter a clear and concise description of the issue.  \n        请清晰准确表述该问题。\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n      label: Describe the solution you'd like | 描述你想要的解决方案\n      description: |\n        Please enter a clear and concise description of what you'd like.  \n        请清晰准确描述新特性的预期行为。\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n      label: Describe the alternatives you've considered | 描述您考虑过的备选方案\n      description: |\n        Please enter a clear and concise description of any alternative solutions or features you've considered.  \n        对您考虑过的任何替代解决方案或功能的清晰简洁的描述。\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n      label: Other information | 其他信息\n      description: |\n        Add any information or screenshots about the feature request.  \n        其他关于新特性的信息或者截图。\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: gradle\n    directory: \"/\"\n    schedule:\n      interval: daily\n    target-branch: main\n    registries:\n      - maven-google\n      - gradle-plugin\n    groups:\n      maven-dependencies:\n        patterns:\n          - \"*\"\n\n  - package-ecosystem: github-actions\n    target-branch: main\n    directory: /\n    schedule:\n      interval: daily\n    groups:\n      action-dependencies:\n        patterns:\n          - \"*\"\n\n  - package-ecosystem: cargo\n    target-branch: main\n    directory: apd/\n    schedule:\n      interval: daily\n    allow:\n      - dependency-type: \"all\"\n    groups:\n      rust-dependencies:\n        patterns:\n          - \"*\"\n\nregistries:\n  maven-google:\n    type: maven-repository\n    url: \"https://dl.google.com/dl/android/maven2/\"\n  gradle-plugin:\n    type: maven-repository\n    url: \"https://plugins.gradle.org/m2/\"\n"
  },
  {
    "path": ".github/scripts/telegram_url.py",
    "content": "import json\nimport os\nimport sys\nimport urllib.parse\n\nurl = f'https://api.telegram.org/bot{os.environ[\"BOT_TOKEN\"]}'\nurl += f'/sendMediaGroup?chat_id={urllib.parse.quote(sys.argv[1])}&media='\n\n# https://core.telegram.org/bots/api#markdownv2-style\nmsg = os.environ[\"COMMIT_MESSAGE\"]\nfor c in ['\\\\', '_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!']:\n    msg = msg.replace(c, f'\\\\{c}')\ncommit_url = os.environ[\"COMMIT_URL\"]\ncommit_id = os.environ[\"COMMIT_ID\"][:7]\n\ncaption = f\"[{commit_id}]({commit_url})\\n{msg}\"[:1024]\n\ndata = json.dumps([\n    {\"type\": \"document\", \"media\": \"attach://Release1\"},\n    {\"type\": \"document\", \"media\": \"attach://Release2\", \"caption\": caption, \"parse_mode\": \"MarkdownV2\"}\n])\n\nurl += urllib.parse.quote(data)\nprint(url)"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build Manager\n\non:\n  push:\n    tags: [ \"*\" ]\n    branches: [ \"main\" ]\n    paths:\n      - '.github/workflows/build.yml'\n      - 'app/**'\n      - 'apd/**'\n      - 'build.gradle.kts'\n      - 'gradle/libs.versions.toml'\n  pull_request:\n    branches: [ \"main\" ]\n    paths:\n      - '.github/workflows/build.yml'\n      - 'app/**'\n      - 'apd/**'\n      - 'build.gradle.kts'\n      - 'gradle/libs.versions.toml'\n  workflow_call:\n  workflow_dispatch:\n\njobs:\n  build-manager:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n\n      - name: Generate version\n        id: parse_version\n        run: |\n          COMMIT_NUM=$(git rev-list --count HEAD)\n          VERSION=$(echo \"$COMMIT_NUM + 200 + 10000\" | bc)\n          echo \"Generated Version: $VERSION\"\n          echo \"VERSION=$VERSION\" >> $GITHUB_OUTPUT\n\n      - name: Setup Java\n        uses: actions/setup-java@v5\n        with:\n          distribution: jetbrains\n          java-version: 21\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v5\n\n      - name: Setup Android SDK\n        uses: android-actions/setup-android@v3\n        with:\n          packages: ''\n\n      - name: Install toolchain\n        run: |\n          rustup default stable\n          rustup update stable\n          cargo install cargo-ndk\n          rustup target install aarch64-linux-android\n\n      - name: Cache Rust\n        uses: Swatinem/rust-cache@v2\n        with:\n          workspaces: apd\n          cache-targets: false\n\n      - name: Build with Gradle\n        run: |\n          echo 'org.gradle.parallel=true' >> gradle.properties\n          echo 'org.gradle.vfs.watch=true' >> gradle.properties\n          echo 'org.gradle.jvmargs=-Xmx2048m' >> gradle.properties\n          echo 'android.native.buildOutput=verbose' >> gradle.properties\n          sed -i 's/org.gradle.configuration-cache=true//g' gradle.properties\n          ./gradlew clean assembleDebug assembleRelease\n          echo \"BUILD_TOOL_VERSION=$(ls /usr/local/lib/android/sdk/build-tools/ | tail -n 1)\" >> $GITHUB_ENV\n\n      - name: Sign Release\n        env:\n          SIGNING_KEY: ${{ secrets.SIGNING_KEY }}\n          BUILD_TOOLS_VERSION: ${{ env.BUILD_TOOL_VERSION }}\n        if: ${{ env.SIGNING_KEY != '' }}\n        continue-on-error: true\n        uses: kevin-david/zipalign-sign-android-release@v2\n        id: sign_app\n        with:\n          releaseDirectory: app/build/outputs/apk/release\n          signingKeyBase64: ${{ secrets.SIGNING_KEY }}\n          alias: ${{ secrets.ALIAS }}\n          keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}\n          keyPassword: ${{ secrets.KEY_PASSWORD }}\n          zipAlign: true\n\n      - name: Sign Debug APK\n        env:\n          SIGNING_KEY: ${{ secrets.SIGNING_KEY }}\n          BUILD_TOOLS_VERSION: ${{ env.BUILD_TOOL_VERSION }}\n        if: ${{ env.SIGNING_KEY != '' }}\n        continue-on-error: true\n        uses: kevin-david/zipalign-sign-android-release@v2\n        id: sign_debug_app\n        with:\n          releaseDirectory: app/build/outputs/apk/debug\n          signingKeyBase64: ${{ secrets.SIGNING_KEY }}\n          alias: ${{ secrets.ALIAS }}\n          keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}\n          keyPassword: ${{ secrets.KEY_PASSWORD }}\n          zipAlign: true\n\n      - name: Upload mappings\n        uses: actions/upload-artifact@v6\n        with:\n          name: \"mappings\"\n          path: \"app/build/outputs/mapping/release/\"\n\n      - name: Upload build artifact1\n        env:\n          SIGNING_KEY: ${{ secrets.SIGNING_KEY }}\n        if: ${{ env.SIGNING_KEY != '' }}\n        uses: actions/upload-artifact@v6\n        with:\n          name: APatch-Release\n          path: |\n            ${{ steps.sign_app.outputs.signedReleaseFile }}\n\n      - name: Upload build artifact2\n        env:\n          SIGNING_KEY: ${{ secrets.SIGNING_KEY }}\n        if: ${{ env.SIGNING_KEY != '' }}\n        uses: actions/upload-artifact@v6\n        with:\n          name: APatch-Debug\n          path: |\n            ${{ steps.sign_debug_app.outputs.signedReleaseFile }}\n\n      - name: Post to channel\n        if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && github.ref_type != 'tag' }}\n        env:\n          BOT_TOKEN: ${{ secrets.BOT_TOKEN }}\n          COMMIT_MESSAGE: ${{ github.event.head_commit.message }}\n          COMMIT_URL: ${{ github.event.head_commit.url }}\n          COMMIT_ID: ${{ github.event.head_commit.id }}\n        run: |\n          if [ -n \"${BOT_TOKEN}\" ]; then\n            CHANNELS=(-1002058433411 -1001910818234)\n            RELEASE_APK=\"${{ steps.sign_app.outputs.signedReleaseFile }}\"\n            DEBUG_APK=\"${{ steps.sign_debug_app.outputs.signedReleaseFile }}\"\n          \n            for CHANNEL in \"${CHANNELS[@]}\"; do\n              URL=$(python3 .github/scripts/telegram_url.py $CHANNEL)\n              if [ -f \"$RELEASE_APK\" ] && [ -f \"$DEBUG_APK\" ]; then\n                curl -v \"$URL\" -F \"Release1=@$RELEASE_APK\" -F \"Release2=@$DEBUG_APK\"\n              fi\n            done\n          fi\n\n      - name: Release apk\n        env:\n          SIGNING_KEY: ${{ secrets.SIGNING_KEY }}\n        if: ${{ env.SIGNING_KEY != '' && github.ref_type == 'tag' }}\n        continue-on-error: true\n        uses: ncipollo/release-action@v1\n        with:\n          token: ${{ github.token }}\n          tag: ${{ steps.parse_version.outputs.VERSION }}\n          artifacts: ${{steps.sign_app.outputs.signedReleaseFile}}\n          generateReleaseNotes: true\n          makeLatest: true\n          replacesArtifacts: true\n"
  },
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\nlocal.properties\n.idea\n.DS_Store\nbuild\ncaptures\n.cxx\nkey.jks\nkey.jks.base64.txt\n.vscode\n.kotlin\napp/src/main/resources/\nprivate\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n<a href=\"https://github.com/bmax121/APatch/releases/latest\"><img src=\"https://images.weserv.nl/?url=https://raw.githubusercontent.com/bmax121/APatch/main/app/src/main/ic_launcher-playstore.png&mask=circle\" style=\"width: 128px;\" alt=\"logo\"></a>\n\n<h1 align=\"center\">APatch</h1>\n\n[![Latest Release](https://img.shields.io/github/v/release/bmax121/APatch?label=Release&logo=github)](https://github.com/bmax121/APatch/releases/latest)\n[![Nightly Release](https://img.shields.io/badge/Nightly%20release-gray?logo=hackthebox&logoColor=fff)](https://nightly.link/bmax121/APatch/workflows/build/main/APatch)\n[![Weblate](https://img.shields.io/badge/Localization-Weblate-teal?logo=weblate)](https://hosted.weblate.org/engage/APatch)\n[![Channel](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/APatchGroup)\n[![GitHub License](https://img.shields.io/github/license/bmax121/APatch?logo=gnu)](/LICENSE)\n\n</div>\n\nThe patching of Android kernel and Android system.\n\n- A new kernel-based root solution for Android devices.\n- APM: Support for modules similar to Magisk.\n- KPM: Support for modules that allow you to inject any code into the kernel (Provides kernel function `inline-hook` and `syscall-table-hook`).\n- APatch relies on [KernelPatch](https://github.com/bmax121/KernelPatch/).\n- The APatch UI and the APModule source code have been derived and modified from [KernelSU](https://github.com/tiann/KernelSU).\n\n[<img src=\"https://fdroid.gitlab.io/artwork/badge/get-it-on.png\"\n     alt=\"Get it on F-Droid\"\n     height=\"80\">](https://f-droid.org/packages/me.bmax.apatch/)\n\nOr download the latest APK from the [Releases Section](https://github.com/bmax121/APatch/releases/latest).\n\n## Supported Versions\n\n- Only supports the ARM64 architecture.\n- Only supports Android kernel versions 3.18 - 6.12\n\nSupport for Samsung devices with security protection: Planned\n\n## Requirement\n\nKernel configs:\n\n- `CONFIG_KALLSYMS=y` and `CONFIG_KALLSYMS_ALL=y`\n\n- `CONFIG_KALLSYMS=y` and `CONFIG_KALLSYMS_ALL=n`: Initial support\n\n## Security Alert\n\nThe **SuperKey** has higher privileges than root access.  \nWeak or compromised keys can lead to unauthorized control of your device.  \nIt is critical to use robust keys and safeguard them from exposure to maintain the security of your device.\n\n## Translation\n\nTo help translate APatch or improve existing translations, please use [Weblate](https://hosted.weblate.org/engage/apatch/). PR of APatch translation is no longer accepted, because it will conflict with Weblate.\n\n<div align=\"center\">\n\n[![Translation Status](https://hosted.weblate.org/widget/APatch/open-graph.png)](https://hosted.weblate.org/engage/APatch/)\n\n</div>\n\n## Get Help\n\n### Usage\n\nFor usage, please refer to [our official documentation](https://apatch.dev).  \nIt's worth noting that the documentation is currently not quite complete, and the content may change at any time.  \nFurthermore, we need more volunteers to [contribute to the documentation](https://github.com/AndroidPatch/APatchDocs) in other languages.\n\n### Updates\n\n- Telegram Channel: [@APatchUpdates](https://t.me/APatchChannel)\n\n### Discussions\n\n- Telegram Group: [@APatchDiscussions(EN/CN)](https://t.me/Apatch_discuss)\n- Telegram Group: [中文](https://t.me/APatch_CN_Group)\n\n### More Information\n\n- [Documents](docs/)\n\n## Credits\n\n- [KernelPatch](https://github.com/bmax121/KernelPatch/): The core.\n- [Magisk](https://github.com/topjohnwu/Magisk): magiskpolicy.\n- [KernelSU](https://github.com/tiann/KernelSU): App UI, and Magisk module like support.\n\n## License\n\nAPatch is licensed under the GNU General Public License v3 [GPL-3](http://www.gnu.org/copyleft/gpl.html).\n"
  },
  {
    "path": "apd/.gitignore",
    "content": "/target\n.cargo/"
  },
  {
    "path": "apd/Cargo.toml",
    "content": "[package]\nname = \"apd\"\nversion = \"0.1.0\"\nedition = \"2024\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nmlua = { version = \"0.11.5\", features = [\"lua54\",\"vendored\"] }\nanyhow = \"1\"\ncsv = \"1.3.1\"\nclap = { version = \"4\", features = [\"derive\"] }\nconst_format = \"0.2\"\nzip = { version = \"7.2.0\",features = [\n    \"deflate\",\n    \"deflate64\",\n    \"time\",\n    \"lzma\",\n    \"xz\",\n], default-features = false }\nzip-extensions = { git = \"https://github.com/AndroidPatch/zip-extensions-rs.git\", branch = \"master\", features = [\n    \"deflate\",\n    \"lzma\",\n    \"xz\",\n], default-features = false }\njava-properties = { git = \"https://github.com/AndroidPatch/java-properties.git\", branch = \"master\", default-features = false }\nlog = \"0.4\"\nenv_logger = \"0.11\"\nserde = { version = \"1\", features = [\"derive\"] }\nserde_json = \"1\"\nencoding_rs = \"0.8\"\nwalkdir=\"2.4\"\nretry = \"2\"\nlibc = \"0.2\"\nextattr = \"1\"\njwalk = \"0.8\"\nis_executable = \"1\"\nnom = \"8\"\nderive-new = \"0.7.0\"\nwhich = \"8\"\ngetopts = \"0.2\"\nerrno = \"0.3.14\"\nnotify = \"8.2\"\nsignal-hook = \"0.4\"\n\n[target.'cfg(any(target_os = \"android\", target_os = \"linux\"))'.dependencies]\nrustix = { version = \"1\", features = [\"all-apis\"] }\n# some android specific dependencies which compiles under unix are also listed here for convenience of coding\nandroid-properties = { version = \"0.2.2\", features = [\"bionic-deprecated\"] }\nprocfs = \"0.18\"\nloopdev = { git = \"https://github.com/AndroidPatch/loopdev\" }\n\n[target.'cfg(target_os = \"android\")'.dependencies]\nandroid_logger = { version = \"0.15\", default-features = false }\n\n[profile.release]\nstrip = true\noverflow-checks = false\nrpath = false\nopt-level = 3\ncodegen-units = 1\npanic = \"abort\"\nlto = \"fat\"\n"
  },
  {
    "path": "apd/build.rs",
    "content": "use std::env;\nuse std::fs::File;\nuse std::io::Write;\nuse std::path::Path;\nuse std::process::Command;\n\nfn get_git_version() -> Result<(u32, String), std::io::Error> {\n    let output = Command::new(\"git\")\n        .args([\"rev-list\", \"--count\", \"HEAD\"])\n        .output()?;\n\n    let output = output.stdout;\n    let version_code = String::from_utf8(output).expect(\"Failed to read git count stdout\");\n    let version_code: u32 = version_code\n        .trim()\n        .parse()\n        .map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, \"Failed to parse git count\"))?;\n    let version_code = 10000 + 200 + version_code; // For historical reasons\n\n    let version_name = String::from_utf8(\n        Command::new(\"git\")\n            .args([\"describe\", \"--tags\", \"--always\"])\n            .output()?\n            .stdout,\n    )\n    .map_err(|_| {\n        std::io::Error::new(\n            std::io::ErrorKind::Other,\n            \"Failed to read git describe stdout\",\n        )\n    })?;\n    let version_name = version_name.trim_start_matches('v').to_string();\n    Ok((version_code, version_name))\n}\n\nfn main() {\n    // update VersionCode when git repository change\n    println!(\"cargo:rerun-if-changed=../.git/HEAD\");\n    println!(\"cargo:rerun-if-changed=../.git/refs/\");\n\n    let (code, name) = match get_git_version() {\n        Ok((code, name)) => (code, name),\n        Err(_) => {\n            // show warning if git is not installed\n            println!(\"cargo:warning=Failed to get git version, using 0.0.0\");\n            (0, \"0.0.0\".to_string())\n        }\n    };\n    let out_dir = env::var(\"OUT_DIR\").expect(\"Failed to get $OUT_DIR\");\n    println!(\"out_dir: ${out_dir}\");\n    println!(\"code: ${code}\");\n    let out_dir = Path::new(&out_dir);\n    File::create(Path::new(out_dir).join(\"VERSION_CODE\"))\n        .expect(\"Failed to create VERSION_CODE\")\n        .write_all(code.to_string().as_bytes())\n        .expect(\"Failed to write VERSION_CODE\");\n\n    File::create(Path::new(out_dir).join(\"VERSION_NAME\"))\n        .expect(\"Failed to create VERSION_NAME\")\n        .write_all(name.trim().as_bytes())\n        .expect(\"Failed to write VERSION_NAME\");\n}\n"
  },
  {
    "path": "apd/src/apd.rs",
    "content": "#[cfg(unix)]\nuse std::os::unix::process::CommandExt;\nuse std::{env, ffi::CStr, path::PathBuf, process::Command};\n\nuse anyhow::{Ok, Result};\n#[cfg(unix)]\nuse getopts::Options;\nuse rustix::thread::{Gid, Uid, set_thread_res_gid, set_thread_res_uid};\n\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\nuse crate::pty::prepare_pty;\nuse crate::{\n    defs,\n    utils::{self, umask},\n};\n\nfn print_usage(opts: Options) {\n    let brief = \"APatch\\n\\nUsage: <command> [options] [-] [user [argument...]]\".to_string();\n    print!(\"{}\", opts.usage(&brief));\n}\n\nfn set_identity(uid: u32, gid: u32) {\n    #[cfg(any(target_os = \"linux\", target_os = \"android\"))]\n    let gid = Gid::from_raw(gid);\n    let uid = Uid::from_raw(uid);\n    set_thread_res_gid(gid, gid, gid).ok();\n    set_thread_res_uid(uid, uid, uid).ok();\n}\n\n#[cfg(not(unix))]\npub fn root_shell() -> Result<()> {\n    unimplemented!()\n}\n\n#[cfg(unix)]\npub fn root_shell() -> Result<()> {\n    // we are root now, this was set in kernel!\n    let env_args: Vec<String> = env::args().collect();\n    let args = env_args\n        .iter()\n        .position(|arg| arg == \"-c\")\n        .map(|i| {\n            let rest = env_args[i + 1..].to_vec();\n            let mut new_args = env_args[..i].to_vec();\n            new_args.push(\"-c\".to_string());\n            if !rest.is_empty() {\n                new_args.push(rest.join(\" \"));\n            }\n            new_args\n        })\n        .unwrap_or_else(|| env_args.clone());\n\n    let mut opts = Options::new();\n    opts.optopt(\n        \"c\",\n        \"command\",\n        \"pass COMMAND to the invoked shell\",\n        \"COMMAND\",\n    );\n    opts.optflag(\"h\", \"help\", \"display this help message and exit\");\n    opts.optflag(\"l\", \"login\", \"pretend the shell to be a login shell\");\n    opts.optflag(\n        \"p\",\n        \"preserve-environment\",\n        \"preserve the entire environment\",\n    );\n    opts.optopt(\n        \"s\",\n        \"shell\",\n        \"use SHELL instead of the default /system/bin/sh\",\n        \"SHELL\",\n    );\n    opts.optflag(\"v\", \"version\", \"display version number and exit\");\n    opts.optflag(\"V\", \"\", \"display version code and exit\");\n    opts.optflag(\n        \"M\",\n        \"mount-master\",\n        \"force run in the global mount namespace\",\n    );\n    opts.optflag(\"\", \"no-pty\", \"Do not allocate a new pseudo terminal.\");\n\n    // Replace -cn with -z, -mm with -M for supporting getopt_long\n    let args = args\n        .into_iter()\n        .map(|e| {\n            if e == \"-mm\" {\n                \"-M\".to_string()\n            } else if e == \"-cn\" {\n                \"-z\".to_string()\n            } else {\n                e\n            }\n        })\n        .collect::<Vec<String>>();\n\n    let matches = match opts.parse(&args[1..]) {\n        Result::Ok(m) => m,\n        Err(f) => {\n            println!(\"{f}\");\n            print_usage(opts);\n            std::process::exit(-1);\n        }\n    };\n\n    if matches.opt_present(\"h\") {\n        print_usage(opts);\n        return Ok(());\n    }\n\n    if matches.opt_present(\"v\") {\n        println!(\"{}:APatch\", defs::VERSION_NAME);\n        return Ok(());\n    }\n\n    if matches.opt_present(\"V\") {\n        println!(\"{}\", defs::VERSION_CODE);\n        return Ok(());\n    }\n\n    let shell = matches.opt_str(\"s\").unwrap_or(\"/system/bin/sh\".to_string());\n    let mut is_login = matches.opt_present(\"l\");\n    let preserve_env = matches.opt_present(\"p\");\n    let mount_master = matches.opt_present(\"M\");\n\n    // we've made sure that -c is the last option and it already contains the whole command, no need to construct it again\n    let args = matches\n        .opt_str(\"c\")\n        .map(|cmd| vec![\"-c\".to_string(), cmd])\n        .unwrap_or_default();\n\n    let mut free_idx = 0;\n    if !matches.free.is_empty() && matches.free[free_idx] == \"-\" {\n        is_login = true;\n        free_idx += 1;\n    }\n\n    // use current uid if no user specified, these has been done in kernel!\n    let mut uid = unsafe { libc::getuid() };\n    let gid = unsafe { libc::getgid() };\n    if free_idx < matches.free.len() {\n        let name = &matches.free[free_idx];\n        uid = unsafe {\n            #[cfg(target_arch = \"aarch64\")]\n            let pw = libc::getpwnam(name.as_ptr()).as_ref();\n            #[cfg(target_arch = \"x86_64\")]\n            let pw = libc::getpwnam(name.as_ptr() as *const i8).as_ref();\n\n            match pw {\n                Some(pw) => pw.pw_uid,\n                None => name.parse::<u32>().unwrap_or(0),\n            }\n        }\n    }\n\n    // https://github.com/topjohnwu/Magisk/blob/master/native/src/core/su/su_daemon.cpp#L408\n    let arg0 = if is_login { \"-\" } else { &shell };\n\n    let mut command = &mut Command::new(&shell);\n\n    if !preserve_env {\n        // This is actually incorrect, I don't know why.\n        // command = command.env_clear();\n\n        let pw = unsafe { libc::getpwuid(uid).as_ref() };\n\n        if let Some(pw) = pw {\n            let home = unsafe { CStr::from_ptr(pw.pw_dir) };\n            let pw_name = unsafe { CStr::from_ptr(pw.pw_name) };\n\n            let home = home.to_string_lossy();\n            let pw_name = pw_name.to_string_lossy();\n\n            command = command\n                .env(\"HOME\", home.as_ref() as &str)\n                .env(\"USER\", pw_name.as_ref() as &str)\n                .env(\"LOGNAME\", pw_name.as_ref() as &str)\n                .env(\"SHELL\", &shell);\n        }\n    }\n\n    // add /data/adb/ap/bin to PATH\n    #[cfg(any(target_os = \"linux\", target_os = \"android\"))]\n    add_path_to_env(defs::BINARY_DIR)?;\n\n    // when AP_RC_PATH exists and ENV is not set, set ENV to AP_RC_PATH\n    if PathBuf::from(defs::AP_RC_PATH).exists() && env::var(\"ENV\").is_err() {\n        command = command.env(\"ENV\", defs::AP_RC_PATH);\n    }\n    #[cfg(target_os = \"android\")]\n    if !matches.opt_present(\"no-pty\") {\n        if let Err(e) = prepare_pty() {\n            log::error!(\"failed to prepare pty: {:?}\", e);\n        }\n    }\n    // escape from the current cgroup and become session leader\n    // WARNING!!! This cause some root shell hang forever!\n    // command = command.process_group(0);\n    command = unsafe {\n        command.pre_exec(move || {\n            umask(0o22);\n            utils::switch_cgroups();\n\n            // switch to global mount namespace\n            #[cfg(any(target_os = \"linux\", target_os = \"android\"))]\n            let global_namespace_enable =\n                std::fs::read_to_string(defs::GLOBAL_NAMESPACE_FILE).unwrap_or(\"0\".to_string());\n            if global_namespace_enable.trim() == \"1\" || mount_master {\n                let _ = utils::switch_mnt_ns(1);\n            }\n\n            set_identity(uid, gid);\n\n            Result::Ok(())\n        })\n    };\n\n    command = command.args(args).arg0(arg0);\n    Err(command.exec().into())\n}\n\nfn add_path_to_env(path: &str) -> Result<()> {\n    let mut paths =\n        env::var_os(\"PATH\").map_or(Vec::new(), |val| env::split_paths(&val).collect::<Vec<_>>());\n    let new_path = PathBuf::from(path.trim_end_matches('/'));\n    paths.push(new_path);\n    let new_path_env = env::join_paths(paths)?;\n    unsafe { env::set_var(\"PATH\", new_path_env) };\n    Ok(())\n}\n"
  },
  {
    "path": "apd/src/assets.rs",
    "content": "use anyhow::Result;\nuse const_format::concatcp;\n\nuse crate::{defs::BINARY_DIR, utils};\n\npub const RESETPROP_PATH: &str = concatcp!(BINARY_DIR, \"resetprop\");\npub const BUSYBOX_PATH: &str = concatcp!(BINARY_DIR, \"busybox\");\npub const MAGISKPOLICY_PATH: &str = concatcp!(BINARY_DIR, \"magiskpolicy\");\n\npub fn ensure_binaries() -> Result<()> {\n    utils::ensure_binary(RESETPROP_PATH)?;\n    utils::ensure_binary(BUSYBOX_PATH)?;\n    utils::ensure_binary(MAGISKPOLICY_PATH)?;\n    Ok(())\n}\n"
  },
  {
    "path": "apd/src/banner",
    "content": "    _    ____       _       _     \n   / \\  |  _ \\ __ _| |_ ___| |__  \n  / _ \\ | |_) / _` | __/ __| '_ \\ \n / ___ \\|  __/ (_| | || (__| | | |\n/_/   \\_\\_|   \\__,_|\\__\\___|_| |_|\n"
  },
  {
    "path": "apd/src/cli.rs",
    "content": "use crate::{defs, event, lua, module, supercall, utils};\n#[cfg(target_os = \"android\")]\nuse android_logger::Config;\nuse anyhow::Result;\nuse clap::Parser;\n#[cfg(target_os = \"android\")]\nuse log::LevelFilter;\n\n/// APatch cli\n#[derive(Parser, Debug)]\n#[command(author, version = defs::VERSION_CODE, about, long_about = None)]\nstruct Args {\n    #[arg(\n        short,\n        long,\n        value_name = \"KEY\",\n        help = \"Super key for authentication root\"\n    )]\n    superkey: Option<String>,\n    #[command(subcommand)]\n    command: Commands,\n}\n\n#[derive(clap::Subcommand, Debug)]\nenum Commands {\n    /// Manage APatch modules\n    Module {\n        #[command(subcommand)]\n        command: Module,\n    },\n\n    /// Trigger `post-fs-data` event\n    PostFsData,\n\n    /// Trigger `service` event\n    Services,\n\n    /// Trigger `boot-complete` event\n    BootCompleted,\n\n    /// Start uid listener for synchronizing root list\n    UidListener,\n\n    /// SELinux policy Patch tool\n    Sepolicy {\n        #[command(subcommand)]\n        command: Sepolicy,\n    },\n}\n\n#[derive(clap::Subcommand, Debug)]\nenum Module {\n    /// Install module <ZIP>\n    Install {\n        /// module zip file path\n        zip: String,\n    },\n\n    /// Uninstall module <id>\n    Uninstall {\n        /// module id\n        id: String,\n    },\n\n    /// enable module <id>\n    Enable {\n        /// module id\n        id: String,\n    },\n\n    /// disable module <id>\n    Disable {\n        // module id\n        id: String,\n    },\n\n    /// run action for module <id>\n    Action {\n        // module id\n        id: String,\n    },\n    /// module lua runner\n    Lua {\n        // module id\n        id: String,\n        // lua function\n        function: String,\n    },\n    /// list all modules\n    List,\n}\n\n#[derive(clap::Subcommand, Debug)]\nenum Sepolicy {\n    /// Check if sepolicy statement is supported/valid\n    Check {\n        /// sepolicy statements\n        sepolicy: String,\n    },\n}\n\npub fn run() -> Result<()> {\n    #[cfg(target_os = \"android\")]\n    android_logger::init_once(\n        Config::default()\n            .with_max_level(LevelFilter::Trace) // limit log level\n            .with_tag(\"APatchD\")\n            .with_filter(\n                android_logger::FilterBuilder::new()\n                    .filter_level(LevelFilter::Trace)\n                    .filter_module(\"notify\", LevelFilter::Warn)\n                    .build(),\n            ),\n    );\n\n    #[cfg(not(target_os = \"android\"))]\n    env_logger::init();\n\n    // the kernel executes su with argv[0] = \"/system/bin/kp\" or \"/system/bin/su\" or \"su\" or \"kp\" and replace it with us\n    let arg0 = std::env::args().next().unwrap_or_default();\n    if arg0.ends_with(\"kp\") || arg0.ends_with(\"su\") {\n        return crate::apd::root_shell();\n    }\n\n    let cli = Args::parse();\n\n    log::info!(\"command: {:?}\", cli.command);\n\n    if let Some(ref _superkey) = cli.superkey {\n        supercall::privilege_apd_profile(&cli.superkey);\n    }\n\n    let result = match cli.command {\n        Commands::PostFsData => event::on_post_data_fs(cli.superkey),\n\n        Commands::BootCompleted => event::on_boot_completed(cli.superkey),\n\n        Commands::UidListener => event::start_uid_listener(),\n\n        Commands::Module { command } => {\n            #[cfg(any(target_os = \"linux\", target_os = \"android\"))]\n            {\n                utils::switch_mnt_ns(1)?;\n            }\n            match command {\n                Module::Install { zip } => module::install_module(&zip),\n                Module::Uninstall { id } => module::uninstall_module(&id),\n                Module::Action { id } => module::run_action(&id),\n                Module::Lua { id, function } => {\n                    lua::run_lua(&id, &function, false, true).map_err(|e| anyhow::anyhow!(\"{}\", e))\n                }\n                Module::Enable { id } => module::enable_module(&id),\n                Module::Disable { id } => module::disable_module(&id),\n                Module::List => module::list_modules(),\n            }\n        }\n\n        Commands::Sepolicy { command } => match command {\n            Sepolicy::Check { sepolicy } => crate::sepolicy::check_rule(&sepolicy),\n        },\n\n        Commands::Services => event::on_services(cli.superkey),\n    };\n\n    if let Err(e) = &result {\n        log::error!(\"Error: {:?}\", e);\n    }\n    result\n}\n"
  },
  {
    "path": "apd/src/defs.rs",
    "content": "use const_format::concatcp;\n\npub const ADB_DIR: &str = \"/data/adb/\";\npub const WORKING_DIR: &str = concatcp!(ADB_DIR, \"ap/\");\npub const BINARY_DIR: &str = concatcp!(WORKING_DIR, \"bin/\");\npub const APATCH_LOG_FOLDER: &str = concatcp!(WORKING_DIR, \"log/\");\n\npub const AP_RC_PATH: &str = concatcp!(WORKING_DIR, \".aprc\");\npub const GLOBAL_NAMESPACE_FILE: &str = concatcp!(ADB_DIR, \".global_namespace_enable\");\npub const DAEMON_PATH: &str = concatcp!(ADB_DIR, \"apd\");\n\npub const MODULE_DIR: &str = concatcp!(ADB_DIR, \"modules/\");\n\n// warning: this directory should not change, or you need to change the code in module_installer.sh!!!\npub const MODULE_UPDATE_DIR: &str = concatcp!(ADB_DIR, \"modules_update/\");\n\npub const TEMP_DIR: &str = \"/debug_ramdisk\";\npub const TEMP_DIR_LEGACY: &str = \"/sbin\";\n\npub const MODULE_WEB_DIR: &str = \"webroot\";\npub const MODULE_ACTION_SH: &str = \"action.sh\";\npub const DISABLE_FILE_NAME: &str = \"disable\";\npub const UPDATE_FILE_NAME: &str = \"update\";\npub const REMOVE_FILE_NAME: &str = \"remove\";\n\n// Metamodule support\npub const METAMODULE_MOUNT_SCRIPT: &str = \"metamount.sh\";\npub const METAMODULE_METAINSTALL_SCRIPT: &str = \"metainstall.sh\";\npub const METAMODULE_METAUNINSTALL_SCRIPT: &str = \"metauninstall.sh\";\npub const METAMODULE_DIR: &str = concatcp!(ADB_DIR, \"metamodule/\");\n\npub const PTS_NAME: &str = \"pts\";\n\npub const VERSION_CODE: &str = include_str!(concat!(env!(\"OUT_DIR\"), \"/VERSION_CODE\"));\npub const VERSION_NAME: &str = include_str!(concat!(env!(\"OUT_DIR\"), \"/VERSION_NAME\"));\n"
  },
  {
    "path": "apd/src/event.rs",
    "content": "use std::{\n    env,\n    ffi::CStr,\n    fs,\n    os::unix::{fs::PermissionsExt, process::CommandExt},\n    path::{Path, PathBuf},\n    process::Command,\n    sync::{Arc, Mutex},\n    thread,\n    time::Duration,\n};\n\nuse anyhow::{Context, Result};\nuse libc::SIGPWR;\nuse log::{info, warn};\nuse notify::{\n    Config, Event, EventKind, INotifyWatcher, RecursiveMode, Watcher,\n    event::{ModifyKind, RenameMode},\n};\nuse signal_hook::{consts::signal::*, iterator::Signals};\n\nuse crate::{\n    assets, defs, lua, metamodule, module, restorecon, supercall,\n    supercall::{\n        fork_for_result, init_load_package_uid_config, init_load_su_path, refresh_ap_package_list,\n    },\n    utils::{self, switch_cgroups},\n};\n\npub fn on_post_data_fs(superkey: Option<String>) -> Result<()> {\n    utils::umask(0);\n    use std::process::Stdio;\n    #[cfg(unix)]\n    init_load_package_uid_config(&superkey);\n\n    init_load_su_path(&superkey);\n\n    let args = [\"/data/adb/ap/bin/magiskpolicy\", \"--magisk\", \"--live\"];\n    fork_for_result(\"/data/adb/ap/bin/magiskpolicy\", &args, &superkey);\n\n    info!(\"Re-privilege apd profile after injecting sepolicy\");\n    supercall::privilege_apd_profile(&superkey);\n\n    if utils::has_magisk() {\n        warn!(\"Magisk detected, skip post-fs-data!\");\n        return Ok(());\n    }\n\n    // Create log environment\n    if !Path::new(defs::APATCH_LOG_FOLDER).exists() {\n        fs::create_dir(defs::APATCH_LOG_FOLDER).expect(\"Failed to create log folder\");\n        let permissions = fs::Permissions::from_mode(0o700);\n        fs::set_permissions(defs::APATCH_LOG_FOLDER, permissions)\n            .expect(\"Failed to set permissions\");\n    }\n    let command_string = format!(\n        \"rm -rf {}*.old.log; for file in {}*; do mv \\\"$file\\\" \\\"$file.old.log\\\"; done\",\n        defs::APATCH_LOG_FOLDER,\n        defs::APATCH_LOG_FOLDER\n    );\n    let mut args = vec![\"-c\", &command_string];\n    // for all file to .old\n    let result = utils::run_command(\"sh\", &args, None)?.wait()?;\n    if result.success() {\n        info!(\"Successfully deleted .old files.\");\n    } else {\n        info!(\"Failed to delete .old files.\");\n    }\n    let logcat_path = format!(\"{}logcat.log\", defs::APATCH_LOG_FOLDER);\n    let dmesg_path = format!(\"{}dmesg.log\", defs::APATCH_LOG_FOLDER);\n    let bootlog = fs::File::create(dmesg_path)?;\n    args = vec![\n        \"-s\",\n        \"9\",\n        \"120s\",\n        \"logcat\",\n        \"-b\",\n        \"main,system,crash\",\n        \"-f\",\n        &logcat_path,\n        \"logcatcher-bootlog:S\",\n        \"&\",\n    ];\n    let _ = unsafe {\n        Command::new(\"timeout\")\n            .process_group(0)\n            .pre_exec(|| {\n                switch_cgroups();\n                Ok(())\n            })\n            .args(args)\n            .spawn()\n    };\n    args = vec![\"-s\", \"9\", \"120s\", \"dmesg\", \"-w\"];\n    let _result = unsafe {\n        Command::new(\"timeout\")\n            .process_group(0)\n            .pre_exec(|| {\n                switch_cgroups();\n                Ok(())\n            })\n            .args(args)\n            .stdout(Stdio::from(bootlog))\n            .spawn()\n    };\n\n    let key = \"KERNELPATCH_VERSION\";\n    match env::var(key) {\n        Ok(value) => println!(\"{}: {}\", key, value),\n        Err(_) => println!(\"{} not found\", key),\n    }\n\n    let key = \"KERNEL_VERSION\";\n    match env::var(key) {\n        Ok(value) => println!(\"{}: {}\", key, value),\n        Err(_) => println!(\"{} not found\", key),\n    }\n\n    let safe_mode = utils::is_safe_mode(superkey.clone());\n\n    if safe_mode {\n        // we should still mount modules.img to `/data/adb/modules` in safe mode\n        // becuase we may need to operate the module dir in safe mode\n        warn!(\"safe mode, skip common post-fs-data.d scripts\");\n        if let Err(e) = module::disable_all_modules() {\n            warn!(\"disable all modules failed: {}\", e);\n        }\n    } else {\n        // Then exec common post-fs-data scripts\n        if let Err(e) = module::exec_common_scripts(\"post-fs-data.d\", true) {\n            warn!(\"exec common post-fs-data scripts failed: {}\", e);\n        }\n    }\n    let module_update_dir = defs::MODULE_UPDATE_DIR; //save module place\n    let module_dir = defs::MODULE_DIR; // run modules place\n    let module_update_flag = Path::new(defs::WORKING_DIR).join(defs::UPDATE_FILE_NAME); // if update ,there will be renewed modules file\n    assets::ensure_binaries().with_context(|| \"binary missing\")?;\n\n    if Path::new(defs::MODULE_UPDATE_DIR).exists() {\n        module::handle_updated_modules()?;\n        fs::remove_dir_all(module_update_dir)?;\n    }\n\n    if safe_mode {\n        warn!(\"safe mode, skip post-fs-data scripts and disable all modules!\");\n        if let Err(e) = module::disable_all_modules() {\n            warn!(\"disable all modules failed: {}\", e);\n        }\n        return Ok(());\n    }\n\n    if let Err(e) = module::prune_modules() {\n        warn!(\"prune modules failed: {}\", e);\n    }\n\n    if let Err(e) = restorecon::restorecon() {\n        warn!(\"restorecon failed: {}\", e);\n    }\n\n    // load sepolicy.rule\n    if module::load_sepolicy_rule().is_err() {\n        warn!(\"load sepolicy.rule failed\");\n    }\n\n    if let Err(e) = metamodule::exec_mount_script(module_dir) {\n        warn!(\"execute metamodule mount failed: {e}\");\n    }\n\n    // exec modules post-fs-data scripts\n    // TODO: Add timeout\n    if let Err(e) = module::exec_stage_script(\"post-fs-data\", true) {\n        warn!(\"exec post-fs-data scripts failed: {}\", e);\n    }\n    if let Err(e) = lua::exec_stage_lua(\"post-fs-data\", true, superkey.as_deref().unwrap_or(\"\")) {\n        warn!(\"Failed to exec post-fs-data lua: {}\", e);\n    }\n    // load system.prop\n    if let Err(e) = module::load_system_prop() {\n        warn!(\"load system.prop failed: {}\", e);\n    }\n\n    info!(\"remove update flag\");\n    let _ = fs::remove_file(module_update_flag);\n\n    run_stage(\"post-mount\", superkey, true);\n\n    env::set_current_dir(\"/\").with_context(|| \"failed to chdir to /\")?;\n\n    Ok(())\n}\n\nfn run_stage(stage: &str, superkey: Option<String>, block: bool) {\n    utils::umask(0);\n\n    if utils::has_magisk() {\n        warn!(\"Magisk detected, skip {stage}\");\n        return;\n    }\n\n    if utils::is_safe_mode(superkey.clone()) {\n        warn!(\"safe mode, skip {stage} scripts\");\n        if let Err(e) = module::disable_all_modules() {\n            warn!(\"disable all modules failed: {}\", e);\n        }\n        return;\n    }\n\n    // execute metamodule stage script first (priority)\n    if let Err(e) = metamodule::exec_stage_script(stage, block) {\n        warn!(\"Failed to exec metamodule {stage} script: {e}\");\n    }\n\n    if let Err(e) = module::exec_common_scripts(&format!(\"{stage}.d\"), block) {\n        warn!(\"Failed to exec common {stage} scripts: {e}\");\n    }\n    if let Err(e) = module::exec_stage_script(stage, block) {\n        warn!(\"Failed to exec {stage} scripts: {e}\");\n    }\n    if let Err(e) = lua::exec_stage_lua(stage, block, superkey.as_deref().unwrap_or(\"\")) {\n        warn!(\"Failed to exec {stage} lua: {e}\");\n    }\n}\n\npub fn on_services(superkey: Option<String>) -> Result<()> {\n    info!(\"on_services triggered!\");\n    run_stage(\"service\", superkey, false);\n\n    Ok(())\n}\n\nfn run_uid_monitor() {\n    info!(\"Trigger run_uid_monitor!\");\n\n    let mut command = &mut Command::new(\"/data/adb/apd\");\n    {\n        command = command.process_group(0);\n        command = unsafe {\n            command.pre_exec(|| {\n                // ignore the error?\n                switch_cgroups();\n                Ok(())\n            })\n        };\n    }\n    command = command.arg(\"uid-listener\");\n\n    command\n        .spawn()\n        .map(|_| ())\n        .expect(\"[run_uid_monitor] Failed to run uid monitor\");\n}\n\npub fn on_boot_completed(superkey: Option<String>) -> Result<()> {\n    info!(\"on_boot_completed triggered!\");\n\n    run_stage(\"boot-completed\", superkey, false);\n\n    run_uid_monitor();\n    Ok(())\n}\n\npub fn start_uid_listener() -> Result<()> {\n    info!(\"start_uid_listener triggered!\");\n    println!(\"[start_uid_listener] Registering...\");\n\n    // create inotify instance\n    const SYS_PACKAGES_LIST_TMP: &str = \"/data/system/packages.list.tmp\";\n    let sys_packages_list_tmp = PathBuf::from(&SYS_PACKAGES_LIST_TMP);\n    let dir: PathBuf = sys_packages_list_tmp.parent().unwrap().into();\n\n    let (tx, rx) = std::sync::mpsc::channel();\n    let tx_clone = tx.clone();\n    let mutex = Arc::new(Mutex::new(()));\n\n    {\n        let mutex_clone = mutex.clone();\n        thread::spawn(move || {\n            let mut signals = Signals::new(&[SIGTERM, SIGINT, SIGPWR]).unwrap();\n            for sig in signals.forever() {\n                log::warn!(\"[shutdown] Caught signal {sig}, refreshing package list...\");\n                let skey = CStr::from_bytes_with_nul(b\"su\\0\")\n                    .expect(\"[shutdown_listener] CStr::from_bytes_with_nul failed\");\n                refresh_ap_package_list(&skey, &mutex_clone);\n                break; // 执行一次后退出线程\n            }\n        });\n    }\n\n    let mut watcher = INotifyWatcher::new(\n        move |ev: notify::Result<Event>| match ev {\n            Ok(Event {\n                kind: EventKind::Modify(ModifyKind::Name(RenameMode::Both)),\n                paths,\n                ..\n            }) => {\n                if paths.contains(&sys_packages_list_tmp) {\n                    info!(\"[uid_monitor] System packages list changed, sending to tx...\");\n                    tx_clone.send(false).unwrap()\n                }\n            }\n            Err(err) => warn!(\"inotify error: {err}\"),\n            _ => (),\n        },\n        Config::default(),\n    )?;\n\n    watcher.watch(dir.as_ref(), RecursiveMode::NonRecursive)?;\n\n    let mut debounce = false;\n    while let Ok(delayed) = rx.recv() {\n        if delayed {\n            debounce = false;\n            let skey = CStr::from_bytes_with_nul(b\"su\\0\")\n                .expect(\"[start_uid_listener] CStr::from_bytes_with_nul failed\");\n            refresh_ap_package_list(&skey, &mutex);\n        } else if !debounce {\n            thread::sleep(Duration::from_secs(1));\n            debounce = true;\n            tx.send(true)?;\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "apd/src/installer.sh",
    "content": "#!/system/bin/sh\n############################################\n# APatch Module installer script\n# mostly from module_installer.sh\n# and util_functions.sh in Magisk\n############################################\n\numask 022\n\nui_print() {\n  if $BOOTMODE; then\n    echo \"$1\"\n  else\n    echo -e \"ui_print $1\\nui_print\" >> /proc/self/fd/$OUTFD\n  fi\n}\n\ntoupper() {\n  echo \"$@\" | tr '[:lower:]' '[:upper:]'\n}\n\ngrep_cmdline() {\n  local REGEX=\"s/^$1=//p\"\n  { echo $(cat /proc/cmdline)$(sed -e 's/[^\"]//g' -e 's/\"\"//g' /proc/cmdline) | xargs -n 1; \\\n    sed -e 's/ = /=/g' -e 's/, /,/g' -e 's/\"//g' /proc/bootconfig; \\\n  } 2>/dev/null | sed -n \"$REGEX\"\n}\n\ngrep_prop() {\n  local REGEX=\"s/^$1=//p\"\n  shift\n  local FILES=$@\n  [ -z \"$FILES\" ] && FILES='/system/build.prop'\n  cat $FILES 2>/dev/null | dos2unix | sed -n \"$REGEX\" | head -n 1\n}\n\ngrep_get_prop() {\n  local result=$(grep_prop $@)\n  if [ -z \"$result\" ]; then\n    # Fallback to getprop\n    getprop \"$1\"\n  else\n    echo $result\n  fi\n}\n\nis_mounted() {\n  grep -q \" $(readlink -f $1) \" /proc/mounts 2>/dev/null\n  return $?\n}\n\nabort() {\n  ui_print \"$1\"\n  $BOOTMODE || recovery_cleanup\n  [ ! -z $MODPATH ] && rm -rf $MODPATH\n  rm -rf $TMPDIR\n  exit 1\n}\n\nprint_title() {\n  local len line1len line2len bar\n  line1len=$(echo -n $1 | wc -c)\n  line2len=$(echo -n $2 | wc -c)\n  len=$line2len\n  [ $line1len -gt $line2len ] && len=$line1len\n  len=$((len + 2))\n  bar=$(printf \"%${len}s\" | tr ' ' '*')\n  ui_print \"$bar\"\n  ui_print \" $1 \"\n  [ \"$2\" ] && ui_print \" $2 \"\n  ui_print \"$bar\"\n}\n\n######################\n# Environment Related\n######################\n\nsetup_flashable() {\n  ensure_bb\n  $BOOTMODE && return\n  if [ -z $OUTFD ] || readlink /proc/$$/fd/$OUTFD | grep -q /tmp; then\n    # We will have to manually find out OUTFD\n    for FD in `ls /proc/$$/fd`; do\n      if readlink /proc/$$/fd/$FD | grep -q pipe; then\n        if ps | grep -v grep | grep -qE \" 3 $FD |status_fd=$FD\"; then\n          OUTFD=$FD\n          break\n        fi\n      fi\n    done\n  fi\n  recovery_actions\n}\n\nensure_bb() {\n  :\n}\n\nrecovery_actions() {\n  :\n}\n\nrecovery_cleanup() {\n  :\n}\n\n#######################\n# Installation Related\n#######################\n\n# find_block [partname...]\nfind_block() {\n  local BLOCK DEV DEVICE DEVNAME PARTNAME UEVENT\n  for BLOCK in \"$@\"; do\n    DEVICE=`find /dev/block \\( -type b -o -type c -o -type l \\) -iname $BLOCK | head -n 1` 2>/dev/null\n    if [ ! -z $DEVICE ]; then\n      readlink -f $DEVICE\n      return 0\n    fi\n  done\n  # Fallback by parsing sysfs uevents\n  for UEVENT in /sys/dev/block/*/uevent; do\n    DEVNAME=`grep_prop DEVNAME $UEVENT`\n    PARTNAME=`grep_prop PARTNAME $UEVENT`\n    for BLOCK in \"$@\"; do\n      if [ \"$(toupper $BLOCK)\" = \"$(toupper $PARTNAME)\" ]; then\n        echo /dev/block/$DEVNAME\n        return 0\n      fi\n    done\n  done\n  # Look just in /dev in case we're dealing with MTD/NAND without /dev/block devices/links\n  for DEV in \"$@\"; do\n    DEVICE=`find /dev \\( -type b -o -type c -o -type l \\) -maxdepth 1 -iname $DEV | head -n 1` 2>/dev/null\n    if [ ! -z $DEVICE ]; then\n      readlink -f $DEVICE\n      return 0\n    fi\n  done\n  return 1\n}\n\n# setup_mntpoint <mountpoint>\nsetup_mntpoint() {\n  local POINT=$1\n  [ -L $POINT ] && mv -f $POINT ${POINT}_link\n  if [ ! -d $POINT ]; then\n    rm -f $POINT\n    mkdir -p $POINT\n  fi\n}\n\n# mount_name <partname(s)> <mountpoint> <flag>\nmount_name() {\n  local PART=$1\n  local POINT=$2\n  local FLAG=$3\n  setup_mntpoint $POINT\n  is_mounted $POINT && return\n  # First try mounting with fstab\n  mount $FLAG $POINT 2>/dev/null\n  if ! is_mounted $POINT; then\n    local BLOCK=$(find_block $PART)\n    mount $FLAG $BLOCK $POINT || return\n  fi\n  ui_print \"- Mounting $POINT\"\n}\n\n# mount_ro_ensure <partname(s)> <mountpoint>\nmount_ro_ensure() {\n  # We handle ro partitions only in recovery\n  $BOOTMODE && return\n  local PART=$1\n  local POINT=$2\n  mount_name \"$PART\" $POINT '-o ro'\n  is_mounted $POINT || abort \"! Cannot mount $POINT\"\n}\n\nmount_partitions() {\n  # Check A/B slot\n  SLOT=`grep_cmdline androidboot.slot_suffix`\n  if [ -z $SLOT ]; then\n    SLOT=`grep_cmdline androidboot.slot`\n    [ -z $SLOT ] || SLOT=_${SLOT}\n  fi\n  [ -z $SLOT ] || ui_print \"- Current boot slot: $SLOT\"\n\n  # Mount ro partitions\n  if is_mounted /system_root; then\n    umount /system 2&>/dev/null\n    umount /system_root 2&>/dev/null\n  fi\n  mount_ro_ensure \"system$SLOT app$SLOT\" /system\n  if [ -f /system/init -o -L /system/init ]; then\n    SYSTEM_ROOT=true\n    setup_mntpoint /system_root\n    if ! mount --move /system /system_root; then\n      umount /system\n      umount -l /system 2>/dev/null\n      mount_ro_ensure \"system$SLOT app$SLOT\" /system_root\n    fi\n    mount -o bind /system_root/system /system\n  else\n    SYSTEM_ROOT=false\n    grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts && SYSTEM_ROOT=true\n  fi\n  # /vendor is used only on some older devices for recovery AVBv1 signing so is not critical if fails\n  [ -L /system/vendor ] && mount_name vendor$SLOT /vendor '-o ro'\n  $SYSTEM_ROOT && ui_print \"- Device is system-as-root\"\n\n  # Mount sepolicy rules dir locations in recovery (best effort)\n  if ! $BOOTMODE; then\n    mount_name \"cache cac\" /cache\n    mount_name metadata /metadata\n    mount_name persist /persist\n  fi\n}\n\napi_level_arch_detect() {\n  API=$(grep_get_prop ro.build.version.sdk)\n  ABI=$(grep_get_prop ro.product.cpu.abi)\n  if [ \"$ABI\" = \"x86\" ]; then\n    ARCH=x86\n    ABI32=x86\n    IS64BIT=false\n  elif [ \"$ABI\" = \"arm64-v8a\" ]; then\n    ARCH=arm64\n    ABI32=armeabi-v7a\n    IS64BIT=true\n  elif [ \"$ABI\" = \"x86_64\" ]; then\n    ARCH=x64\n    ABI32=x86\n    IS64BIT=true\n  else\n    ARCH=arm\n    ABI=armeabi-v7a\n    ABI32=armeabi-v7a\n    IS64BIT=false\n  fi\n}\n\n#################\n# Module Related\n#################\n\nset_perm() {\n  chown $2:$3 $1 || return 1\n  chmod $4 $1 || return 1\n  local CON=$5\n  [ -z $CON ] && CON=u:object_r:system_file:s0\n  chcon $CON $1 || return 1\n}\n\nset_perm_recursive() {\n  find $1 -type d 2>/dev/null | while read dir; do\n    set_perm $dir $2 $3 $4 $6\n  done\n  find $1 -type f -o -type l 2>/dev/null | while read file; do\n    set_perm $file $2 $3 $5 $6\n  done\n}\n\nmktouch() {\n  mkdir -p ${1%/*} 2>/dev/null\n  [ -z $2 ] && touch $1 || echo $2 > $1\n  chmod 644 $1\n}\n\nmark_remove() {\n  mkdir -p ${1%/*} 2>/dev/null\n  mknod $1 c 0 0\n  chmod 644 $1\n}\n\nmark_replace() {\n  # REPLACE must be directory!!!\n  # https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories\n  mkdir -p $1 2>/dev/null\n  setfattr -n trusted.overlay.opaque -v y $1\n  chmod 644 $1\n}\n\nrequest_size_check() {\n  reqSizeM=`du -ms \"$1\" | cut -f1`\n}\n\nrequest_zip_size_check() {\n  reqSizeM=`unzip -l \"$1\" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'`\n}\n\nboot_actions() { return; }\n\n# Require ZIPFILE to be set\nis_legacy_script() {\n  unzip -l \"$ZIPFILE\" install.sh | grep -q install.sh\n  return $?\n}\n\nhandle_partition() {\n    # if /system/vendor is a symlink, we need to move it out of $MODPATH/system, otherwise it will be overlayed\n    # if /system/vendor is a normal directory, it is ok to overlay it and we don't need to overlay it separately.\n    if [ ! -e $MODPATH/system/$1 ]; then\n        # no partition found\n        return;\n    fi\n\n    if [ -L \"/system/$1\" ] && [ \"$(readlink -f /system/$1)\" = \"/$1\" ]; then\n        ui_print \"- Handle partition /$1\"\n        # we create a symlink if module want to access $MODPATH/system/$1\n        # but it doesn't always work(ie. write it in post-fs-data.sh would fail because it is readonly)\n        mv -f $MODPATH/system/$1 $MODPATH/$1 && ln -sf ../$1 $MODPATH/system/$1\n    fi\n}\n\n# Require OUTFD, ZIPFILE to be set\ninstall_module() {\n  rm -rf $TMPDIR\n  mkdir -p $TMPDIR\n  chcon u:object_r:system_file:s0 $TMPDIR\n  cd $TMPDIR\n\n  mount_partitions\n  api_level_arch_detect\n\n  # Setup busybox and binaries\n  if $BOOTMODE; then\n    boot_actions\n  else\n    recovery_actions\n  fi\n\n  # Extract prop file\n  unzip -o \"$ZIPFILE\" module.prop -d $TMPDIR >&2\n  [ ! -f $TMPDIR/module.prop ] && abort \"! Unable to extract zip file!\"\n\n  local MODDIRNAME=modules\n  $BOOTMODE && MODDIRNAME=modules_update\n  local MODULEROOT=$NVBASE/$MODDIRNAME\n  MODID=`grep_prop id $TMPDIR/module.prop`\n  MODNAME=`grep_prop name $TMPDIR/module.prop`\n  MODAUTH=`grep_prop author $TMPDIR/module.prop`\n  MODPATH=$MODULEROOT/$MODID\n\n  # Create mod paths\n  rm -rf $MODPATH\n  mkdir -p $MODPATH\n\n  if is_legacy_script; then\n    unzip -oj \"$ZIPFILE\" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2\n\n    # Load install script\n    . $TMPDIR/install.sh\n\n    # Callbacks\n    print_modname\n    on_install\n\n    [ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh\n    $SKIPMOUNT && touch $MODPATH/skip_mount\n    $PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop\n    cp -af $TMPDIR/module.prop $MODPATH/module.prop\n    $POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh\n    $LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh\n\n    ui_print \"- Setting permissions\"\n    set_permissions\n  else\n    print_title \"$MODNAME\" \"by $MODAUTH\"\n    print_title \"Powered by APatch\"\n\n    unzip -o \"$ZIPFILE\" customize.sh -d $MODPATH >&2\n\n    if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then\n      ui_print \"- Extracting module files\"\n      unzip -o \"$ZIPFILE\" -x 'META-INF/*' -d $MODPATH >&2\n\n      # Default permissions\n      set_perm_recursive $MODPATH 0 0 0755 0644\n      set_perm_recursive $MODPATH/system/bin 0 2000 0755 0755\n      set_perm_recursive $MODPATH/system/xbin 0 2000 0755 0755\n      set_perm_recursive $MODPATH/system/system_ext/bin 0 2000 0755 0755\n      set_perm_recursive $MODPATH/system/vendor 0 2000 0755 0755 u:object_r:vendor_file:s0\n    fi\n\n    # Load customization script\n    [ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh\n  fi\n\n  # Handle replace folders\n  for TARGET in $REPLACE; do\n    ui_print \"- Replace target: $TARGET\"\n    mark_replace $MODPATH$TARGET\n  done\n\n  # Handle remove files\n  for TARGET in $REMOVE; do\n    ui_print \"- Remove target: $TARGET\"\n    mark_remove $MODPATH$TARGET\n  done\n\n  handle_partition vendor\n  handle_partition system_ext\n  handle_partition product\n\n  if $BOOTMODE; then\n    mktouch $NVBASE/modules/$MODID/update\n    rm -rf $NVBASE/modules/$MODID/remove 2>/dev/null\n    rm -rf $NVBASE/modules/$MODID/disable 2>/dev/null\n    cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop\n  fi\n\n  # Remove stuff that doesn't belong to modules and clean up any empty directories\n  rm -rf \\\n  $MODPATH/system/placeholder $MODPATH/customize.sh \\\n  $MODPATH/README.md $MODPATH/.git*\n  rmdir -p $MODPATH 2>/dev/null\n\n  cd /\n  $BOOTMODE || recovery_cleanup\n  rm -rf $TMPDIR\n\n  ui_print \"- Done\"\n}\n\n##########\n# Presets\n##########\n\n# Detect whether in boot mode\n[ -z $BOOTMODE ] && ps | grep zygote | grep -qv grep && BOOTMODE=true\n[ -z $BOOTMODE ] && ps -A 2>/dev/null | grep zygote | grep -qv grep && BOOTMODE=true\n[ -z $BOOTMODE ] && BOOTMODE=false\n\nNVBASE=/data/adb\nTMPDIR=/dev/tmp\nPOSTFSDATAD=$NVBASE/post-fs-data.d\nSERVICED=$NVBASE/service.d\n\n# Some modules dependents on this\nexport MAGISK_VER=27.0\nexport MAGISK_VER_CODE=27000\n"
  },
  {
    "path": "apd/src/installer_bind.sh",
    "content": "#!/system/bin/sh\n############################################\n# APatch Module installer script\n# mostly from module_installer.sh\n# and util_functions.sh in Magisk\n############################################\n\numask 022\n\nui_print() {\n  if $BOOTMODE; then\n    echo \"$1\"\n  else\n    echo -e \"ui_print $1\\nui_print\" >> /proc/self/fd/$OUTFD\n  fi\n}\n\ntoupper() {\n  echo \"$@\" | tr '[:lower:]' '[:upper:]'\n}\n\ngrep_cmdline() {\n  local REGEX=\"s/^$1=//p\"\n  { echo $(cat /proc/cmdline)$(sed -e 's/[^\"]//g' -e 's/\"\"//g' /proc/cmdline) | xargs -n 1; \\\n    sed -e 's/ = /=/g' -e 's/, /,/g' -e 's/\"//g' /proc/bootconfig; \\\n  } 2>/dev/null | sed -n \"$REGEX\"\n}\n\ngrep_prop() {\n  local REGEX=\"s/$1=//p\"\n  shift\n  local FILES=$@\n  [ -z \"$FILES\" ] && FILES='/system/build.prop'\n  cat $FILES 2>/dev/null | dos2unix | sed -n \"$REGEX\" | head -n 1 | xargs\n}\n\ngrep_get_prop() {\n  local result=$(grep_prop $@)\n  if [ -z \"$result\" ]; then\n    # Fallback to getprop\n    getprop \"$1\"\n  else\n    echo $result\n  fi\n}\n\nis_mounted() {\n  grep -q \" $(readlink -f $1) \" /proc/mounts 2>/dev/null\n  return $?\n}\n\nabort() {\n  ui_print \"$1\"\n  $BOOTMODE || recovery_cleanup\n  [ ! -z $MODPATH ] && rm -rf $MODPATH\n  rm -rf $TMPDIR\n  exit 1\n}\n\nprint_title() {\n  local len line1len line2len bar\n  line1len=$(echo -n $1 | wc -c)\n  line2len=$(echo -n $2 | wc -c)\n  len=$line2len\n  [ $line1len -gt $line2len ] && len=$line1len\n  len=$((len + 2))\n  bar=$(printf \"%${len}s\" | tr ' ' '*')\n  ui_print \"$bar\"\n  ui_print \" $1 \"\n  [ \"$2\" ] && ui_print \" $2 \"\n  ui_print \"$bar\"\n}\n\ncheck_sepolicy() {\n    /data/adb/apd sepolicy check \"$1\"\n    return $?\n}\n\n######################\n# Environment Related\n######################\n\nsetup_flashable() {\n  ensure_bb\n  $BOOTMODE && return\n  if [ -z $OUTFD ] || readlink /proc/$$/fd/$OUTFD | grep -q /tmp; then\n    # We will have to manually find out OUTFD\n    for FD in /proc/$$/fd/*; do\n      if readlink /proc/$$/fd/$FD | grep -q pipe; then\n        if ps | grep -v grep | grep -qE \" 3 $FD |status_fd=$FD\"; then\n          OUTFD=$FD\n          break\n        fi\n      fi\n    done\n  fi\n  recovery_actions\n}\n\nensure_bb() {\n  :\n}\n\nrecovery_actions() {\n  :\n}\n\nrecovery_cleanup() {\n  :\n}\n\n#######################\n# Installation Related\n#######################\n\n# find_block [partname...]\nfind_block() {\n  local BLOCK DEV DEVICE DEVNAME PARTNAME UEVENT\n  for BLOCK in \"$@\"; do\n    DEVICE=`find /dev/block \\( -type b -o -type c -o -type l \\) -iname $BLOCK | head -n 1` 2>/dev/null\n    if [ ! -z $DEVICE ]; then\n      readlink -f $DEVICE\n      return 0\n    fi\n  done\n  # Fallback by parsing sysfs uevents\n  for UEVENT in /sys/dev/block/*/uevent; do\n    DEVNAME=`grep_prop DEVNAME $UEVENT`\n    PARTNAME=`grep_prop PARTNAME $UEVENT`\n    for BLOCK in \"$@\"; do\n      if [ \"$(toupper $BLOCK)\" = \"$(toupper $PARTNAME)\" ]; then\n        echo /dev/block/$DEVNAME\n        return 0\n      fi\n    done\n  done\n  # Look just in /dev in case we're dealing with MTD/NAND without /dev/block devices/links\n  for DEV in \"$@\"; do\n    DEVICE=`find /dev \\( -type b -o -type c -o -type l \\) -maxdepth 1 -iname $DEV | head -n 1` 2>/dev/null\n    if [ ! -z $DEVICE ]; then\n      readlink -f $DEVICE\n      return 0\n    fi\n  done\n  return 1\n}\n\n# setup_mntpoint <mountpoint>\nsetup_mntpoint() {\n  local POINT=$1\n  [ -L $POINT ] && mv -f $POINT ${POINT}_link\n  if [ ! -d $POINT ]; then\n    rm -f $POINT\n    mkdir -p $POINT\n  fi\n}\n\n# mount_name <partname(s)> <mountpoint> <flag>\nmount_name() {\n  local PART=$1\n  local POINT=$2\n  local FLAG=$3\n  setup_mntpoint $POINT\n  is_mounted $POINT && return\n  # First try mounting with fstab\n  mount $FLAG $POINT 2>/dev/null\n  if ! is_mounted $POINT; then\n    local BLOCK=$(find_block $PART)\n    mount $FLAG $BLOCK $POINT || return\n  fi\n  ui_print \"- Mounting $POINT\"\n}\n\n# mount_ro_ensure <partname(s)> <mountpoint>\nmount_ro_ensure() {\n  # We handle ro partitions only in recovery\n  $BOOTMODE && return\n  local PART=$1\n  local POINT=$2\n  mount_name \"$PART\" $POINT '-o ro'\n  is_mounted $POINT || abort \"! Cannot mount $POINT\"\n}\n\nmount_partitions() {\n  # Check A/B slot\n  SLOT=`grep_cmdline androidboot.slot_suffix`\n  if [ -z $SLOT ]; then\n    SLOT=`grep_cmdline androidboot.slot`\n    [ -z $SLOT ] || SLOT=_${SLOT}\n  fi\n  [ -z $SLOT ] || ui_print \"- Current boot slot: $SLOT\"\n\n  # Mount ro partitions\n  if is_mounted /system_root; then\n    umount /system 2&>/dev/null\n    umount /system_root 2&>/dev/null\n  fi\n  mount_ro_ensure \"system$SLOT app$SLOT\" /system\n  if [ -f /system/init -o -L /system/init ]; then\n    SYSTEM_ROOT=true\n    setup_mntpoint /system_root\n    if ! mount --move /system /system_root; then\n      umount /system\n      umount -l /system 2>/dev/null\n      mount_ro_ensure \"system$SLOT app$SLOT\" /system_root\n    fi\n    mount -o bind /system_root/system /system\n  else\n    SYSTEM_ROOT=false\n    grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts && SYSTEM_ROOT=true\n  fi\n  # /vendor is used only on some older devices for recovery AVBv1 signing so is not critical if fails\n  [ -L /system/vendor ] && mount_name vendor$SLOT /vendor '-o ro'\n  $SYSTEM_ROOT && ui_print \"- Device is system-as-root\"\n\n  # Mount sepolicy rules dir locations in recovery (best effort)\n  if ! $BOOTMODE; then\n    mount_name \"cache cac\" /cache\n    mount_name metadata /metadata\n    mount_name persist /persist\n  fi\n}\n\napi_level_arch_detect() {\n  API=$(grep_get_prop ro.build.version.sdk)\n  ABI=$(grep_get_prop ro.product.cpu.abi)\n  if [ \"$ABI\" = \"x86\" ]; then\n    ARCH=x86\n    ABI32=x86\n    IS64BIT=false\n  elif [ \"$ABI\" = \"arm64-v8a\" ]; then\n    ARCH=arm64\n    ABI32=armeabi-v7a\n    IS64BIT=true\n  elif [ \"$ABI\" = \"x86_64\" ]; then\n    ARCH=x64\n    ABI32=x86\n    IS64BIT=true\n  else\n    ARCH=arm\n    ABI=armeabi-v7a\n    ABI32=armeabi-v7a\n    IS64BIT=false\n  fi\n}\n\n#################\n# Module Related\n#################\n\nset_perm() {\n  chown $2:$3 $1 || return 1\n  chmod $4 $1 || return 1\n  local CON=$5\n  [ -z $CON ] && CON=u:object_r:system_file:s0\n  chcon $CON $1 || return 1\n}\n\nset_perm_recursive() {\n  find $1 -type d 2>/dev/null | while read dir; do\n    set_perm $dir $2 $3 $4 $6\n  done\n  find $1 -type f -o -type l 2>/dev/null | while read file; do\n    set_perm $file $2 $3 $5 $6\n  done\n}\n\nmktouch() {\n  mkdir -p ${1%/*} 2>/dev/null\n  [ -z $2 ] && touch $1 || echo $2 > $1\n  chmod 644 $1\n}\n\nmark_remove() {\n  mkdir -p ${1%/*} 2>/dev/null\n  mknod $1 c 0 0\n  chmod 644 $1\n}\n\nmark_replace() {\n  # REPLACE must be directory!!!\n  # https://docs.kernel.org/filesystems/overlayfs.html#whiteouts-and-opaque-directories\n  mkdir -p $1 2>/dev/null\n  setfattr -n trusted.overlay.opaque -v y $1\n  chmod 644 $1\n}\n\nrequest_size_check() {\n  reqSizeM=`du -ms \"$1\" | cut -f1`\n}\n\nrequest_zip_size_check() {\n  reqSizeM=`unzip -l \"$1\" | tail -n 1 | awk '{ print int(($1 - 1) / 1048576 + 1) }'`\n}\n\nboot_actions() { return; }\n\n# Require ZIPFILE to be set\nis_legacy_script() {\n  unzip -l \"$ZIPFILE\" install.sh | grep -q install.sh\n  return $?\n}\n\nhandle_partition() {\n    PARTITION=\"$1\"\n    REQUIRE_SYMLINK=\"$2\"\n    if [ ! -e \"$MODPATH/system/$PARTITION\" ]; then\n        # no partition found\n        return;\n    fi\n\n    if [ \"$REQUIRE_SYMLINK\" = \"false\" ] || [ -L \"/system/$PARTITION\" ] && [ \"$(readlink -f \"/system/$PARTITION\")\" = \"/$PARTITION\" ]; then\n        ui_print \"- Handle partition /$PARTITION\"\n        ln -sf \"./system/$PARTITION\" \"$MODPATH/$PARTITION\"\n    fi\n}\n\n# Require OUTFD, ZIPFILE to be set\ninstall_module() {\n  rm -rf $TMPDIR\n  mkdir -p $TMPDIR\n  chcon u:object_r:system_file:s0 $TMPDIR\n  cd $TMPDIR\n\n  mount_partitions\n  api_level_arch_detect\n\n  # Setup busybox and binaries\n  if $BOOTMODE; then\n    boot_actions\n  else\n    recovery_actions\n  fi\n\n  # Extract prop file\n  unzip -o \"$ZIPFILE\" module.prop -d $TMPDIR >&2\n  [ ! -f $TMPDIR/module.prop ] && abort \"! Unable to extract zip file!\"\n\n  local MODDIRNAME=modules\n  $BOOTMODE && MODDIRNAME=modules_update\n  local MODULEROOT=$NVBASE/$MODDIRNAME\n  MODID=`grep_prop id $TMPDIR/module.prop`\n  MODNAME=`grep_prop name $TMPDIR/module.prop`\n  MODAUTH=`grep_prop author $TMPDIR/module.prop`\n  MODPATH=$MODULEROOT/$MODID\n\n  # Create mod paths\n  rm -rf $MODPATH\n  mkdir -p $MODPATH\n\n  if is_legacy_script; then\n    unzip -oj \"$ZIPFILE\" module.prop install.sh uninstall.sh 'common/*' -d $TMPDIR >&2\n\n    # Load install script\n    . $TMPDIR/install.sh\n\n    # Callbacks\n    print_modname\n    on_install\n\n    [ -f $TMPDIR/uninstall.sh ] && cp -af $TMPDIR/uninstall.sh $MODPATH/uninstall.sh\n    $SKIPMOUNT && touch $MODPATH/skip_mount\n    $PROPFILE && cp -af $TMPDIR/system.prop $MODPATH/system.prop\n    cp -af $TMPDIR/module.prop $MODPATH/module.prop\n    $POSTFSDATA && cp -af $TMPDIR/post-fs-data.sh $MODPATH/post-fs-data.sh\n    $LATESTARTSERVICE && cp -af $TMPDIR/service.sh $MODPATH/service.sh\n\n    ui_print \"- Setting permissions\"\n    set_permissions\n  else\n    print_title \"$MODNAME\" \"by $MODAUTH\"\n    print_title \"Powered by APatch\"\n\n    unzip -o \"$ZIPFILE\" customize.sh -d $MODPATH >&2\n\n    if ! grep -q '^SKIPUNZIP=1$' $MODPATH/customize.sh 2>/dev/null; then\n      ui_print \"- Extracting module files\"\n      unzip -o \"$ZIPFILE\" -x 'META-INF/*' -d $MODPATH >&2\n\n      # Default permissions\n      set_perm_recursive $MODPATH 0 0 0755 0644\n      set_perm_recursive $MODPATH/system/bin 0 2000 0755 0755\n      set_perm_recursive $MODPATH/system/xbin 0 2000 0755 0755\n      set_perm_recursive $MODPATH/system/system_ext/bin 0 2000 0755 0755\n      set_perm_recursive $MODPATH/system/vendor 0 2000 0755 0755 u:object_r:vendor_file:s0\n    fi\n\n    # Load customization script\n    [ -f $MODPATH/customize.sh ] && . $MODPATH/customize.sh\n  fi\n\n  handle_partition vendor true\n  handle_partition system_ext true\n  handle_partition product true\n  handle_partition odm false\n\n  # Handle replace folders\n  for TARGET in $REPLACE; do\n    ui_print \"- Replace target: $TARGET\"\n    mark_replace \"$MODPATH$TARGET\"\n  done\n\n  # Handle remove files\n  for TARGET in $REMOVE; do\n    ui_print \"- Remove target: $TARGET\"\n    mark_remove \"$MODPATH$TARGET\"\n  done\n\n  if $BOOTMODE; then\n    mktouch $NVBASE/modules/$MODID/update\n    rm -rf $NVBASE/modules/$MODID/remove 2>/dev/null\n    rm -rf $NVBASE/modules/$MODID/disable 2>/dev/null\n    cp -af $MODPATH/module.prop $NVBASE/modules/$MODID/module.prop\n  fi\n\n  # Remove stuff that doesn't belong to modules and clean up any empty directories\n  rm -rf \\\n  $MODPATH/system/placeholder $MODPATH/customize.sh \\\n  $MODPATH/README.md $MODPATH/.git*\n  rmdir -p $MODPATH 2>/dev/null\n\n  cd /\n  $BOOTMODE || recovery_cleanup\n  rm -rf $TMPDIR\n\n  ui_print \"- Done\"\n}\n\n##########\n# Presets\n##########\n\n# Detect whether in boot mode\n[ -z $BOOTMODE ] && ps | grep zygote | grep -qv grep && BOOTMODE=true\n[ -z $BOOTMODE ] && ps -A 2>/dev/null | grep zygote | grep -qv grep && BOOTMODE=true\n[ -z $BOOTMODE ] && BOOTMODE=false\n\nNVBASE=/data/adb\nTMPDIR=/dev/tmp\nPOSTFSDATAD=$NVBASE/post-fs-data.d\nSERVICED=$NVBASE/service.d\n\n# Some modules dependents on this\nexport MAGISK_VER=27.0\nexport MAGISK_VER_CODE=27000"
  },
  {
    "path": "apd/src/lua.rs",
    "content": "use crate::module::*;\nuse crate::utils::*;\nuse anyhow::Result;\nuse log::{info, warn};\nuse mlua::{Function, Lua, Result as LuaResult, Table};\nuse std::{fs, path::Path};\n\npub fn save_text<P: AsRef<Path>>(filename: P, content: &str) -> std::io::Result<()> {\n    let _ = ensure_dir_exists(\"/data/adb/config\");\n    let path = format!(\"/data/adb/config/{}\", filename.as_ref().display());\n    fs::write(&path, content)?;\n    Ok(())\n}\n\npub fn load_text<P: AsRef<Path>>(filename: P) -> std::io::Result<String> {\n    let _ = ensure_dir_exists(\"/data/adb/config\");\n    let path = format!(\"/data/adb/config/{}\", filename.as_ref().display());\n    fs::read_to_string(path)\n}\n\npub fn load_all_lua_modules(lua: &Lua) -> LuaResult<()> {\n    let modules_dir = Path::new(\"/data/adb/modules\");\n\n    let modules: Table = match lua.globals().get(\"modules\") {\n        Ok(t) => t,\n        Err(_) => {\n            let t = lua.create_table()?;\n            lua.globals().set(\"modules\", t.clone())?;\n            t\n        }\n    };\n\n    if modules_dir.exists() {\n        for entry in\n            fs::read_dir(modules_dir).unwrap_or_else(|_| fs::read_dir(\"/dev/null\").unwrap())\n        {\n            if let Ok(entry) = entry {\n                let path = entry.path();\n                if path.is_dir() {\n                    let id = path.file_name().unwrap().to_string_lossy().to_string();\n                    let package: Table = lua.globals().get(\"package\")?;\n                    let old_cpath: String = package.get(\"cpath\")?;\n                    let new_cpath = format!(\"{}/?.so;{}\", path.to_string_lossy(), old_cpath);\n                    package.set(\"cpath\", new_cpath)?;\n\n                    let lua_file = path.join(format!(\"{}.lua\", id));\n\n                    if lua_file.exists() {\n                        match fs::read_to_string(&lua_file) {\n                            Ok(code) => {\n                                match lua\n                                    .load(&code)\n                                    .set_name(&*lua_file.to_string_lossy())\n                                    .eval::<Table>()\n                                {\n                                    Ok(module) => {\n                                        modules.set(id.clone(), module.clone())?;\n                                    }\n                                    Err(e) => {\n                                        eprintln!(\n                                            \"Failed to eval Lua {}: {}\",\n                                            lua_file.display(),\n                                            e\n                                        );\n                                    }\n                                }\n                            }\n                            Err(e) => {\n                                eprintln!(\"Failed to read Lua {}: {}\", lua_file.display(), e);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    Ok(())\n}\n\npub fn info_lua(lua: &Lua) -> LuaResult<Function> {\n    lua.create_function(|_, msg: String| {\n        info!(\"[Lua] {}\", msg);\n        Ok(())\n    })\n}\n\npub fn warn_lua(lua: &Lua) -> LuaResult<Function> {\n    lua.create_function(|_, msg: String| {\n        warn!(\"[Lua] {}\", msg);\n        Ok(())\n    })\n}\n\npub fn install_module_lua(lua: &Lua) -> LuaResult<Function> {\n    lua.create_function(|_, zip: String| {\n        install_module(&zip)\n            .map_err(|e| mlua::Error::external(format!(\"install_module failed: {}\", e)))\n    })\n}\npub fn save_text_lua(lua: &Lua) -> LuaResult<Function> {\n    lua.create_function(|_, (filename, content): (String, String)| {\n        save_text(&filename, &content)\n            .map_err(|e| mlua::Error::external(format!(\"save filed: {}\", e)))?;\n        Ok(())\n    })\n}\npub fn read_text_lua(lua: &Lua) -> LuaResult<Function> {\n    lua.create_function(|_, filename: String| {\n        let content = match load_text(&filename) {\n            Ok(s) => s,\n            Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => String::new(),\n            Err(e) => return Err(mlua::Error::external(format!(\"read failed: {}\", e))),\n        };\n        Ok(content)\n    })\n}\n\npub fn exec_stage_lua(stage: &str, wait: bool, superkey: &str) -> Result<()> {\n    let stage_safe = stage.replace('-', \"_\");\n    run_lua(&superkey, &stage_safe, true, wait).map_err(|e| anyhow::anyhow!(\"{}\", e))?;\n    Ok(())\n}\n\npub fn run_lua(id: &str, function: &str, on_each_module: bool, _wait: bool) -> mlua::Result<()> {\n    let lua = unsafe { Lua::unsafe_new() };\n\n    let func = install_module_lua(&lua)?;\n    lua.globals().set(\"install_module\", func)?;\n    lua.globals().set(\"info\", info_lua(&lua)?)?;\n    lua.globals().set(\"warn\", warn_lua(&lua)?)?;\n    lua.globals().set(\"setConfig\", save_text_lua(&lua)?)?;\n    lua.globals().set(\"getConfig\", read_text_lua(&lua)?)?;\n\n    load_all_lua_modules(&lua)?;\n\n    let modules: mlua::Table = lua.globals().get(\"modules\")?;\n    if on_each_module {\n        for pair in modules.pairs::<String, mlua::Table>() {\n            let (_, module_table) = pair?;\n            if let Ok(func_obj) = module_table.get::<mlua::Function>(function) {\n                func_obj.call::<()>(id)?;\n            }\n        }\n    } else {\n        let module_table: mlua::Table = modules.get(id)?;\n        let func_obj: mlua::Function = module_table.get(function)?;\n        func_obj.call::<()>(())?;\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "apd/src/main.rs",
    "content": "mod apd;\nmod assets;\nmod cli;\nmod defs;\nmod event;\nmod lua;\nmod metamodule;\nmod module;\nmod package;\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\nmod pty;\nmod restorecon;\nmod sepolicy;\nmod supercall;\nmod utils;\nfn main() -> anyhow::Result<()> {\n    cli::run()\n}\n"
  },
  {
    "path": "apd/src/metamodule.rs",
    "content": "//! Metamodule management\n//!\n//! This module handles all metamodule-related functionality.\n//! Metamodules are special modules that manage how regular modules are mounted\n//! and provide hooks for module installation/uninstallation.\n\nuse std::{\n    collections::HashMap,\n    path::{Path, PathBuf},\n    process::Command,\n};\n\nuse anyhow::{Context, Result, ensure};\nuse log::{info, warn};\n\nuse crate::{assets, defs, module::ModuleType::All};\n\n/// Determine whether the provided module properties mark it as a metamodule\npub fn is_metamodule(props: &HashMap<String, String>) -> bool {\n    props.get(\"metamodule\").is_some_and(|s| {\n        let trimmed = s.trim();\n        trimmed == \"1\" || trimmed.eq_ignore_ascii_case(\"true\")\n    })\n}\n\n/// Get metamodule path if it exists\n/// The metamodule is stored in /data/adb/modules/{id} with a symlink at /data/adb/metamodule\npub fn get_metamodule_path() -> Option<PathBuf> {\n    let path = Path::new(defs::METAMODULE_DIR);\n\n    // Check if symlink exists and resolve it\n    if path.is_symlink()\n        && let Ok(target) = std::fs::read_link(path)\n    {\n        // If target is relative, resolve it\n        let resolved = if target.is_absolute() {\n            target\n        } else {\n            path.parent()?.join(target)\n        };\n\n        if resolved.exists() && resolved.is_dir() {\n            return Some(resolved);\n        }\n        warn!(\n            \"Metamodule symlink points to non-existent path: {}\",\n            resolved.display()\n        );\n    }\n\n    // Fallback: search for metamodule=1 in modules directory\n    let mut result = None;\n    let _ = crate::module::foreach_module(All, |module_path| {\n        if let Ok(props) = crate::module::read_module_prop(module_path)\n            && is_metamodule(&props)\n        {\n            info!(\n                \"Found metamodule in modules directory: {}\",\n                module_path.display()\n            );\n            result = Some(module_path.to_path_buf());\n        }\n        Ok(())\n    });\n\n    result\n}\n\n/// Check if metamodule exists\npub fn has_metamodule() -> bool {\n    get_metamodule_path().is_some()\n}\n\n/// Check if it's safe to install a regular module\n/// Returns Ok(()) if safe, Err(is_disabled) if blocked\n/// - Err(true) means metamodule is disabled\n/// - Err(false) means metamodule is in other unstable state\npub fn check_install_safety() -> Result<(), bool> {\n    // No metamodule → safe\n    let Some(metamodule_path) = get_metamodule_path() else {\n        return Ok(());\n    };\n\n    // No metainstall.sh → safe (uses default installer)\n    // The staged update directory may contain the latest scripts, so check both locations\n    let has_metainstall = metamodule_path\n        .join(defs::METAMODULE_METAINSTALL_SCRIPT)\n        .exists()\n        || metamodule_path.file_name().is_some_and(|module_id| {\n            Path::new(defs::MODULE_UPDATE_DIR)\n                .join(module_id)\n                .join(defs::METAMODULE_METAINSTALL_SCRIPT)\n                .exists()\n        });\n    if !has_metainstall {\n        return Ok(());\n    }\n\n    // Check for marker files\n    let has_update = metamodule_path.join(defs::UPDATE_FILE_NAME).exists();\n    let has_remove = metamodule_path.join(defs::REMOVE_FILE_NAME).exists();\n    let has_disable = metamodule_path.join(defs::DISABLE_FILE_NAME).exists();\n\n    // Stable state (no markers) → safe\n    if !has_update && !has_remove && !has_disable {\n        return Ok(());\n    }\n\n    // Return true if disabled, false for other unstable states\n    Err(has_disable && !has_update && !has_remove)\n}\n\n/// Create or update the metamodule symlink\n/// Points /data/adb/metamodule -> /data/adb/modules/{module_id}\npub fn ensure_symlink<P>(module_path: P) -> Result<()>\nwhere\n    P: AsRef<Path>,\n{\n    // METAMODULE_DIR might have trailing slash, so we need to trim it\n    let symlink_path = Path::new(defs::METAMODULE_DIR.trim_end_matches('/'));\n    let module_path = module_path.as_ref();\n\n    info!(\n        \"Creating metamodule symlink: {} -> {}\",\n        symlink_path.display(),\n        module_path.display()\n    );\n\n    // Remove existing symlink if it exists\n    if symlink_path.exists() || symlink_path.is_symlink() {\n        info!(\"Removing old metamodule symlink/path\");\n        if symlink_path.is_symlink() {\n            std::fs::remove_file(symlink_path).with_context(|| \"Failed to remove old symlink\")?;\n        } else {\n            // Could be a directory, remove it\n            std::fs::remove_dir_all(symlink_path)\n                .with_context(|| \"Failed to remove old directory\")?;\n        }\n    }\n\n    // Create symlink\n    #[cfg(unix)]\n    std::os::unix::fs::symlink(module_path, symlink_path)\n        .with_context(|| format!(\"Failed to create symlink to {}\", module_path.display()))?;\n\n    info!(\"Metamodule symlink created successfully\");\n    Ok(())\n}\n\n/// Remove the metamodule symlink\npub fn remove_symlink() -> Result<()> {\n    let symlink_path = Path::new(defs::METAMODULE_DIR.trim_end_matches('/'));\n\n    if symlink_path.is_symlink() {\n        std::fs::remove_file(symlink_path)\n            .with_context(|| \"Failed to remove metamodule symlink\")?;\n        info!(\"Metamodule symlink removed\");\n    }\n\n    Ok(())\n}\n\n/// Get the install script content, using metainstall.sh from metamodule if available\n/// Returns the script content to be executed\npub fn get_install_script(\n    is_metamodule: bool,\n    installer_content: &str,\n    install_module_script: &str,\n) -> Result<String> {\n    // Check if there's a metamodule with metainstall.sh\n    // Only apply this logic for regular modules (not when installing metamodule itself)\n    let install_script = if is_metamodule {\n        info!(\"Installing metamodule, using default installer\");\n        install_module_script.to_string()\n    } else if let Some(metamodule_path) = get_metamodule_path() {\n        if metamodule_path.join(defs::DISABLE_FILE_NAME).exists() {\n            info!(\"Metamodule is disabled, using default installer\");\n            install_module_script.to_string()\n        } else {\n            let metainstall_path = metamodule_path.join(defs::METAMODULE_METAINSTALL_SCRIPT);\n\n            if metainstall_path.exists() {\n                info!(\"Using metainstall.sh from metamodule\");\n                let metamodule_content = std::fs::read_to_string(&metainstall_path)\n                    .with_context(|| \"Failed to read metamodule metainstall.sh\")?;\n                format!(\"{installer_content}\\n{metamodule_content}\\nexit 0\\n\")\n            } else {\n                info!(\"Metamodule exists but has no metainstall.sh, using default installer\");\n                install_module_script.to_string()\n            }\n        }\n    } else {\n        info!(\"No metamodule found, using default installer\");\n        install_module_script.to_string()\n    };\n\n    Ok(install_script)\n}\n\n/// Check if metamodule script exists and is ready to execute\n/// Returns None if metamodule doesn't exist, is disabled, or script is missing\n/// Returns Some(script_path) if script is ready to execute\nfn check_metamodule_script(script_name: &str) -> Option<PathBuf> {\n    // Check if metamodule exists\n    let metamodule_path = get_metamodule_path()?;\n\n    // Check if metamodule is disabled\n    if metamodule_path.join(defs::DISABLE_FILE_NAME).exists() {\n        info!(\"Metamodule is disabled, skipping {script_name}\");\n        return None;\n    }\n\n    // Check if script exists\n    let script_path = metamodule_path.join(script_name);\n    if !script_path.exists() {\n        return None;\n    }\n\n    Some(script_path)\n}\n\n/// Execute metamodule's metauninstall.sh for a specific module\npub fn exec_metauninstall_script(module_id: &str) -> Result<()> {\n    let Some(metauninstall_path) = check_metamodule_script(defs::METAMODULE_METAUNINSTALL_SCRIPT)\n    else {\n        return Ok(());\n    };\n\n    info!(\"Executing metamodule metauninstall.sh for module: {module_id}\",);\n\n    let result = Command::new(assets::BUSYBOX_PATH)\n        .args([\"sh\", metauninstall_path.to_str().unwrap()])\n        .current_dir(metauninstall_path.parent().unwrap())\n        .envs(crate::module::get_common_script_envs())\n        .env(\"MODULE_ID\", module_id)\n        .status()?;\n\n    ensure!(\n        result.success(),\n        \"Metamodule metauninstall.sh failed for module {module_id}: {:?}\",\n        result\n    );\n\n    info!(\"Metamodule metauninstall.sh executed successfully for {module_id}\",);\n    Ok(())\n}\n\n/// Execute metamodule mount script\npub fn exec_mount_script(module_dir: &str) -> Result<()> {\n    let Some(mount_script) = check_metamodule_script(defs::METAMODULE_MOUNT_SCRIPT) else {\n        return Ok(());\n    };\n\n    info!(\"Executing mount script for metamodule\");\n\n    let result = Command::new(assets::BUSYBOX_PATH)\n        .args([\"sh\", mount_script.to_str().unwrap()])\n        .envs(crate::module::get_common_script_envs())\n        .env(\"MODULE_DIR\", module_dir)\n        .status()?;\n\n    ensure!(\n        result.success(),\n        \"Metamodule mount script failed with status: {:?}\",\n        result\n    );\n\n    info!(\"Metamodule mount script executed successfully\");\n    Ok(())\n}\n\n/// Execute metamodule script for a specific stage\npub fn exec_stage_script(stage: &str, block: bool) -> Result<()> {\n    let Some(script_path) = check_metamodule_script(&format!(\"{stage}.sh\")) else {\n        return Ok(());\n    };\n\n    info!(\"Executing metamodule {stage}.sh\");\n    crate::module::exec_script(&script_path, block)?;\n    info!(\"Metamodule {stage}.sh executed successfully\");\n    Ok(())\n}\n"
  },
  {
    "path": "apd/src/module.rs",
    "content": "#[cfg(unix)]\nuse std::os::unix::{prelude::PermissionsExt, process::CommandExt};\nuse std::{\n    collections::HashMap,\n    env::var as env_var,\n    fs::{self, remove_dir_all},\n    io::Cursor,\n    path::{Path, PathBuf},\n    process::Command,\n    str::FromStr,\n};\n\nuse crate::lua;\nuse anyhow::{Context, Result, anyhow, bail, ensure};\nuse const_format::concatcp;\nuse is_executable::is_executable;\nuse java_properties::PropertiesIter;\nuse log::{info, warn};\nuse zip_extensions::zip_extract_file_to_memory;\n\n#[allow(clippy::wildcard_imports)]\nuse crate::utils::*;\nuse crate::{\n    assets,\n    defs::{self, MODULE_DIR, MODULE_UPDATE_DIR},\n    metamodule, restorecon,\n};\n\nconst INSTALLER_CONTENT: &str = include_str!(\"./installer.sh\");\nconst INSTALL_MODULE_SCRIPT: &str = concatcp!(\n    INSTALLER_CONTENT,\n    \"\\n\",\n    \"install_module\",\n    \"\\n\",\n    \"exit 0\",\n    \"\\n\"\n);\n\n#[derive(PartialEq, Eq)]\npub enum ModuleType {\n    All,\n    Active,\n    Updated,\n}\n\nfn exec_install_script(module_file: &str, is_metamodule: bool) -> Result<()> {\n    let realpath = std::fs::canonicalize(module_file)\n        .with_context(|| format!(\"realpath: {module_file} failed\"))?;\n\n    // Get install script from metamodule module\n    let install_script =\n        metamodule::get_install_script(is_metamodule, INSTALLER_CONTENT, INSTALL_MODULE_SCRIPT)?;\n\n    let result = Command::new(assets::BUSYBOX_PATH)\n        .args([\"sh\", \"-c\", &install_script])\n        .envs(get_common_script_envs())\n        .env(\"OUTFD\", \"1\")\n        .env(\"ZIPFILE\", realpath)\n        .status()?;\n    ensure!(result.success(), \"Failed to install module script\");\n    Ok(())\n}\n\npub fn handle_updated_modules() -> Result<()> {\n    let modules_root = Path::new(MODULE_DIR);\n    foreach_module(ModuleType::Updated, |updated_module| {\n        if !updated_module.is_dir() {\n            return Ok(());\n        }\n\n        if let Some(name) = updated_module.file_name() {\n            let module_dir = modules_root.join(name);\n            let mut disabled = false;\n            let mut removed = false;\n            if module_dir.exists() {\n                // If the old module is disabled, we need to also disable the new one\n                disabled = module_dir.join(defs::DISABLE_FILE_NAME).exists();\n                removed = module_dir.join(defs::REMOVE_FILE_NAME).exists();\n                remove_dir_all(&module_dir)?;\n            }\n            std::fs::rename(updated_module, &module_dir)?;\n            if removed {\n                let path = module_dir.join(defs::REMOVE_FILE_NAME);\n                if let Err(e) = ensure_file_exists(&path) {\n                    warn!(\"Failed to create {}: {e}\", path.display());\n                }\n            } else if disabled {\n                let path = module_dir.join(defs::DISABLE_FILE_NAME);\n                if let Err(e) = ensure_file_exists(&path) {\n                    warn!(\"Failed to create {}: {e}\", path.display());\n                }\n            }\n        }\n        Ok(())\n    })?;\n    Ok(())\n}\n\n/// Get common environment variables for script execution\npub fn get_common_script_envs() -> Vec<(&'static str, String)> {\n    vec![\n        (\"ASH_STANDALONE\", \"1\".to_string()),\n        (\"APATCH\", \"true\".to_string()),\n        (\"APATCH_VER\", defs::VERSION_NAME.to_string()),\n        (\"APATCH_VER_CODE\", defs::VERSION_CODE.to_string()),\n        (\n            \"PATH\",\n            format!(\n                \"{}:{}\",\n                env_var(\"PATH\").unwrap_or_default(),\n                defs::BINARY_DIR.trim_end_matches('/')\n            ),\n        ),\n    ]\n}\n\n// because we use something like A-B update\n// we need to update the module state after the boot_completed\n// if someone(such as the module) install a module before the boot_completed\n// then it may cause some problems, just forbid it\nfn ensure_boot_completed() -> Result<()> {\n    // ensure getprop sys.boot_completed == 1\n    if getprop(\"sys.boot_completed\").as_deref() != Some(\"1\") {\n        bail!(\"Android is Booting!\");\n    }\n    Ok(())\n}\n\nfn mark_update() -> Result<()> {\n    ensure_file_exists(concatcp!(defs::WORKING_DIR, defs::UPDATE_FILE_NAME))\n}\n\nfn mark_module_state(module: &str, flag_file: &str, create_or_delete: bool) -> Result<()> {\n    let module_state_file = Path::new(defs::MODULE_DIR).join(module).join(flag_file);\n    if create_or_delete {\n        ensure_file_exists(module_state_file)\n    } else {\n        if module_state_file.exists() {\n            fs::remove_file(module_state_file)?;\n        }\n        Ok(())\n    }\n}\npub fn foreach_module(\n    module_type: ModuleType,\n    mut f: impl FnMut(&Path) -> Result<()>,\n) -> Result<()> {\n    let modules_dir = Path::new(match module_type {\n        ModuleType::Updated => MODULE_UPDATE_DIR,\n        _ => defs::MODULE_DIR,\n    });\n    let dir = std::fs::read_dir(modules_dir)?;\n    for entry in dir.flatten() {\n        let path = entry.path();\n        if !path.is_dir() {\n            warn!(\"{} is not a directory, skip\", path.display());\n            continue;\n        }\n\n        if module_type == ModuleType::Active && path.join(defs::DISABLE_FILE_NAME).exists() {\n            info!(\"{} is disabled, skip\", path.display());\n            continue;\n        }\n        if module_type == ModuleType::Active && path.join(defs::REMOVE_FILE_NAME).exists() {\n            warn!(\"{} is removed, skip\", path.display());\n            continue;\n        }\n\n        f(&path)?;\n    }\n\n    Ok(())\n}\n\nfn foreach_active_module(f: impl FnMut(&Path) -> Result<()>) -> Result<()> {\n    foreach_module(ModuleType::Active, f)\n}\n\npub fn load_sepolicy_rule() -> Result<()> {\n    foreach_active_module(|path| {\n        let rule_file = path.join(\"sepolicy.rule\");\n        if !rule_file.exists() {\n            return Ok(());\n        }\n\n        info!(\"load policy: {}\", &rule_file.display());\n        Command::new(assets::MAGISKPOLICY_PATH)\n            .arg(\"--live\")\n            .arg(\"--apply\")\n            .arg(&rule_file)\n            .status()\n            .with_context(|| format!(\"Failed to exec {}\", rule_file.display()))?;\n        Ok(())\n    })?;\n\n    Ok(())\n}\n\npub fn exec_script<T: AsRef<Path>>(path: T, wait: bool) -> Result<()> {\n    info!(\"exec {}\", path.as_ref().display());\n\n    let mut command = &mut Command::new(assets::BUSYBOX_PATH);\n    #[cfg(unix)]\n    {\n        command = command.process_group(0);\n        command = unsafe {\n            command.pre_exec(|| {\n                // ignore the error?\n                switch_cgroups();\n                Ok(())\n            })\n        };\n    }\n    command = command\n        .current_dir(path.as_ref().parent().unwrap())\n        .arg(\"sh\")\n        .arg(path.as_ref())\n        .env(\"ASH_STANDALONE\", \"1\")\n        .env(\"APATCH\", \"true\")\n        .env(\"APATCH_VER\", defs::VERSION_NAME)\n        .env(\"APATCH_VER_CODE\", defs::VERSION_CODE)\n        .env(\n            \"PATH\",\n            format!(\n                \"{}:{}\",\n                env_var(\"PATH\")?,\n                defs::BINARY_DIR.trim_end_matches('/')\n            ),\n        );\n\n    let result = if wait {\n        command.status().map(|_| ())\n    } else {\n        command.spawn().map(|_| ())\n    };\n    result.map_err(|err| anyhow!(\"Failed to exec {}: {}\", path.as_ref().display(), err))\n}\n\npub fn exec_stage_script(stage: &str, block: bool) -> Result<()> {\n    foreach_active_module(|module| {\n        let script_path = module.join(format!(\"{stage}.sh\"));\n        if !script_path.exists() {\n            return Ok(());\n        }\n\n        exec_script(&script_path, block)\n    })?;\n    Ok(())\n}\n\npub fn exec_common_scripts(dir: &str, wait: bool) -> Result<()> {\n    let script_dir = Path::new(defs::ADB_DIR).join(dir);\n    if !script_dir.exists() {\n        info!(\"{} not exists, skip\", script_dir.display());\n        return Ok(());\n    }\n\n    let dir = fs::read_dir(&script_dir)?;\n    for entry in dir.flatten() {\n        let path = entry.path();\n\n        if !is_executable(&path) {\n            warn!(\"{} is not executable, skip\", path.display());\n            continue;\n        }\n\n        exec_script(path, wait)?;\n    }\n\n    Ok(())\n}\n\npub fn load_system_prop() -> Result<()> {\n    foreach_active_module(|module| {\n        let system_prop = module.join(\"system.prop\");\n        if !system_prop.exists() {\n            return Ok(());\n        }\n        info!(\"load {} system.prop\", module.display());\n\n        // resetprop -n --file system.prop\n        Command::new(assets::RESETPROP_PATH)\n            .arg(\"-n\")\n            .arg(\"--file\")\n            .arg(&system_prop)\n            .status()\n            .with_context(|| format!(\"Failed to exec {}\", system_prop.display()))?;\n\n        Ok(())\n    })?;\n\n    Ok(())\n}\n\npub fn prune_modules() -> Result<()> {\n    foreach_module(ModuleType::All, |module| {\n        fs::remove_file(module.join(defs::UPDATE_FILE_NAME)).ok();\n        if !module.join(defs::REMOVE_FILE_NAME).exists() {\n            return Ok(());\n        }\n\n        info!(\"remove module: {}\", module.display());\n\n        // Execute metamodule's metauninstall.sh first\n        let module_id = module.file_name().and_then(|n| n.to_str()).unwrap_or(\"\");\n\n        // Check if this is a metamodule\n        let is_metamodule = read_module_prop(module)\n            .map(|props| metamodule::is_metamodule(&props))\n            .unwrap_or(false);\n\n        if is_metamodule {\n            info!(\"Removing metamodule symlink\");\n            if let Err(e) = metamodule::remove_symlink() {\n                warn!(\"Failed to remove metamodule symlink: {e}\");\n            }\n        } else if let Err(e) = metamodule::exec_metauninstall_script(module_id) {\n            warn!(\"Failed to exec metamodule uninstall for {module_id}: {e}\",);\n        }\n\n        // Then execute module's own uninstall.sh\n        let uninstaller = module.join(\"uninstall.sh\");\n        if uninstaller.exists()\n            && let Err(e) = exec_script(uninstaller, true)\n        {\n            warn!(\"Failed to exec uninstaller: {e}\");\n        }\n\n        // Finally remove the module directory\n        if let Err(e) = remove_dir_all(module) {\n            warn!(\"Failed to remove {}: {e}\", module.display());\n        }\n\n        Ok(())\n    })?;\n\n    // collect remaining modules, if none, clean up metamodule record\n    let remaining_modules: Vec<_> = std::fs::read_dir(defs::MODULE_DIR)?\n        .filter_map(std::result::Result::ok)\n        .filter(|entry| entry.path().join(\"module.prop\").exists())\n        .collect();\n\n    if remaining_modules.is_empty() {\n        info!(\"no remaining modules.\");\n    }\n\n    Ok(())\n}\n\nfn _install_module(zip: &str) -> Result<()> {\n    ensure_boot_completed()?;\n\n    // print banner\n    println!(include_str!(\"banner\"));\n\n    assets::ensure_binaries().with_context(|| \"binary missing\")?;\n\n    // first check if workding dir is usable\n    ensure_dir_exists(defs::WORKING_DIR).with_context(|| \"Failed to create working dir\")?;\n    ensure_dir_exists(defs::BINARY_DIR).with_context(|| \"Failed to create bin dir\")?;\n\n    // read the module_id from zip\n    let mut buffer: Vec<u8> = Vec::new();\n    let entry_path = PathBuf::from_str(\"module.prop\")?;\n    let zip_path = PathBuf::from_str(zip)?;\n    let zip_path = zip_path.canonicalize()?;\n    zip_extract_file_to_memory(&zip_path, &entry_path, &mut buffer)?;\n    let mut module_prop = HashMap::new();\n    PropertiesIter::new_with_encoding(Cursor::new(buffer), encoding_rs::UTF_8).read_into(\n        |k, v| {\n            module_prop.insert(k, v);\n        },\n    )?;\n    info!(\"module prop: {:?}\", module_prop);\n\n    let Some(module_id) = module_prop.get(\"id\") else {\n        bail!(\"module id not found in module.prop!\");\n    };\n    let module_id = module_id.trim();\n\n    // Check if this module is a metamodule\n    let is_metamodule = metamodule::is_metamodule(&module_prop);\n\n    // Check if module needs mounting (has system/ dir and no skip_mount file)\n    let needs_mount = {\n        let zip_file = fs::File::open(&zip_path)?;\n        let archive = zip::ZipArchive::new(zip_file)?;\n        let has_system = archive.file_names().any(|name| name.starts_with(\"system/\"));\n        let has_skip_mount = archive.file_names().any(|name| name == \"skip_mount\");\n        has_system && !has_skip_mount\n    };\n\n    // Check if it's safe to install regular module\n    if !is_metamodule && needs_mount && let Err(is_disabled) = metamodule::check_install_safety() {\n        println!(\"\\n❌ Installation Blocked\");\n        println!(\"┌────────────────────────────────\");\n        println!(\"│ A metamodule with custom installer is active\");\n        println!(\"│\");\n        if is_disabled {\n            println!(\"│ Current state: Disabled\");\n            println!(\"│ Action required: Re-enable or uninstall it, then reboot\");\n        } else {\n            println!(\"│ Current state: Pending changes\");\n            println!(\"│ Action required: Reboot to apply changes first\");\n        }\n        println!(\"└─────────────────────────────────\\n\");\n        bail!(\"Metamodule installation blocked\");\n    }\n\n    let modules_dir = Path::new(defs::MODULE_DIR);\n    let modules_update_dir = Path::new(defs::MODULE_UPDATE_DIR);\n    if !Path::new(modules_dir).exists() {\n        fs::create_dir(modules_dir).expect(\"Failed to create modules folder\");\n        let permissions = fs::Permissions::from_mode(0o700);\n        fs::set_permissions(modules_dir, permissions).expect(\"Failed to set permissions\");\n    }\n\n    if is_metamodule {\n        info!(\"Installing metamodule: {module_id}\");\n\n        // Check if there's already a metamodule installed\n        if metamodule::has_metamodule()\n            && let Some(existing_path) = metamodule::get_metamodule_path()\n        {\n            let existing_id = read_module_prop(&existing_path)\n                .ok()\n                .and_then(|m| m.get(\"id\").cloned())\n                .unwrap_or_else(|| \"unknown\".to_string());\n\n            if existing_id != module_id {\n                println!(\"\\n❌ Installation Failed\");\n                println!(\"┌────────────────────────────────\");\n                println!(\"│ A metamodule is already installed\");\n                println!(\"│   Current metamodule: {existing_id}\");\n                println!(\"│\");\n                println!(\"│ Only one metamodule can be active at a time.\");\n                println!(\"│\");\n                println!(\"│ To install this metamodule:\");\n                println!(\"│   1. Uninstall the current metamodule\");\n                println!(\"│   2. Reboot your device\");\n                println!(\"│   3. Install the new metamodule\");\n                println!(\"└─────────────────────────────────\\n\");\n                bail!(\"Cannot install multiple metamodules\");\n            }\n        }\n    }\n\n    let module_dir = format!(\"{}{}\", modules_dir.display(), module_id);\n    let _module_update_dir = format!(\"{}{}\", modules_update_dir.display(), module_id);\n    info!(\"module dir: {}\", module_dir);\n    if !Path::new(&module_dir.clone()).exists() {\n        fs::create_dir(&module_dir.clone()).expect(\"Failed to create module folder\");\n        let permissions = fs::Permissions::from_mode(0o700);\n        fs::set_permissions(module_dir.clone(), permissions).expect(\"Failed to set permissions\");\n    }\n    // unzip the image and move it to modules_update/<id> dir\n    let file = fs::File::open(zip)?;\n    let mut archive = zip::ZipArchive::new(file)?;\n    archive.extract(&_module_update_dir)?;\n\n    println!(\"- Running module installer\");\n    exec_install_script(zip, is_metamodule)?;\n\n    // set permission and selinux context for $MOD/system\n    let module_system_dir = PathBuf::from(module_dir.clone()).join(\"system\");\n    if module_system_dir.exists() {\n        #[cfg(unix)]\n        fs::set_permissions(&module_system_dir, fs::Permissions::from_mode(0o755))?;\n        restorecon::restore_syscon(&module_system_dir)?;\n    }\n\n    // Create symlink for metamodule\n    if is_metamodule {\n        println!(\"- Creating metamodule symlink\");\n        metamodule::ensure_symlink(&module_dir)?;\n    }\n\n    mark_update()?;\n    Ok(())\n}\n\npub fn install_module(zip: &str) -> Result<()> {\n    let result = _install_module(zip);\n    result\n}\n\npub fn _uninstall_module(id: &str, update_dir: &str) -> Result<()> {\n    let dir = Path::new(update_dir);\n    ensure!(dir.exists(), \"No module installed\");\n\n    // iterate the modules_update dir, find the module to be removed\n    let dir = fs::read_dir(dir)?;\n    for entry in dir.flatten() {\n        let path = entry.path();\n        let module_prop = path.join(\"module.prop\");\n        if !module_prop.exists() {\n            continue;\n        }\n        let content = fs::read(module_prop)?;\n        let mut module_id: String = String::new();\n        PropertiesIter::new_with_encoding(Cursor::new(content), encoding_rs::UTF_8).read_into(\n            |k, v| {\n                if k.eq(\"id\") {\n                    module_id = v;\n                }\n            },\n        )?;\n        if module_id.eq(id) {\n            let remove_file = path.join(defs::REMOVE_FILE_NAME);\n            fs::File::create(remove_file).with_context(|| \"Failed to create remove file.\")?;\n            break;\n        }\n    }\n\n    // santity check\n    let target_module_path = format!(\"{update_dir}/{id}\");\n    let target_module = Path::new(&target_module_path);\n    if target_module.exists() {\n        let remove_file = target_module.join(defs::REMOVE_FILE_NAME);\n        if !remove_file.exists() {\n            fs::File::create(remove_file).with_context(|| \"Failed to create remove file.\")?;\n        }\n    }\n\n    let _ = mark_module_state(id, defs::REMOVE_FILE_NAME, true);\n    Ok(())\n}\npub fn uninstall_module(id: &str) -> Result<()> {\n    _uninstall_module(id, defs::MODULE_DIR)?;\n    mark_update()?;\n    Ok(())\n}\n\n/// Read module.prop from the given module path and return as a HashMap\npub fn read_module_prop(module_path: &Path) -> Result<HashMap<String, String>> {\n    let module_prop = module_path.join(\"module.prop\");\n    ensure!(\n        module_prop.exists(),\n        \"module.prop not found in {}\",\n        module_path.display()\n    );\n\n    let content = std::fs::read(&module_prop)\n        .with_context(|| format!(\"Failed to read module.prop: {}\", module_prop.display()))?;\n\n    let mut prop_map: HashMap<String, String> = HashMap::new();\n    PropertiesIter::new_with_encoding(Cursor::new(content), encoding_rs::UTF_8)\n        .read_into(|k, v| {\n            prop_map.insert(k, v);\n        })\n        .with_context(|| format!(\"Failed to parse module.prop: {}\", module_prop.display()))?;\n\n    Ok(prop_map)\n}\n\npub fn run_action(id: &str) -> Result<()> {\n    let action_script_path = format!(\"/data/adb/modules/{}/action.sh\", id);\n    if Path::new(&action_script_path).exists() {\n        let _ = exec_script(&action_script_path, true);\n    } else {\n        //if no action.sh, try to run lua action\n        lua::run_lua(&id, \"action\", false, true).map_err(|e| anyhow::anyhow!(\"{}\", e))?;\n    }\n    Ok(())\n}\n\nfn _change_module_state(module_dir: &str, mid: &str, enable: bool) -> Result<()> {\n    let src_module_path = format!(\"{module_dir}/{mid}\");\n    let src_module = Path::new(&src_module_path);\n    ensure!(src_module.exists(), \"module: {} not found!\", mid);\n\n    let disable_path = src_module.join(defs::DISABLE_FILE_NAME);\n    if enable {\n        if disable_path.exists() {\n            fs::remove_file(&disable_path).with_context(|| {\n                format!(\"Failed to remove disable file: {}\", &disable_path.display())\n            })?;\n        }\n    } else {\n        ensure_file_exists(disable_path)?;\n    }\n\n    let _ = mark_module_state(mid, defs::DISABLE_FILE_NAME, !enable);\n\n    Ok(())\n}\n\npub fn _enable_module(id: &str, update_dir: &Path) -> Result<()> {\n    if let Some(module_dir_str) = update_dir.to_str() {\n        _change_module_state(module_dir_str, id, true)\n    } else {\n        info!(\"Enable module failed: Invalid path\");\n        Err(anyhow::anyhow!(\"Invalid module directory\"))\n    }\n}\n\npub fn enable_module(id: &str) -> Result<()> {\n    let update_dir = Path::new(defs::MODULE_DIR);\n    _enable_module(id, update_dir)?;\n    Ok(())\n}\n\npub fn _disable_module(id: &str, update_dir: &Path) -> Result<()> {\n    if let Some(module_dir_str) = update_dir.to_str() {\n        _change_module_state(module_dir_str, id, false)\n    } else {\n        info!(\"Disable module failed: Invalid path\");\n        Err(anyhow::anyhow!(\"Invalid module directory\"))\n    }\n}\n\npub fn disable_module(id: &str) -> Result<()> {\n    let module_dir = Path::new(defs::MODULE_DIR);\n    _disable_module(id, module_dir)?;\n\n    Ok(())\n}\n\npub fn _disable_all_modules(dir: &str) -> Result<()> {\n    let dir = fs::read_dir(dir)?;\n    for entry in dir.flatten() {\n        let path = entry.path();\n        let disable_flag = path.join(defs::DISABLE_FILE_NAME);\n        if let Err(e) = ensure_file_exists(disable_flag) {\n            warn!(\"Failed to disable module: {}: {}\", path.display(), e);\n        }\n    }\n    Ok(())\n}\n\npub fn disable_all_modules() -> Result<()> {\n    // Skip disabling modules since boot completed\n    if getprop(\"sys.boot_completed\").as_deref() == Some(\"1\") {\n        info!(\"System boot completed, no need to disable all modules\");\n        return Ok(());\n    }\n    mark_update()?;\n    _disable_all_modules(defs::MODULE_DIR)?;\n    Ok(())\n}\n\nfn _list_modules(path: &str) -> Vec<HashMap<String, String>> {\n    // first check enabled modules\n    let dir = fs::read_dir(path);\n    let Ok(dir) = dir else {\n        return Vec::new();\n    };\n\n    let mut modules: Vec<HashMap<String, String>> = Vec::new();\n\n    for entry in dir.flatten() {\n        let path = entry.path();\n        info!(\"path: {}\", path.display());\n        let module_prop = path.join(\"module.prop\");\n        if !module_prop.exists() {\n            continue;\n        }\n        let content = fs::read(&module_prop);\n        let Ok(content) = content else {\n            warn!(\"Failed to read file: {}\", module_prop.display());\n            continue;\n        };\n        let mut module_prop_map: HashMap<String, String> = HashMap::new();\n        let encoding = encoding_rs::UTF_8;\n        let result =\n            PropertiesIter::new_with_encoding(Cursor::new(content), encoding).read_into(|k, v| {\n                module_prop_map.insert(k, v);\n            });\n\n        if !module_prop_map.contains_key(\"id\") || module_prop_map[\"id\"].is_empty() {\n            match entry.file_name().to_str() {\n                Some(id) => {\n                    info!(\"Use dir name as module id: {}\", id);\n                    module_prop_map.insert(\"id\".to_owned(), id.to_owned());\n                }\n                _ => {\n                    info!(\"Failed to get module id: {:?}\", module_prop);\n                    continue;\n                }\n            }\n        }\n\n        // Add enabled, update, remove flags\n        let enabled = !path.join(defs::DISABLE_FILE_NAME).exists();\n        let update = path.join(defs::UPDATE_FILE_NAME).exists();\n        let remove = path.join(defs::REMOVE_FILE_NAME).exists();\n        let web = path.join(defs::MODULE_WEB_DIR).exists();\n        let id = module_prop_map.get(\"id\").map(|s| s.as_str()).unwrap_or(\"\");\n        let id_lua_file = format!(\"{}.lua\", id);\n        let action = path.join(defs::MODULE_ACTION_SH).exists() || path.join(&id_lua_file).exists();\n\n        module_prop_map.insert(\"enabled\".to_owned(), enabled.to_string());\n        module_prop_map.insert(\"update\".to_owned(), update.to_string());\n        module_prop_map.insert(\"remove\".to_owned(), remove.to_string());\n        module_prop_map.insert(\"web\".to_owned(), web.to_string());\n        module_prop_map.insert(\"action\".to_owned(), action.to_string());\n\n        if result.is_err() {\n            warn!(\"Failed to parse module.prop: {}\", module_prop.display());\n            continue;\n        }\n        modules.push(module_prop_map);\n    }\n\n    modules\n}\n\npub fn list_modules() -> Result<()> {\n    let modules = _list_modules(defs::MODULE_DIR);\n    println!(\"{}\", serde_json::to_string_pretty(&modules)?);\n    Ok(())\n}\n"
  },
  {
    "path": "apd/src/package.rs",
    "content": "use std::{\n    fs::File,\n    io::{self, BufRead},\n    path::Path,\n    thread,\n    time::Duration,\n};\n\nuse log::{info, warn};\nuse serde::{Deserialize, Serialize};\n\n#[derive(Deserialize, Serialize, Clone)]\npub struct PackageConfig {\n    pub pkg: String,\n    pub exclude: i32,\n    pub allow: i32,\n    pub uid: i32,\n    pub to_uid: i32,\n    pub sctx: String,\n}\n\npub fn read_ap_package_config() -> Vec<PackageConfig> {\n    let max_retry = 5;\n    for _ in 0..max_retry {\n        let file = match File::open(\"/data/adb/ap/package_config\") {\n            Ok(file) => file,\n            Err(e) => {\n                warn!(\"Error opening file: {}\", e);\n                thread::sleep(Duration::from_secs(1));\n                continue;\n            }\n        };\n\n        let mut reader = csv::Reader::from_reader(file);\n        let mut package_configs = Vec::new();\n        let mut success = true;\n\n        for record in reader.deserialize() {\n            match record {\n                Ok(config) => package_configs.push(config),\n                Err(e) => {\n                    warn!(\"Error deserializing record: {}\", e);\n                    success = false;\n                    break;\n                }\n            }\n        }\n\n        if success {\n            return package_configs;\n        }\n        thread::sleep(Duration::from_secs(1));\n    }\n    Vec::new()\n}\n\npub fn write_ap_package_config(package_configs: &[PackageConfig]) -> io::Result<()> {\n    let max_retry = 5;\n    for _ in 0..max_retry {\n        let temp_path = \"/data/adb/ap/package_config.tmp\";\n        let file = match File::create(temp_path) {\n            Ok(file) => file,\n            Err(e) => {\n                warn!(\"Error creating temp file: {}\", e);\n                thread::sleep(Duration::from_secs(1));\n                continue;\n            }\n        };\n\n        let mut writer = csv::Writer::from_writer(file);\n        let mut success = true;\n\n        for config in package_configs {\n            if let Err(e) = writer.serialize(config) {\n                warn!(\"Error serializing record: {}\", e);\n                success = false;\n                break;\n            }\n        }\n\n        if !success {\n            thread::sleep(Duration::from_secs(1));\n            continue;\n        }\n\n        if let Err(e) = writer.flush() {\n            warn!(\"Error flushing writer: {}\", e);\n            thread::sleep(Duration::from_secs(1));\n            continue;\n        }\n\n        if let Err(e) = std::fs::rename(temp_path, \"/data/adb/ap/package_config\") {\n            warn!(\"Error renaming temp file: {}\", e);\n            thread::sleep(Duration::from_secs(1));\n            continue;\n        }\n        return Ok(());\n    }\n    Err(io::Error::new(\n        io::ErrorKind::Other,\n        \"Failed after max retries\",\n    ))\n}\n\nfn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>\nwhere\n    P: AsRef<Path>,\n{\n    File::open(filename).map(|file| io::BufReader::new(file).lines())\n}\n\npub fn synchronize_package_uid() -> io::Result<()> {\n    info!(\"[synchronize_package_uid] Start synchronizing root list with system packages...\");\n\n    let max_retry = 5;\n    for _ in 0..max_retry {\n        match read_lines(\"/data/system/packages.list\") {\n            Ok(lines) => {\n                let lines: Vec<_> = lines.filter_map(|line| line.ok()).collect();\n\n                let mut package_configs = read_ap_package_config();\n\n                let system_packages: Vec<String> = lines\n                    .iter()\n                    .filter_map(|line| line.split_whitespace().next())\n                    .map(|pkg| pkg.to_string())\n                    .collect();\n\n                let original_len = package_configs.len();\n                package_configs.retain(|config| system_packages.contains(&config.pkg));\n                let removed_count = original_len - package_configs.len();\n\n                if removed_count > 0 {\n                    info!(\n                        \"Removed {} uninstalled package configurations\",\n                        removed_count\n                    );\n                }\n\n                let mut updated = false;\n\n                for line in &lines {\n                    let words: Vec<&str> = line.split_whitespace().collect();\n                    if words.len() >= 2 {\n                        let pkg_name = words[0];\n                        if let Ok(uid) = words[1].parse::<i32>() {\n                            for config in package_configs\n                                .iter_mut()\n                                .filter(|config| config.pkg == pkg_name)\n                            {\n                                if config.uid % 100000 != uid % 100000 {\n                                    let new_uid = config.uid / 100000 * 100000 + uid % 100000;\n                                    info!(\n                                        \"Updating uid for package {}: {} -> {}\",\n                                        pkg_name, config.uid, new_uid\n                                    );\n                                    config.uid = new_uid;\n                                    updated = true;\n                                }\n                            }\n                        } else {\n                            warn!(\"Error parsing uid: {}\", words[1]);\n                        }\n                    }\n                }\n\n                if updated || removed_count > 0 {\n                    write_ap_package_config(&package_configs)?;\n                }\n                return Ok(());\n            }\n            Err(e) => {\n                warn!(\"Error reading packages.list: {}\", e);\n                thread::sleep(Duration::from_secs(1));\n            }\n        }\n    }\n    Err(io::Error::new(\n        io::ErrorKind::Other,\n        \"Failed after max retries\",\n    ))\n}\n"
  },
  {
    "path": "apd/src/pty.rs",
    "content": "use std::{\n    ffi::c_int,\n    fs::File,\n    io::{Read, Write, stderr, stdin, stdout},\n    mem::MaybeUninit,\n    os::fd::{AsFd, AsRawFd, OwnedFd, RawFd},\n    process::exit,\n    ptr::null_mut,\n    sync::Mutex,\n    thread,\n};\n\nuse anyhow::{Ok, Result, bail};\nuse libc::{\n    __errno, EINTR, SIG_BLOCK, SIG_UNBLOCK, SIGWINCH, TIOCGWINSZ, TIOCSWINSZ, fork,\n    pthread_sigmask, sigaddset, sigemptyset, sigset_t, sigwait, waitpid, winsize,\n};\nuse rustix::{\n    fs::{Mode, OFlags, open},\n    io::dup,\n    ioctl::{Getter, Opcode, ioctl, opcode},\n    process::setsid,\n    pty::{grantpt, unlockpt},\n    stdio::{dup2_stderr, dup2_stdin, dup2_stdout},\n    termios::{OptionalActions, Termios, isatty, tcgetattr, tcsetattr},\n};\n\nuse crate::{defs::PTS_NAME, utils::get_tmp_path};\n\n// https://github.com/topjohnwu/Magisk/blob/5627053b7481618adfdf8fa3569b48275589915b/native/src/core/su/pts.cpp\n\nfn get_pty_num<F: AsFd>(fd: F) -> Result<u32> {\n    // TIOCGPTN: Get the PTY number\n    const TIOCGPTN: Opcode = opcode::read::<u32>(b'T', 0x30);\n    Ok(unsafe {\n        let tiocgptn = Getter::<TIOCGPTN, u32>::new();\n        ioctl(fd, tiocgptn)?\n    })\n}\n\nstatic OLD_STDIN: Mutex<Option<Termios>> = Mutex::new(None);\n\nfn watch_sigwinch_async(slave: RawFd) {\n    let mut winch = MaybeUninit::<sigset_t>::uninit();\n    unsafe {\n        sigemptyset(winch.as_mut_ptr());\n        sigaddset(winch.as_mut_ptr(), SIGWINCH);\n        pthread_sigmask(SIG_BLOCK, winch.as_mut_ptr(), null_mut());\n    }\n\n    thread::spawn(move || unsafe {\n        let mut winch = MaybeUninit::<sigset_t>::uninit();\n        sigemptyset(winch.as_mut_ptr());\n        sigaddset(winch.as_mut_ptr(), SIGWINCH);\n        pthread_sigmask(SIG_UNBLOCK, winch.as_mut_ptr(), null_mut());\n        let mut sig: c_int = 0;\n        loop {\n            let mut w = MaybeUninit::<winsize>::uninit();\n            if libc::ioctl(1, TIOCGWINSZ, w.as_mut_ptr()) < 0 {\n                continue;\n            }\n            libc::ioctl(slave, TIOCSWINSZ, w.as_mut_ptr());\n            if sigwait(winch.as_mut_ptr(), &mut sig) != 0 {\n                break;\n            }\n        }\n    });\n}\n\nfn set_stdin_raw() -> rustix::io::Result<()> {\n    let mut termios = tcgetattr(stdin())?;\n\n    let mut guard = OLD_STDIN.lock().unwrap();\n    *guard = Some(termios.clone());\n    drop(guard);\n\n    termios.make_raw();\n    tcsetattr(stdin(), OptionalActions::Flush, &termios)\n}\n\nfn restore_stdin() -> Result<()> {\n    let mut guard = OLD_STDIN.lock().unwrap();\n\n    if let Some(original_termios) = guard.take() {\n        tcsetattr(stdin(), OptionalActions::Flush, &original_termios)?;\n    }\n\n    Ok(())\n}\n\nfn pump<R: Read, W: Write>(mut from: R, mut to: W) {\n    let mut buf = [0u8; 4096];\n    loop {\n        match from.read(&mut buf) {\n            Result::Ok(len) => {\n                if len == 0 {\n                    return;\n                }\n                if to.write_all(&buf[0..len]).is_err() {\n                    return;\n                }\n                if to.flush().is_err() {\n                    return;\n                }\n            }\n            Err(_) => {\n                return;\n            }\n        }\n    }\n}\n\nfn pump_stdin_async(mut ptmx: File) {\n    let _ = set_stdin_raw();\n\n    thread::spawn(move || {\n        let mut stdin = stdin();\n        pump(&mut stdin, &mut ptmx);\n    });\n}\n\nfn pump_stdout_blocking(mut ptmx: File) {\n    let mut stdout = stdout();\n    pump(&mut ptmx, &mut stdout);\n\n    let _ = restore_stdin();\n}\n\nfn create_transfer(ptmx: OwnedFd) -> Result<()> {\n    let pid = unsafe { fork() };\n    match pid {\n        d if d < 0 => bail!(\"fork\"),\n        0 => return Ok(()),\n        _ => {}\n    }\n\n    let ptmx_r = ptmx;\n    let ptmx_w = dup(&ptmx_r)?;\n\n    let ptmx_r = File::from(ptmx_r);\n    let ptmx_w = File::from(ptmx_w);\n\n    watch_sigwinch_async(ptmx_w.as_raw_fd());\n    pump_stdin_async(ptmx_r);\n    pump_stdout_blocking(ptmx_w);\n\n    let mut status: c_int = -1;\n\n    unsafe {\n        loop {\n            if waitpid(pid, &mut status, 0) == -1 && *__errno() != EINTR {\n                continue;\n            }\n            break;\n        }\n    }\n\n    exit(status)\n}\n\npub fn prepare_pty() -> Result<()> {\n    let tty_in = isatty(stdin());\n    let tty_out = isatty(stdout());\n    let tty_err = isatty(stderr());\n    if !tty_in && !tty_out && !tty_err {\n        return Ok(());\n    }\n\n    let mut pts_path = format!(\"{}/{}\", get_tmp_path(), PTS_NAME);\n    if !std::path::Path::new(&pts_path).exists() {\n        pts_path = \"/dev/pts\".to_string();\n    }\n    let ptmx_path = format!(\"{}/ptmx\", pts_path);\n    let ptmx_fd = open(ptmx_path, OFlags::RDWR, Mode::empty())?;\n    grantpt(&ptmx_fd)?;\n    unlockpt(&ptmx_fd)?;\n    let pty_num = get_pty_num(&ptmx_fd)?;\n    create_transfer(ptmx_fd)?;\n    setsid()?;\n    let pty_fd = open(format!(\"{pts_path}/{pty_num}\"), OFlags::RDWR, Mode::empty())?;\n    if tty_in {\n        dup2_stdin(&pty_fd)?;\n    }\n    if tty_out {\n        dup2_stdout(&pty_fd)?;\n    }\n    if tty_err {\n        dup2_stderr(&pty_fd)?;\n    }\n    Ok(())\n}\n"
  },
  {
    "path": "apd/src/restorecon.rs",
    "content": "use std::path::Path;\n\nuse anyhow::Result;\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\nuse anyhow::{Context, Ok};\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\nuse extattr::{Flags as XattrFlags, lsetxattr};\nuse jwalk::{Parallelism::Serial, WalkDir};\n\nuse crate::defs;\n\npub const SYSTEM_CON: &str = \"u:object_r:system_file:s0\";\npub const ADB_CON: &str = \"u:object_r:adb_data_file:s0\";\npub const UNLABEL_CON: &str = \"u:object_r:unlabeled:s0\";\n\nconst SELINUX_XATTR: &str = \"security.selinux\";\n\npub fn lsetfilecon<P: AsRef<Path>>(path: P, con: &str) -> Result<()> {\n    #[cfg(any(target_os = \"linux\", target_os = \"android\"))]\n    lsetxattr(&path, SELINUX_XATTR, con, XattrFlags::empty()).with_context(|| {\n        format!(\n            \"Failed to change SELinux context for {}\",\n            path.as_ref().display()\n        )\n    })?;\n    Ok(())\n}\n\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\npub fn lgetfilecon<P: AsRef<Path>>(path: P) -> Result<String> {\n    let con = extattr::lgetxattr(&path, SELINUX_XATTR).with_context(|| {\n        format!(\n            \"Failed to get SELinux context for {}\",\n            path.as_ref().display()\n        )\n    })?;\n    let con = String::from_utf8_lossy(&con);\n    Ok(con.to_string())\n}\n\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\npub fn setsyscon<P: AsRef<Path>>(path: P) -> Result<()> {\n    lsetfilecon(path, SYSTEM_CON)\n}\n\n#[cfg(not(any(target_os = \"linux\", target_os = \"android\")))]\npub fn setsyscon<P: AsRef<Path>>(path: P) -> Result<()> {\n    unimplemented!()\n}\n\n#[cfg(not(any(target_os = \"linux\", target_os = \"android\")))]\npub fn lgetfilecon<P: AsRef<Path>>(path: P) -> Result<String> {\n    unimplemented!()\n}\n\npub fn restore_syscon<P: AsRef<Path>>(dir: P) -> Result<()> {\n    for dir_entry in WalkDir::new(dir).parallelism(Serial) {\n        if let Some(path) = dir_entry.ok().map(|dir_entry| dir_entry.path()) {\n            setsyscon(&path)?;\n        }\n    }\n    Ok(())\n}\n\nfn restore_syscon_if_unlabeled<P: AsRef<Path>>(dir: P) -> Result<()> {\n    for dir_entry in WalkDir::new(dir).parallelism(Serial) {\n        if let Some(path) = dir_entry.ok().map(|dir_entry| dir_entry.path()) {\n            if let Result::Ok(con) = lgetfilecon(&path) {\n                if con == UNLABEL_CON || con.is_empty() {\n                    lsetfilecon(&path, SYSTEM_CON)?;\n                }\n            }\n        }\n    }\n    Ok(())\n}\n\npub fn restorecon() -> Result<()> {\n    lsetfilecon(defs::DAEMON_PATH, ADB_CON)?;\n    restore_syscon_if_unlabeled(defs::MODULE_DIR)?;\n    Ok(())\n}\n"
  },
  {
    "path": "apd/src/sepolicy.rs",
    "content": "use std::{ffi, path::Path, vec};\n\nuse anyhow::{Result, bail};\nuse derive_new::new;\nuse nom::{\n    AsChar, IResult, Parser,\n    branch::alt,\n    bytes::complete::{tag, take_while, take_while_m_n, take_while1},\n    character::complete::{space0, space1},\n    combinator::map,\n};\n\ntype SeObject<'a> = Vec<&'a str>;\n\nfn is_sepolicy_char(c: char) -> bool {\n    c.is_alphanum() || c == '_' || c == '-'\n}\n\nfn parse_single_word(input: &str) -> IResult<&str, &str> {\n    take_while1(is_sepolicy_char).parse(input)\n}\n\nfn parse_bracket_objs(input: &str) -> IResult<&str, SeObject<'_>> {\n    let (input, (_, words, _)) = (\n        tag(\"{\"),\n        take_while_m_n(1, 100, |c: char| is_sepolicy_char(c) || c.is_whitespace()),\n        tag(\"}\"),\n    )\n        .parse(input)?;\n    Ok((input, words.split_whitespace().collect()))\n}\n\nfn parse_single_obj(input: &str) -> IResult<&str, SeObject<'_>> {\n    let (input, word) = take_while1(is_sepolicy_char).parse(input)?;\n    Ok((input, vec![word]))\n}\n\nfn parse_star(input: &str) -> IResult<&str, SeObject<'_>> {\n    let (input, _) = tag(\"*\").parse(input)?;\n    Ok((input, vec![\"*\"]))\n}\n\n// 1. a single sepolicy word\n// 2. { obj1 obj2 obj3 ...}\n// 3. *\nfn parse_seobj(input: &str) -> IResult<&str, SeObject<'_>> {\n    let (input, strs) = alt((parse_single_obj, parse_bracket_objs, parse_star)).parse(input)?;\n    Ok((input, strs))\n}\n\nfn parse_seobj_no_star(input: &str) -> IResult<&str, SeObject<'_>> {\n    let (input, strs) = alt((parse_single_obj, parse_bracket_objs)).parse(input)?;\n    Ok((input, strs))\n}\n\ntrait SeObjectParser<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self>\n    where\n        Self: Sized;\n}\n\n#[derive(Debug, PartialEq, Eq, new)]\nstruct NormalPerm<'a> {\n    op: &'a str,\n    source: SeObject<'a>,\n    target: SeObject<'a>,\n    class: SeObject<'a>,\n    perm: SeObject<'a>,\n}\n\n#[derive(Debug, PartialEq, Eq, new)]\nstruct XPerm<'a> {\n    op: &'a str,\n    source: SeObject<'a>,\n    target: SeObject<'a>,\n    class: SeObject<'a>,\n    operation: &'a str,\n    perm_set: &'a str,\n}\n\n#[derive(Debug, PartialEq, Eq, new)]\nstruct TypeState<'a> {\n    op: &'a str,\n    stype: SeObject<'a>,\n}\n\n#[derive(Debug, PartialEq, Eq, new)]\nstruct TypeAttr<'a> {\n    stype: SeObject<'a>,\n    sattr: SeObject<'a>,\n}\n\n#[derive(Debug, PartialEq, Eq, new)]\nstruct Type<'a> {\n    name: &'a str,\n    attrs: SeObject<'a>,\n}\n\n#[derive(Debug, PartialEq, Eq, new)]\nstruct Attr<'a> {\n    name: &'a str,\n}\n\n#[derive(Debug, PartialEq, Eq, new)]\nstruct TypeTransition<'a> {\n    source: &'a str,\n    target: &'a str,\n    class: &'a str,\n    default_type: &'a str,\n    object_name: Option<&'a str>,\n}\n\n#[derive(Debug, PartialEq, Eq, new)]\nstruct TypeChange<'a> {\n    op: &'a str,\n    source: &'a str,\n    target: &'a str,\n    class: &'a str,\n    default_type: &'a str,\n}\n\n#[derive(Debug, PartialEq, Eq, new)]\nstruct GenFsCon<'a> {\n    fs_name: &'a str,\n    partial_path: &'a str,\n    fs_context: &'a str,\n}\n\n#[derive(Debug)]\nenum PolicyStatement<'a> {\n    // \"allow *source_type *target_type *class *perm_set\"\n    // \"deny *source_type *target_type *class *perm_set\"\n    // \"auditallow *source_type *target_type *class *perm_set\"\n    // \"dontaudit *source_type *target_type *class *perm_set\"\n    NormalPerm(NormalPerm<'a>),\n\n    // \"allowxperm *source_type *target_type *class operation xperm_set\"\n    // \"auditallowxperm *source_type *target_type *class operation xperm_set\"\n    // \"dontauditxperm *source_type *target_type *class operation xperm_set\"\n    XPerm(XPerm<'a>),\n\n    // \"permissive ^type\"\n    // \"enforce ^type\"\n    TypeState(TypeState<'a>),\n\n    // \"type type_name ^(attribute)\"\n    Type(Type<'a>),\n\n    // \"typeattribute ^type ^attribute\"\n    TypeAttr(TypeAttr<'a>),\n\n    // \"attribute ^attribute\"\n    Attr(Attr<'a>),\n\n    // \"type_transition source_type target_type class default_type (object_name)\"\n    TypeTransition(TypeTransition<'a>),\n\n    // \"type_change source_type target_type class default_type\"\n    // \"type_member source_type target_type class default_type\"\n    TypeChange(TypeChange<'a>),\n\n    // \"genfscon fs_name partial_path fs_context\"\n    GenFsCon(GenFsCon<'a>),\n}\n\nimpl<'a> SeObjectParser<'a> for NormalPerm<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self> {\n        let (input, op) = alt((\n            tag(\"allow\"),\n            tag(\"deny\"),\n            tag(\"auditallow\"),\n            tag(\"dontaudit\"),\n        ))\n        .parse(input)?;\n\n        let (input, _) = space0(input)?;\n        let (input, source) = parse_seobj(input)?;\n        let (input, _) = space0(input)?;\n        let (input, target) = parse_seobj(input)?;\n        let (input, _) = space0(input)?;\n        let (input, class) = parse_seobj(input)?;\n        let (input, _) = space0(input)?;\n        let (input, perm) = parse_seobj(input)?;\n        Ok((input, NormalPerm::new(op, source, target, class, perm)))\n    }\n}\n\nimpl<'a> SeObjectParser<'a> for XPerm<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self> {\n        let (input, op) = alt((\n            tag(\"allowxperm\"),\n            tag(\"auditallowxperm\"),\n            tag(\"dontauditxperm\"),\n        ))\n        .parse(input)?;\n\n        let (input, _) = space0(input)?;\n        let (input, source) = parse_seobj(input)?;\n        let (input, _) = space0(input)?;\n        let (input, target) = parse_seobj(input)?;\n        let (input, _) = space0(input)?;\n        let (input, class) = parse_seobj(input)?;\n        let (input, _) = space0(input)?;\n        let (input, operation) = parse_single_word(input)?;\n        let (input, _) = space0(input)?;\n        let (input, perm_set) = parse_single_word(input)?;\n\n        Ok((\n            input,\n            XPerm::new(op, source, target, class, operation, perm_set),\n        ))\n    }\n}\n\nimpl<'a> SeObjectParser<'a> for TypeState<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self> {\n        let (input, op) = alt((tag(\"permissive\"), tag(\"enforce\"))).parse(input)?;\n\n        let (input, _) = space1(input)?;\n        let (input, stype) = parse_seobj_no_star(input)?;\n\n        Ok((input, TypeState::new(op, stype)))\n    }\n}\n\nimpl<'a> SeObjectParser<'a> for Type<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self> {\n        let (input, _) = tag(\"type\")(input)?;\n        let (input, _) = space1(input)?;\n        let (input, name) = parse_single_word(input)?;\n\n        if input.is_empty() {\n            return Ok((input, Type::new(name, vec![\"domain\"]))); // default to domain\n        }\n\n        let (input, _) = space1(input)?;\n        let (input, attrs) = parse_seobj_no_star(input)?;\n\n        Ok((input, Type::new(name, attrs)))\n    }\n}\n\nimpl<'a> SeObjectParser<'a> for TypeAttr<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self> {\n        let (input, _) = alt((tag(\"typeattribute\"), tag(\"attradd\"))).parse(input)?;\n        let (input, _) = space1(input)?;\n        let (input, stype) = parse_seobj_no_star(input)?;\n        let (input, _) = space1(input)?;\n        let (input, attr) = parse_seobj_no_star(input)?;\n\n        Ok((input, TypeAttr::new(stype, attr)))\n    }\n}\n\nimpl<'a> SeObjectParser<'a> for Attr<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self> {\n        let (input, _) = tag(\"attribute\")(input)?;\n        let (input, _) = space1(input)?;\n        let (input, attr) = parse_single_word(input)?;\n\n        Ok((input, Attr::new(attr)))\n    }\n}\n\nimpl<'a> SeObjectParser<'a> for TypeTransition<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self> {\n        let (input, _) = alt((tag(\"type_transition\"), tag(\"name_transition\"))).parse(input)?;\n        let (input, _) = space1(input)?;\n        let (input, source) = parse_single_word(input)?;\n        let (input, _) = space1(input)?;\n        let (input, target) = parse_single_word(input)?;\n        let (input, _) = space1(input)?;\n        let (input, class) = parse_single_word(input)?;\n        let (input, _) = space1(input)?;\n        let (input, default) = parse_single_word(input)?;\n\n        if input.is_empty() {\n            return Ok((\n                input,\n                TypeTransition::new(source, target, class, default, None),\n            ));\n        }\n\n        let (input, _) = space1(input)?;\n        let (input, object) = parse_single_word(input)?;\n\n        Ok((\n            input,\n            TypeTransition::new(source, target, class, default, Some(object)),\n        ))\n    }\n}\n\nimpl<'a> SeObjectParser<'a> for TypeChange<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self> {\n        let (input, op) = alt((tag(\"type_change\"), tag(\"type_member\"))).parse(input)?;\n        let (input, _) = space1(input)?;\n        let (input, source) = parse_single_word(input)?;\n        let (input, _) = space1(input)?;\n        let (input, target) = parse_single_word(input)?;\n        let (input, _) = space1(input)?;\n        let (input, class) = parse_single_word(input)?;\n        let (input, _) = space1(input)?;\n        let (input, default) = parse_single_word(input)?;\n\n        Ok((input, TypeChange::new(op, source, target, class, default)))\n    }\n}\n\nimpl<'a> SeObjectParser<'a> for GenFsCon<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self>\n    where\n        Self: Sized,\n    {\n        let (input, _) = tag(\"genfscon\")(input)?;\n        let (input, _) = space1(input)?;\n        let (input, fs) = parse_single_word(input)?;\n        let (input, _) = space1(input)?;\n        let (input, path) = parse_single_word(input)?;\n        let (input, _) = space1(input)?;\n        let (input, context) = parse_single_word(input)?;\n        Ok((input, GenFsCon::new(fs, path, context)))\n    }\n}\n\nimpl<'a> PolicyStatement<'a> {\n    fn parse(input: &'a str) -> IResult<&'a str, Self> {\n        let (input, _) = space0(input)?;\n        let (input, statement) = alt((\n            map(NormalPerm::parse, PolicyStatement::NormalPerm),\n            map(XPerm::parse, PolicyStatement::XPerm),\n            map(TypeState::parse, PolicyStatement::TypeState),\n            map(Type::parse, PolicyStatement::Type),\n            map(TypeAttr::parse, PolicyStatement::TypeAttr),\n            map(Attr::parse, PolicyStatement::Attr),\n            map(TypeTransition::parse, PolicyStatement::TypeTransition),\n            map(TypeChange::parse, PolicyStatement::TypeChange),\n            map(GenFsCon::parse, PolicyStatement::GenFsCon),\n        ))\n        .parse(input)?;\n        let (input, _) = space0(input)?;\n        let (input, _) = take_while(|c| c == ';')(input)?;\n        let (input, _) = space0(input)?;\n        Ok((input, statement))\n    }\n}\n\nfn parse_sepolicy<'a, 'b>(input: &'b str, strict: bool) -> Result<Vec<PolicyStatement<'a>>>\nwhere\n    'b: 'a,\n{\n    let mut statements = vec![];\n\n    for line in input.split(['\\n', ';']) {\n        let trimmed_line = line.trim();\n        if trimmed_line.is_empty() || trimmed_line.starts_with('#') {\n            continue;\n        }\n        if let Ok((_, statement)) = PolicyStatement::parse(trimmed_line) {\n            statements.push(statement);\n        } else if strict {\n            bail!(\"Failed to parse policy statement: {}\", line)\n        }\n    }\n    Ok(statements)\n}\n\nconst SEPOLICY_MAX_LEN: usize = 128;\n\nconst CMD_NORMAL_PERM: u32 = 1;\nconst CMD_XPERM: u32 = 2;\nconst CMD_TYPE_STATE: u32 = 3;\nconst CMD_TYPE: u32 = 4;\nconst CMD_TYPE_ATTR: u32 = 5;\nconst CMD_ATTR: u32 = 6;\nconst CMD_TYPE_TRANSITION: u32 = 7;\nconst CMD_TYPE_CHANGE: u32 = 8;\nconst CMD_GENFSCON: u32 = 9;\n\n#[derive(Debug, Default)]\nenum PolicyObject {\n    All, // for \"*\", stand for all objects, and is NULL in ffi\n    One([u8; SEPOLICY_MAX_LEN]),\n    #[default]\n    None,\n}\n\nimpl TryFrom<&str> for PolicyObject {\n    type Error = anyhow::Error;\n    fn try_from(s: &str) -> Result<Self> {\n        anyhow::ensure!(s.len() <= SEPOLICY_MAX_LEN, \"policy object too long\");\n        if s == \"*\" {\n            return Ok(PolicyObject::All);\n        }\n        let mut buf = [0u8; SEPOLICY_MAX_LEN];\n        buf[..s.len()].copy_from_slice(s.as_bytes());\n        Ok(PolicyObject::One(buf))\n    }\n}\n\n/// atomic statement, such as: allow domain1 domain2:file1 read;\n/// normal statement would be expanded to atomic statement, for example:\n/// allow domain1 domain2:file1 { read write }; would be expanded to two atomic statement\n/// allow domain1 domain2:file1 read;allow domain1 domain2:file1 write;\n#[allow(clippy::too_many_arguments)]\n#[derive(Debug, new)]\nstruct AtomicStatement {\n    cmd: u32,\n    subcmd: u32,\n    sepol1: PolicyObject,\n    sepol2: PolicyObject,\n    sepol3: PolicyObject,\n    sepol4: PolicyObject,\n    sepol5: PolicyObject,\n    sepol6: PolicyObject,\n    sepol7: PolicyObject,\n}\n\nimpl<'a> TryFrom<&'a NormalPerm<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(perm: &'a NormalPerm<'a>) -> Result<Self> {\n        let mut result = vec![];\n        let subcmd = match perm.op {\n            \"allow\" => 1,\n            \"deny\" => 2,\n            \"auditallow\" => 3,\n            \"dontaudit\" => 4,\n            _ => 0,\n        };\n        for &s in &perm.source {\n            for &t in &perm.target {\n                for &c in &perm.class {\n                    for &p in &perm.perm {\n                        result.push(AtomicStatement {\n                            cmd: CMD_NORMAL_PERM,\n                            subcmd,\n                            sepol1: s.try_into()?,\n                            sepol2: t.try_into()?,\n                            sepol3: c.try_into()?,\n                            sepol4: p.try_into()?,\n                            sepol5: PolicyObject::None,\n                            sepol6: PolicyObject::None,\n                            sepol7: PolicyObject::None,\n                        });\n                    }\n                }\n            }\n        }\n        Ok(result)\n    }\n}\n\nimpl<'a> TryFrom<&'a XPerm<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(perm: &'a XPerm<'a>) -> Result<Self> {\n        let mut result = vec![];\n        let subcmd = match perm.op {\n            \"allowxperm\" => 1,\n            \"auditallowxperm\" => 2,\n            \"dontauditxperm\" => 3,\n            _ => 0,\n        };\n        for &s in &perm.source {\n            for &t in &perm.target {\n                for &c in &perm.class {\n                    result.push(AtomicStatement {\n                        cmd: CMD_XPERM,\n                        subcmd,\n                        sepol1: s.try_into()?,\n                        sepol2: t.try_into()?,\n                        sepol3: c.try_into()?,\n                        sepol4: perm.operation.try_into()?,\n                        sepol5: perm.perm_set.try_into()?,\n                        sepol6: PolicyObject::None,\n                        sepol7: PolicyObject::None,\n                    });\n                }\n            }\n        }\n        Ok(result)\n    }\n}\n\nimpl<'a> TryFrom<&'a TypeState<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(perm: &'a TypeState<'a>) -> Result<Self> {\n        let mut result = vec![];\n        let subcmd = match perm.op {\n            \"permissive\" => 1,\n            \"enforcing\" => 2,\n            _ => 0,\n        };\n        for &t in &perm.stype {\n            result.push(AtomicStatement {\n                cmd: CMD_TYPE_STATE,\n                subcmd,\n                sepol1: t.try_into()?,\n                sepol2: PolicyObject::None,\n                sepol3: PolicyObject::None,\n                sepol4: PolicyObject::None,\n                sepol5: PolicyObject::None,\n                sepol6: PolicyObject::None,\n                sepol7: PolicyObject::None,\n            });\n        }\n        Ok(result)\n    }\n}\n\nimpl<'a> TryFrom<&'a Type<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(perm: &'a Type<'a>) -> Result<Self> {\n        let mut result = vec![];\n        for &attr in &perm.attrs {\n            result.push(AtomicStatement {\n                cmd: CMD_TYPE,\n                subcmd: 0,\n                sepol1: perm.name.try_into()?,\n                sepol2: attr.try_into()?,\n                sepol3: PolicyObject::None,\n                sepol4: PolicyObject::None,\n                sepol5: PolicyObject::None,\n                sepol6: PolicyObject::None,\n                sepol7: PolicyObject::None,\n            });\n        }\n        Ok(result)\n    }\n}\n\nimpl<'a> TryFrom<&'a TypeAttr<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(perm: &'a TypeAttr<'a>) -> Result<Self> {\n        let mut result = vec![];\n        for &t in &perm.stype {\n            for &attr in &perm.sattr {\n                result.push(AtomicStatement {\n                    cmd: CMD_TYPE_ATTR,\n                    subcmd: 0,\n                    sepol1: t.try_into()?,\n                    sepol2: attr.try_into()?,\n                    sepol3: PolicyObject::None,\n                    sepol4: PolicyObject::None,\n                    sepol5: PolicyObject::None,\n                    sepol6: PolicyObject::None,\n                    sepol7: PolicyObject::None,\n                });\n            }\n        }\n        Ok(result)\n    }\n}\n\nimpl<'a> TryFrom<&'a Attr<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(perm: &'a Attr<'a>) -> Result<Self> {\n        let result = vec![AtomicStatement {\n            cmd: CMD_ATTR,\n            subcmd: 0,\n            sepol1: perm.name.try_into()?,\n            sepol2: PolicyObject::None,\n            sepol3: PolicyObject::None,\n            sepol4: PolicyObject::None,\n            sepol5: PolicyObject::None,\n            sepol6: PolicyObject::None,\n            sepol7: PolicyObject::None,\n        }];\n        Ok(result)\n    }\n}\n\nimpl<'a> TryFrom<&'a TypeTransition<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(perm: &'a TypeTransition<'a>) -> Result<Self> {\n        let mut result = vec![];\n        let obj = match perm.object_name {\n            Some(obj) => obj.try_into()?,\n            None => PolicyObject::None,\n        };\n        result.push(AtomicStatement {\n            cmd: CMD_TYPE_TRANSITION,\n            subcmd: 0,\n            sepol1: perm.source.try_into()?,\n            sepol2: perm.target.try_into()?,\n            sepol3: perm.class.try_into()?,\n            sepol4: perm.default_type.try_into()?,\n            sepol5: obj,\n            sepol6: PolicyObject::None,\n            sepol7: PolicyObject::None,\n        });\n        Ok(result)\n    }\n}\n\nimpl<'a> TryFrom<&'a TypeChange<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(perm: &'a TypeChange<'a>) -> Result<Self> {\n        let mut result = vec![];\n        let subcmd = match perm.op {\n            \"type_change\" => 1,\n            \"type_member\" => 2,\n            _ => 0,\n        };\n        result.push(AtomicStatement {\n            cmd: CMD_TYPE_CHANGE,\n            subcmd,\n            sepol1: perm.source.try_into()?,\n            sepol2: perm.target.try_into()?,\n            sepol3: perm.class.try_into()?,\n            sepol4: perm.default_type.try_into()?,\n            sepol5: PolicyObject::None,\n            sepol6: PolicyObject::None,\n            sepol7: PolicyObject::None,\n        });\n        Ok(result)\n    }\n}\n\nimpl<'a> TryFrom<&'a GenFsCon<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(perm: &'a GenFsCon<'a>) -> Result<Self> {\n        let result = vec![AtomicStatement {\n            cmd: CMD_GENFSCON,\n            subcmd: 0,\n            sepol1: perm.fs_name.try_into()?,\n            sepol2: perm.partial_path.try_into()?,\n            sepol3: perm.fs_context.try_into()?,\n            sepol4: PolicyObject::None,\n            sepol5: PolicyObject::None,\n            sepol6: PolicyObject::None,\n            sepol7: PolicyObject::None,\n        }];\n        Ok(result)\n    }\n}\n\nimpl<'a> TryFrom<&'a PolicyStatement<'a>> for Vec<AtomicStatement> {\n    type Error = anyhow::Error;\n    fn try_from(value: &'a PolicyStatement) -> Result<Self> {\n        match value {\n            PolicyStatement::NormalPerm(perm) => perm.try_into(),\n            PolicyStatement::XPerm(perm) => perm.try_into(),\n            PolicyStatement::TypeState(perm) => perm.try_into(),\n            PolicyStatement::Type(perm) => perm.try_into(),\n            PolicyStatement::TypeAttr(perm) => perm.try_into(),\n            PolicyStatement::Attr(perm) => perm.try_into(),\n            PolicyStatement::TypeTransition(perm) => perm.try_into(),\n            PolicyStatement::TypeChange(perm) => perm.try_into(),\n            PolicyStatement::GenFsCon(perm) => perm.try_into(),\n        }\n    }\n}\n\n////////////////////////////////////////////////////////////////\n///  for C FFI to call kernel interface\n///////////////////////////////////////////////////////////////\n\n#[derive(Debug)]\n#[repr(C)]\nstruct FfiPolicy {\n    cmd: u32,\n    subcmd: u32,\n    sepol1: *const ffi::c_char,\n    sepol2: *const ffi::c_char,\n    sepol3: *const ffi::c_char,\n    sepol4: *const ffi::c_char,\n    sepol5: *const ffi::c_char,\n    sepol6: *const ffi::c_char,\n    sepol7: *const ffi::c_char,\n}\n\nfn to_c_ptr(pol: &PolicyObject) -> *const ffi::c_char {\n    match pol {\n        PolicyObject::None | PolicyObject::All => std::ptr::null(),\n        PolicyObject::One(s) => s.as_ptr().cast::<ffi::c_char>(),\n    }\n}\n\nimpl From<AtomicStatement> for FfiPolicy {\n    fn from(policy: AtomicStatement) -> FfiPolicy {\n        FfiPolicy {\n            cmd: policy.cmd,\n            subcmd: policy.subcmd,\n            sepol1: to_c_ptr(&policy.sepol1),\n            sepol2: to_c_ptr(&policy.sepol2),\n            sepol3: to_c_ptr(&policy.sepol3),\n            sepol4: to_c_ptr(&policy.sepol4),\n            sepol5: to_c_ptr(&policy.sepol5),\n            sepol6: to_c_ptr(&policy.sepol6),\n            sepol7: to_c_ptr(&policy.sepol7),\n        }\n    }\n}\n\npub fn check_rule(policy: &str) -> Result<()> {\n    let path = Path::new(policy);\n    let policy = if path.exists() {\n        std::fs::read_to_string(path)?\n    } else {\n        policy.to_string()\n    };\n    parse_sepolicy(policy.trim(), true)?;\n    Ok(())\n}\n"
  },
  {
    "path": "apd/src/supercall.rs",
    "content": "use std::{\n    ffi::{CStr, CString},\n    fmt::Write,\n    fs::File,\n    io::{self, Read},\n    process,\n    process::exit,\n    ptr,\n    sync::{Arc, Mutex},\n};\n\nuse errno::errno;\nuse libc::{EINVAL, c_int, c_long, c_void, execv, fork, pid_t, setenv, syscall, uid_t, wait};\nuse log::{error, info, warn};\n\nuse crate::package::{read_ap_package_config, synchronize_package_uid};\n\nconst MAJOR: c_long = 0;\nconst MINOR: c_long = 11;\nconst PATCH: c_long = 1;\n\nconst KSTORAGE_EXCLUDE_LIST_GROUP: i32 = 1;\n\nconst __NR_SUPERCALL: c_long = 45;\nconst SUPERCALL_KLOG: c_long = 0x1004;\nconst SUPERCALL_KERNELPATCH_VER: c_long = 0x1008;\nconst SUPERCALL_KERNEL_VER: c_long = 0x1009;\nconst SUPERCALL_SU: c_long = 0x1010;\nconst SUPERCALL_KSTORAGE_WRITE: c_long = 0x1041;\nconst SUPERCALL_SU_GRANT_UID: c_long = 0x1100;\nconst SUPERCALL_SU_REVOKE_UID: c_long = 0x1101;\nconst SUPERCALL_SU_NUMS: c_long = 0x1102;\nconst SUPERCALL_SU_LIST: c_long = 0x1103;\nconst SUPERCALL_SU_RESET_PATH: c_long = 0x1111;\nconst SUPERCALL_SU_GET_SAFEMODE: c_long = 0x1112;\n\nconst SUPERCALL_SCONTEXT_LEN: usize = 0x60;\n\n#[repr(C)]\nstruct SuProfile {\n    uid: i32,\n    to_uid: i32,\n    scontext: [u8; SUPERCALL_SCONTEXT_LEN],\n}\n\nfn ver_and_cmd(cmd: c_long) -> c_long {\n    let version_code: u32 = ((MAJOR << 16) + (MINOR << 8) + PATCH).try_into().unwrap();\n    ((version_code as c_long) << 32) | (0x1158 << 16) | (cmd & 0xFFFF)\n}\n\nfn sc_su_revoke_uid(key: &CStr, uid: uid_t) -> c_long {\n    if key.to_bytes().is_empty() {\n        return (-EINVAL).into();\n    }\n    unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key.as_ptr(),\n            ver_and_cmd(SUPERCALL_SU_REVOKE_UID),\n            uid,\n        ) as c_long\n    }\n}\n\nfn sc_su_grant_uid(key: &CStr, profile: &SuProfile) -> c_long {\n    if key.to_bytes().is_empty() {\n        return (-EINVAL).into();\n    }\n    unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key.as_ptr(),\n            ver_and_cmd(SUPERCALL_SU_GRANT_UID),\n            profile,\n        ) as c_long\n    }\n}\n\nfn sc_kstorage_write(\n    key: &CStr,\n    gid: i32,\n    did: i64,\n    data: *mut c_void,\n    offset: i32,\n    dlen: i32,\n) -> c_long {\n    if key.to_bytes().is_empty() {\n        return (-EINVAL).into();\n    }\n    unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key.as_ptr(),\n            ver_and_cmd(SUPERCALL_KSTORAGE_WRITE),\n            gid as c_long,\n            did as c_long,\n            data,\n            (((offset as i64) << 32) | (dlen as i64)) as c_long,\n        ) as c_long\n    }\n}\n\nfn sc_set_ap_mod_exclude(key: &CStr, uid: i64, exclude: i32) -> c_long {\n    sc_kstorage_write(\n        key,\n        KSTORAGE_EXCLUDE_LIST_GROUP,\n        uid,\n        &exclude as *const i32 as *mut c_void,\n        0,\n        size_of::<i32>() as i32,\n    )\n}\n\npub fn sc_su_get_safemode(key: &CStr) -> c_long {\n    if key.to_bytes().is_empty() {\n        warn!(\"[sc_su_get_safemode] null superkey, tell apd we are not in safemode!\");\n        return 0;\n    }\n\n    let key_ptr = key.as_ptr();\n    if key_ptr.is_null() {\n        warn!(\"[sc_su_get_safemode] superkey pointer is null!\");\n        return 0;\n    }\n\n    unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key_ptr,\n            ver_and_cmd(SUPERCALL_SU_GET_SAFEMODE),\n        ) as c_long\n    }\n}\n\nfn sc_su(key: &CStr, profile: &SuProfile) -> c_long {\n    if key.to_bytes().is_empty() {\n        return (-EINVAL).into();\n    }\n    unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key.as_ptr(),\n            ver_and_cmd(SUPERCALL_SU),\n            profile,\n        ) as c_long\n    }\n}\n\nfn sc_su_reset_path(key: &CStr, path: &CStr) -> c_long {\n    if key.to_bytes().is_empty() || path.to_bytes().is_empty() {\n        return (-EINVAL).into();\n    }\n    unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key.as_ptr(),\n            ver_and_cmd(SUPERCALL_SU_RESET_PATH),\n            path.as_ptr(),\n        ) as c_long\n    }\n}\n\nfn sc_kp_ver(key: &CStr) -> Result<u32, i32> {\n    if key.to_bytes().is_empty() {\n        return Err(-EINVAL);\n    }\n    let ret = unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key.as_ptr(),\n            ver_and_cmd(SUPERCALL_KERNELPATCH_VER),\n        )\n    };\n    Ok(ret as u32)\n}\n\nfn sc_k_ver(key: &CStr) -> Result<u32, i32> {\n    if key.to_bytes().is_empty() {\n        return Err(-EINVAL);\n    }\n    let ret = unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key.as_ptr(),\n            ver_and_cmd(SUPERCALL_KERNEL_VER),\n        )\n    };\n    Ok(ret as u32)\n}\n\nfn sc_klog(key: &CStr, msg: &CStr) -> c_long {\n    if key.to_bytes().is_empty() || msg.to_bytes().is_empty() {\n        return (-EINVAL).into();\n    }\n    unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key.as_ptr(),\n            ver_and_cmd(SUPERCALL_KLOG),\n            msg.as_ptr(),\n        ) as c_long\n    }\n}\n\nfn sc_su_uid_nums(key: &CStr) -> c_long {\n    if key.to_bytes().is_empty() {\n        return (-EINVAL).into();\n    }\n    unsafe { syscall(__NR_SUPERCALL, key.as_ptr(), ver_and_cmd(SUPERCALL_SU_NUMS)) as c_long }\n}\n\nfn sc_su_allow_uids(key: &CStr, buf: &mut [uid_t]) -> c_long {\n    if key.to_bytes().is_empty() {\n        return (-EINVAL).into();\n    }\n    if buf.is_empty() {\n        return (-EINVAL).into();\n    }\n    unsafe {\n        syscall(\n            __NR_SUPERCALL,\n            key.as_ptr(),\n            ver_and_cmd(SUPERCALL_SU_LIST),\n            buf.as_mut_ptr(),\n            buf.len() as i32,\n        ) as c_long\n    }\n}\n\nfn read_file_to_string(path: &str) -> io::Result<String> {\n    let mut file = File::open(path)?;\n    let mut content = String::new();\n    file.read_to_string(&mut content)?;\n    Ok(content)\n}\n\nfn convert_string_to_u8_array(s: &str) -> [u8; SUPERCALL_SCONTEXT_LEN] {\n    let mut u8_array = [0u8; SUPERCALL_SCONTEXT_LEN];\n    let bytes = s.as_bytes();\n    let len = usize::min(SUPERCALL_SCONTEXT_LEN, bytes.len());\n    u8_array[..len].copy_from_slice(&bytes[..len]);\n    u8_array\n}\n\nfn convert_superkey(s: &Option<String>) -> Option<CString> {\n    s.as_ref().and_then(|s| CString::new(s.clone()).ok())\n}\n\npub fn refresh_ap_package_list(skey: &CStr, mutex: &Arc<Mutex<()>>) {\n    let _lock = mutex.lock().unwrap();\n\n    let num = sc_su_uid_nums(skey);\n    if num < 0 {\n        error!(\"[refresh_su_list] Error getting number of UIDs: {}\", num);\n        return;\n    }\n    let num = num as usize;\n    let mut uids = vec![0 as uid_t; num];\n    let n = sc_su_allow_uids(skey, &mut uids);\n    if n < 0 {\n        error!(\"[refresh_su_list] Error getting su list\");\n        return;\n    }\n    for uid in &uids {\n        if *uid == 0 || *uid == 2000 {\n            warn!(\n                \"[refresh_ap_package_list] Skip revoking critical uid: {}\",\n                uid\n            );\n            continue;\n        }\n        info!(\n            \"[refresh_ap_package_list] Revoking {} root permission...\",\n            uid\n        );\n        let rc = sc_su_revoke_uid(skey, *uid);\n        if rc != 0 {\n            error!(\"[refresh_ap_package_list] Error revoking UID: {}\", rc);\n        }\n    }\n\n    if let Err(e) = synchronize_package_uid() {\n        error!(\"Failed to synchronize package UIDs: {}\", e);\n    }\n\n    let package_configs = read_ap_package_config();\n    for config in package_configs {\n        if config.allow == 1 && config.exclude == 0 {\n            let profile = SuProfile {\n                uid: config.uid,\n                to_uid: config.to_uid,\n                scontext: convert_string_to_u8_array(&config.sctx),\n            };\n            let result = sc_su_grant_uid(skey, &profile);\n            info!(\n                \"[refresh_ap_package_list] Loading {}: result = {}\",\n                config.pkg, result\n            );\n        }\n        if config.allow == 0 && config.exclude == 1 {\n            let result = sc_set_ap_mod_exclude(skey, config.uid as i64, 1);\n            info!(\n                \"[refresh_ap_package_list] Loading exclude {}: result = {}\",\n                config.pkg, result\n            );\n        }\n    }\n}\n\npub fn privilege_apd_profile(superkey: &Option<String>) {\n    let key = convert_superkey(superkey);\n\n    let all_allow_ctx = \"u:r:magisk:s0\";\n    let profile = SuProfile {\n        uid: process::id().try_into().expect(\"PID conversion failed\"),\n        to_uid: 0,\n        scontext: convert_string_to_u8_array(all_allow_ctx),\n    };\n    if let Some(ref key) = key {\n        let result = sc_su(key, &profile);\n        info!(\"[privilege_apd_profile] result = {}\", result);\n    }\n}\n\npub fn init_load_package_uid_config(superkey: &Option<String>) {\n    let package_configs = read_ap_package_config();\n    let key = convert_superkey(superkey);\n\n    for config in package_configs {\n        if config.allow == 1 && config.exclude == 0 {\n            match key {\n                Some(ref key) => {\n                    let profile = SuProfile {\n                        uid: config.uid,\n                        to_uid: config.to_uid,\n                        scontext: convert_string_to_u8_array(&config.sctx),\n                    };\n                    let result = sc_su_grant_uid(key, &profile);\n                    info!(\"Processed {}: result = {}\", config.pkg, result);\n                }\n                _ => {\n                    warn!(\"Superkey is None, skipping config: {}\", config.pkg);\n                }\n            }\n        }\n        if config.allow == 0 && config.exclude == 1 {\n            match key {\n                Some(ref key) => {\n                    let result = sc_set_ap_mod_exclude(key, config.uid as i64, 1);\n                    info!(\"Processed exclude {}: result = {}\", config.pkg, result);\n                }\n                _ => {\n                    warn!(\"Superkey is None, skipping config: {}\", config.pkg);\n                }\n            }\n        }\n    }\n}\n\npub fn init_load_su_path(superkey: &Option<String>) {\n    let su_path_file = \"/data/adb/ap/su_path\";\n\n    match read_file_to_string(su_path_file) {\n        Ok(su_path) => {\n            let superkey_cstr = convert_superkey(superkey);\n\n            match superkey_cstr {\n                Some(superkey_cstr) => match CString::new(su_path.trim()) {\n                    Ok(su_path_cstr) => {\n                        let result = sc_su_reset_path(&superkey_cstr, &su_path_cstr);\n                        if result == 0 {\n                            info!(\"suPath load successfully\");\n                        } else {\n                            warn!(\"Failed to load su path, error code: {}\", result);\n                        }\n                    }\n                    Err(e) => {\n                        warn!(\"Failed to convert su_path: {}\", e);\n                    }\n                },\n                _ => {\n                    warn!(\"Superkey is None, skipping...\");\n                }\n            }\n        }\n        Err(e) => {\n            warn!(\"Failed to read su_path file: {}\", e);\n        }\n    }\n}\n\nfn set_env_var(key: &str, value: &str) {\n    let key_c = CString::new(key).expect(\"CString::new failed\");\n    let value_c = CString::new(value).expect(\"CString::new failed\");\n    unsafe {\n        setenv(key_c.as_ptr(), value_c.as_ptr(), 1);\n    }\n}\n\nfn log_kernel(key: &CStr, _fmt: &str, args: std::fmt::Arguments) -> c_long {\n    let mut buf = String::with_capacity(1024);\n    write!(&mut buf, \"{}\", args).expect(\"Error formatting string\");\n\n    let c_buf = CString::new(buf).expect(\"CString::new failed\");\n    sc_klog(key, &c_buf)\n}\n\n#[macro_export]\nmacro_rules! log_kernel {\n    ($key:expr_2021, $fmt:expr_2021, $($arg:tt)*) => (\n        log_kernel($key, $fmt, std::format_args!($fmt, $($arg)*))\n    )\n}\n\npub fn fork_for_result(exec: &str, argv: &[&str], key: &Option<String>) {\n    let mut cmd = String::new();\n    for arg in argv {\n        cmd.push_str(arg);\n        cmd.push(' ');\n    }\n\n    let superkey_cstr = convert_superkey(key);\n\n    match superkey_cstr {\n        Some(superkey_cstr) => {\n            unsafe {\n                let pid: pid_t = fork();\n                if pid < 0 {\n                    log_kernel!(\n                        &superkey_cstr,\n                        \"{} fork {} error: {}\\n\",\n                        libc::getpid(),\n                        exec,\n                        -1\n                    );\n                } else if pid == 0 {\n                    set_env_var(\"KERNELPATCH\", \"true\");\n                    let kpver = format!(\"{:x}\", sc_kp_ver(&superkey_cstr).unwrap_or(0));\n                    set_env_var(\"KERNELPATCH_VERSION\", kpver.as_str());\n                    let kver = format!(\"{:x}\", sc_k_ver(&superkey_cstr).unwrap_or(0));\n                    set_env_var(\"KERNEL_VERSION\", kver.as_str());\n\n                    let c_exec = CString::new(exec).expect(\"CString::new failed\");\n                    let c_argv: Vec<CString> =\n                        argv.iter().map(|&arg| CString::new(arg).unwrap()).collect();\n                    let mut c_argv_ptrs: Vec<*const libc::c_char> =\n                        c_argv.iter().map(|arg| arg.as_ptr()).collect();\n                    c_argv_ptrs.push(ptr::null());\n\n                    execv(c_exec.as_ptr(), c_argv_ptrs.as_ptr());\n\n                    log_kernel!(\n                        &superkey_cstr,\n                        \"{} exec {} error: {}\\n\",\n                        libc::getpid(),\n                        cmd,\n                        CStr::from_ptr(libc::strerror(errno().0))\n                            .to_string_lossy()\n                            .into_owned()\n                    );\n                    exit(1); // execv only returns on error\n                } else {\n                    let mut status: c_int = 0;\n                    wait(&mut status);\n                    log_kernel!(\n                        &superkey_cstr,\n                        \"{} wait {} status: 0x{}\\n\",\n                        libc::getpid(),\n                        cmd,\n                        status\n                    );\n                }\n            }\n        }\n        _ => {\n            warn!(\"[fork_for_result] SuperKey convert failed!\");\n        }\n    }\n}\n"
  },
  {
    "path": "apd/src/utils.rs",
    "content": "#[allow(unused_imports)]\nuse std::fs::{Permissions, set_permissions};\n#[cfg(unix)]\nuse std::os::unix::prelude::PermissionsExt;\nuse std::{\n    ffi::CString,\n    fs::{File, OpenOptions, create_dir_all, metadata},\n    io::{ErrorKind::AlreadyExists, Write},\n    path::Path,\n    process::{Command, Stdio},\n};\n\nuse anyhow::{Context, Error, Ok, Result, bail};\nuse log::{info, warn};\n\nuse crate::{defs, supercall::sc_su_get_safemode};\n\npub fn ensure_file_exists<T: AsRef<Path>>(file: T) -> Result<()> {\n    match File::options().write(true).create_new(true).open(&file) {\n        Result::Ok(_) => Ok(()),\n        Err(err) => {\n            if err.kind() == AlreadyExists && file.as_ref().is_file() {\n                Ok(())\n            } else {\n                Err(Error::from(err))\n                    .with_context(|| format!(\"{} is not a regular file\", file.as_ref().display()))\n            }\n        }\n    }\n}\n\npub fn ensure_dir_exists<T: AsRef<Path>>(dir: T) -> Result<()> {\n    let result = create_dir_all(&dir).map_err(Error::from);\n    if dir.as_ref().is_dir() {\n        result\n    } else if result.is_ok() {\n        bail!(\"{} is not a regular directory\", dir.as_ref().display())\n    } else {\n        result\n    }\n}\n\n// todo: ensure\npub fn ensure_binary<T: AsRef<Path>>(path: T) -> Result<()> {\n    set_permissions(&path, Permissions::from_mode(0o755))?;\n    Ok(())\n}\n\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\npub fn getprop(prop: &str) -> Option<String> {\n    android_properties::getprop(prop).value()\n}\n\n#[cfg(not(any(target_os = \"linux\", target_os = \"android\")))]\npub fn getprop(_prop: &str) -> Option<String> {\n    unimplemented!()\n}\npub fn run_command(\n    command: &str,\n    args: &[&str],\n    stdout: Option<Stdio>,\n) -> Result<std::process::Child> {\n    let mut command_builder = Command::new(command);\n    command_builder.args(args);\n    if let Some(out) = stdout {\n        command_builder.stdout(out);\n    }\n    let child = command_builder.spawn()?;\n    Ok(child)\n}\npub fn is_safe_mode(superkey: Option<String>) -> bool {\n    let safemode = getprop(\"persist.sys.safemode\")\n        .filter(|prop| prop == \"1\")\n        .is_some()\n        || getprop(\"ro.sys.safemode\")\n            .filter(|prop| prop == \"1\")\n            .is_some();\n    info!(\"safemode: {}\", safemode);\n    if safemode {\n        return true;\n    }\n    let safemode = superkey\n        .as_ref()\n        .and_then(|key_str| CString::new(key_str.as_str()).ok())\n        .map_or_else(\n            || {\n                warn!(\"[is_safe_mode] No valid superkey provided, assuming safemode as false.\");\n                false\n            },\n            |cstr| sc_su_get_safemode(&cstr) == 1,\n        );\n    info!(\"kernel_safemode: {}\", safemode);\n    safemode\n}\n\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\npub fn switch_mnt_ns(pid: i32) -> Result<()> {\n    use std::os::fd::AsRawFd;\n\n    use anyhow::ensure;\n    let path = format!(\"/proc/{pid}/ns/mnt\");\n    let fd = File::open(path)?;\n    let current_dir = std::env::current_dir();\n    let ret = unsafe { libc::setns(fd.as_raw_fd(), libc::CLONE_NEWNS) };\n    if let Result::Ok(current_dir) = current_dir {\n        let _ = std::env::set_current_dir(current_dir);\n    }\n    ensure!(ret == 0, \"switch mnt ns failed\");\n    Ok(())\n}\n\nfn switch_cgroup(grp: &str, pid: u32) {\n    let path = Path::new(grp).join(\"cgroup.procs\");\n    if !path.exists() {\n        return;\n    }\n\n    let fp = OpenOptions::new().append(true).open(path);\n    if let Result::Ok(mut fp) = fp {\n        let _ = write!(fp, \"{pid}\");\n    }\n}\n\npub fn switch_cgroups() {\n    let pid = std::process::id();\n    switch_cgroup(\"/acct\", pid);\n    switch_cgroup(\"/dev/cg2_bpf\", pid);\n    switch_cgroup(\"/sys/fs/cgroup\", pid);\n\n    if getprop(\"ro.config.per_app_memcg\")\n        .filter(|prop| prop == \"false\")\n        .is_none()\n    {\n        switch_cgroup(\"/dev/memcg/apps\", pid);\n    }\n}\n\n#[cfg(any(target_os = \"linux\", target_os = \"android\"))]\npub fn umask(mask: u32) {\n    unsafe { libc::umask(mask) };\n}\n\n#[cfg(not(any(target_os = \"linux\", target_os = \"android\")))]\npub fn umask(_mask: u32) {\n    unimplemented!(\"umask is not supported on this platform\")\n}\n\npub fn has_magisk() -> bool {\n    which::which(\"magisk\").is_ok()\n}\npub fn get_tmp_path() -> &'static str {\n    if metadata(defs::TEMP_DIR_LEGACY).is_ok() {\n        return defs::TEMP_DIR_LEGACY;\n    }\n    if metadata(defs::TEMP_DIR).is_ok() {\n        return defs::TEMP_DIR;\n    }\n    \"\"\n}\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n/release/\n"
  },
  {
    "path": "app/build.gradle.kts",
    "content": "@file:Suppress(\"UnstableApiUsage\")\n\nimport com.android.build.gradle.tasks.PackageAndroidArtifact\nimport org.jetbrains.kotlin.gradle.dsl.JvmTarget\nimport java.net.URI\n\nplugins {\n    alias(libs.plugins.agp.app)\n    alias(libs.plugins.kotlin.compose.compiler)\n    alias(libs.plugins.ksp)\n    alias(libs.plugins.lsplugin.apksign)\n    alias(libs.plugins.lsplugin.resopt)\n    id(\"kotlin-parcelize\")\n}\n\nval androidCompileSdkVersion: Int by rootProject.extra\nval androidCompileNdkVersion: String by rootProject.extra\nval androidBuildToolsVersion: String by rootProject.extra\nval androidMinSdkVersion: Int by rootProject.extra\nval androidTargetSdkVersion: Int by rootProject.extra\nval androidSourceCompatibility: JavaVersion by rootProject.extra\nval androidTargetCompatibility: JavaVersion by rootProject.extra\nval managerVersionCode: Int by rootProject.extra\nval managerVersionName: String by rootProject.extra\nval branchName: String by rootProject.extra\nval kernelPatchVersion: String by rootProject.extra\n\napksign {\n    storeFileProperty = \"KEYSTORE_FILE\"\n    storePasswordProperty = \"KEYSTORE_PASSWORD\"\n    keyAliasProperty = \"KEY_ALIAS\"\n    keyPasswordProperty = \"KEY_PASSWORD\"\n}\n\nval ccache = System.getenv(\"PATH\")?.split(File.pathSeparator)\n    ?.map { File(it, \"ccache\") }?.firstOrNull { it.exists() }?.absolutePath\n\nval baseFlags = listOf(\n    \"-Wall\", \"-Qunused-arguments\", \"-fno-rtti\", \"-fvisibility=hidden\",\n    \"-fvisibility-inlines-hidden\", \"-fno-exceptions\", \"-fno-stack-protector\",\n    \"-fomit-frame-pointer\", \"-Wno-builtin-macro-redefined\", \"-Wno-unused-value\",\n    \"-D__FILE__=__FILE_NAME__\",\n    \"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON\", \"-Wno-unused\", \"-Wno-unused-parameter\",\n    \"-Wno-unused-command-line-argument\", \"-Wno-incompatible-function-pointer-types\",\n    \"-U_FORTIFY_SOURCE\", \"-D_FORTIFY_SOURCE=0\"\n)\n\nval baseArgs = mutableListOf(\n    \"-DANDROID_STL=none\", \"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON\",\n    \"-DCMAKE_CXX_STANDARD=23\", \"-DCMAKE_C_STANDARD=23\",\n    \"-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON\", \"-DCMAKE_VISIBILITY_INLINES_HIDDEN=ON\",\n    \"-DCMAKE_CXX_VISIBILITY_PRESET=hidden\", \"-DCMAKE_C_VISIBILITY_PRESET=hidden\"\n).apply { if (ccache != null) add(\"-DANDROID_CCACHE=$ccache\") }\n\nandroid {\n    namespace = \"me.bmax.apatch\"\n\n    buildTypes {\n        debug {\n            isDebuggable = true\n            isMinifyEnabled = false\n            isShrinkResources = false\n            proguardFiles(\n                getDefaultProguardFile(\"proguard-android-optimize.txt\"),\n                \"proguard-rules.pro\"\n            )\n            externalNativeBuild {\n                cmake {\n                    arguments += listOf(\"-DCMAKE_CXX_FLAGS_DEBUG=-Og\", \"-DCMAKE_C_FLAGS_DEBUG=-Og\")\n                }\n            }\n        }\n        release {\n            isMinifyEnabled = true\n            isShrinkResources = true\n            isDebuggable = false\n            multiDexEnabled = true\n            vcsInfo.include = false\n            proguardFiles(\n                getDefaultProguardFile(\"proguard-android-optimize.txt\"),\n                \"proguard-rules.pro\"\n            )\n            externalNativeBuild {\n                cmake {\n                    val relFlags = listOf(\n                        \"-flto\", \"-ffunction-sections\", \"-fdata-sections\", \"-Wl,--gc-sections\",\n                        \"-fno-unwind-tables\", \"-fno-asynchronous-unwind-tables\", \"-Wl,--exclude-libs,ALL\",\n                        \"-Ofast\", \"-fmerge-all-constants\", \"-flto=full\", \"-ffat-lto-objects\",\n                        \"-fno-semantic-interposition\", \"-fno-threadsafe-statics\"\n                    )\n                    cppFlags += relFlags\n                    cFlags += relFlags\n                    arguments += listOf(\"-DCMAKE_BUILD_TYPE=Release\", \"-DCMAKE_CXX_FLAGS_RELEASE=-O3 -DNDEBUG\", \"-DCMAKE_C_FLAGS_RELEASE=-O3 -DNDEBUG\")\n                }\n            }\n        }\n    }\n\n    dependenciesInfo.includeInApk = false\n\n    buildFeatures {\n        aidl = true\n        buildConfig = true\n        compose = true\n        prefab = true\n    }\n\n    defaultConfig {\n        minSdk = androidMinSdkVersion\n        targetSdk = androidTargetSdkVersion\n        versionCode = managerVersionCode\n        versionName = managerVersionName\n        ndk.abiFilters.addAll(arrayOf(\"arm64-v8a\"))\n        externalNativeBuild {\n            cmake {\n                cppFlags += baseFlags + \"-std=c++2b\"\n                cFlags += baseFlags + \"-std=c2x\"\n                arguments += baseArgs\n                abiFilters(\"arm64-v8a\")\n            }\n        }\n        buildConfigField(\"String\", \"buildKPV\", \"\\\"$kernelPatchVersion\\\"\")\n        base.archivesName = \"APatch_${managerVersionCode}_${managerVersionName}_${branchName}\"\n    }\n\n    compileOptions {\n        sourceCompatibility = JavaVersion.VERSION_21\n        targetCompatibility = JavaVersion.VERSION_21\n    }\n\n    packaging {\n        jniLibs {\n            useLegacyPackaging = true\n        }\n        resources {\n            excludes += \"**\"\n            merges += \"META-INF/com/google/android/**\"\n        }\n    }\n\n    externalNativeBuild {\n        cmake {\n            version = \"3.28.0+\"\n            path(\"src/main/cpp/CMakeLists.txt\")\n        }\n    }\n\n    androidResources {\n        generateLocaleConfig = true\n    }\n\n    compileSdk = androidCompileSdkVersion\n    ndkVersion = androidCompileNdkVersion\n    buildToolsVersion = androidBuildToolsVersion\n\n    lint {\n        abortOnError = false\n        checkReleaseBuilds = false\n    }\n\n    android.sourceSets.named(\"main\") {\n        kotlin.directories += \"build/generated/ksp/$name/kotlin\"\n        jniLibs.directories += \"libs\"\n    }\n}\n\n// https://stackoverflow.com/a/77745844\ntasks.withType<PackageAndroidArtifact> {\n    doFirst { appMetadata.asFile.orNull?.writeText(\"\") }\n}\n\njava {\n    toolchain {\n        languageVersion = JavaLanguageVersion.of(21)\n    }\n}\n\nkotlin {\n    jvmToolchain(21)\n    compilerOptions {\n        jvmTarget = JvmTarget.JVM_21\n    }\n}\n\nfun registerDownloadTask(\n    taskName: String, srcUrl: String, destPath: String, project: Project\n) {\n    project.tasks.register(taskName) {\n        val destFile = File(destPath)\n\n        doLast {\n            if (!destFile.exists() || isFileUpdated(srcUrl, destFile)) {\n                println(\" - Downloading $srcUrl to ${destFile.absolutePath}\")\n                downloadFile(srcUrl, destFile)\n                println(\" - Download completed.\")\n            } else {\n                println(\" - File is up-to-date, skipping download.\")\n            }\n        }\n    }\n}\n\nfun isFileUpdated(url: String, localFile: File): Boolean {\n    val connection = URI.create(url).toURL().openConnection()\n    val remoteLastModified = connection.getHeaderFieldDate(\"Last-Modified\", 0L)\n    return remoteLastModified > localFile.lastModified()\n}\n\nfun downloadFile(url: String, destFile: File) {\n    URI.create(url).toURL().openStream().use { input ->\n        destFile.outputStream().use { output ->\n            input.copyTo(output)\n        }\n    }\n}\n\nregisterDownloadTask(\n    taskName = \"downloadKpimg\",\n    srcUrl = \"https://github.com/bmax121/KernelPatch/releases/download/$kernelPatchVersion/kpimg-android\",\n    destPath = \"${project.projectDir}/src/main/assets/kpimg\",\n    project = project\n)\n\nregisterDownloadTask(\n    taskName = \"downloadKptools\",\n    srcUrl = \"https://github.com/bmax121/KernelPatch/releases/download/$kernelPatchVersion/kptools-android\",\n    destPath = \"${project.projectDir}/libs/arm64-v8a/libkptools.so\",\n    project = project\n)\n\n// Compat kp version less than 0.10.7\n// TODO: Remove in future\nregisterDownloadTask(\n    taskName = \"downloadCompatKpatch\",\n    srcUrl = \"https://github.com/bmax121/KernelPatch/releases/download/0.10.7/kpatch-android\",\n    destPath = \"${project.projectDir}/libs/arm64-v8a/libkpatch.so\",\n    project = project\n)\n\ntasks.register<Copy>(\"mergeScripts\") {\n    into(\"${project.projectDir}/src/main/resources/META-INF/com/google/android\")\n    from(rootProject.file(\"${project.rootDir}/scripts/update_binary.sh\")) {\n        rename { \"update-binary\" }\n    }\n    from(rootProject.file(\"${project.rootDir}/scripts/update_script.sh\")) {\n        rename { \"updater-script\" }\n    }\n}\n\ntasks.getByName(\"preBuild\").dependsOn(\n    \"downloadKpimg\",\n    \"downloadKptools\",\n    \"downloadCompatKpatch\",\n    \"mergeScripts\",\n)\n\n// https://github.com/bbqsrc/cargo-ndk\n// cargo ndk -t arm64-v8a build --release\ntasks.register<Exec>(\"cargoBuild\") {\n    executable(\"cargo\")\n    args(\"ndk\", \"-t\", \"arm64-v8a\", \"build\", \"--release\")\n    workingDir(\"${project.rootDir}/apd\")\n}\n\ntasks.register<Copy>(\"buildApd\") {\n    dependsOn(\"cargoBuild\")\n    from(\"${project.rootDir}/apd/target/aarch64-linux-android/release/apd\")\n    into(\"${project.projectDir}/libs/arm64-v8a\")\n    rename(\"apd\", \"libapd.so\")\n}\n\ntasks.configureEach {\n    if (name == \"mergeDebugJniLibFolders\" || name == \"mergeReleaseJniLibFolders\") {\n        dependsOn(\"buildApd\")\n    }\n}\n\ntasks.register<Exec>(\"cargoClean\") {\n    executable(\"cargo\")\n    args(\"clean\")\n    workingDir(\"${project.rootDir}/apd\")\n}\n\ntasks.register<Delete>(\"apdClean\") {\n    dependsOn(\"cargoClean\")\n    delete(file(\"${project.projectDir}/libs/arm64-v8a/libapd.so\"))\n}\n\ntasks.clean {\n    dependsOn(\"apdClean\")\n}\n\nksp {\n    arg(\"compose-destinations.defaultTransitions\", \"none\")\n}\n\ndependencies {\n    implementation(libs.androidx.appcompat)\n    implementation(libs.androidx.activity.compose)\n    implementation(libs.androidx.core.splashscreen)\n    implementation(libs.androidx.webkit)\n\n    implementation(platform(libs.androidx.compose.bom))\n    implementation(libs.androidx.compose.material.icons.extended)\n    implementation(libs.androidx.compose.material3)\n    implementation(libs.androidx.compose.ui)\n    implementation(libs.androidx.compose.ui.tooling.preview)\n    implementation(libs.androidx.compose.runtime.livedata)\n\n    debugImplementation(libs.androidx.compose.ui.test.manifest)\n    debugImplementation(libs.androidx.compose.ui.tooling)\n\n    implementation(libs.androidx.lifecycle.runtime.compose)\n    implementation(libs.androidx.lifecycle.runtime.ktx)\n    implementation(libs.androidx.lifecycle.viewmodel.compose)\n\n    implementation(libs.compose.destinations.core)\n    ksp(libs.compose.destinations.ksp)\n\n    implementation(libs.com.github.topjohnwu.libsu.core)\n    implementation(libs.com.github.topjohnwu.libsu.service)\n    implementation(libs.com.github.topjohnwu.libsu.nio)\n    implementation(libs.com.github.topjohnwu.libsu.io)\n\n    implementation(libs.dev.rikka.rikkax.parcelablelist)\n\n    implementation(libs.io.coil.kt.coil.compose)\n\n    implementation(libs.kotlinx.coroutines.core)\n\n    implementation(libs.me.zhanghai.android.appiconloader.coil)\n\n    implementation(libs.sheet.compose.dialogs.core)\n    implementation(libs.sheet.compose.dialogs.list)\n    implementation(libs.sheet.compose.dialogs.input)\n\n    implementation(libs.markdown)\n\n    implementation(libs.ini4j)\n\n    compileOnly(libs.cxx)\n}\n"
  },
  {
    "path": "app/libs/arm64-v8a/.gitignore",
    "content": "libkptools.so\nlibapjni.so\nlibkpatch.so\nlibapd.so"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "-dontwarn org.bouncycastle.jsse.BCSSLParameters\n-dontwarn org.bouncycastle.jsse.BCSSLSocket\n-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider\n-dontwarn org.conscrypt.Conscrypt$Version\n-dontwarn org.conscrypt.Conscrypt\n-dontwarn org.conscrypt.ConscryptHostnameVerifier\n-dontwarn org.openjsse.javax.net.ssl.SSLParameters\n-dontwarn org.openjsse.javax.net.ssl.SSLSocket\n-dontwarn org.openjsse.net.ssl.OpenJSSE\n-dontwarn java.beans.Introspector\n-dontwarn java.beans.VetoableChangeListener\n-dontwarn java.beans.VetoableChangeSupport\n-dontwarn java.beans.BeanInfo\n-dontwarn java.beans.IntrospectionException\n-dontwarn java.beans.PropertyDescriptor\n\n# Keep ini4j Service Provider Interface\n-keep,allowobfuscation,allowoptimization class org.ini4j.spi.** { *; }\n\n# Kotlin\n-assumenosideeffects class kotlin.jvm.internal.Intrinsics {\n    public static void check*(...);\n    public static void throw*(...);\n}\n\n-repackageclasses\n-allowaccessmodification\n-overloadaggressively\n-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission\n        android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"\n        android:maxSdkVersion=\"29\" />\n    <uses-permission\n        android:name=\"android.permission.READ_EXTERNAL_STORAGE\"\n        android:maxSdkVersion=\"32\" />\n    <uses-permission\n        android:name=\"android.permission.QUERY_ALL_PACKAGES\"\n        tools:ignore=\"QueryAllPackagesPermission\" />\n\n    <application\n        android:name=\".APApplication\"\n        android:allowBackup=\"true\"\n        android:dataExtractionRules=\"@xml/data_extraction_rules\"\n        android:enableOnBackInvokedCallback=\"true\"\n        android:fullBackupContent=\"@xml/backup_rules\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"APatch\"\n        android:networkSecurityConfig=\"@xml/network_security_config\"\n        android:requestLegacyExternalStorage=\"true\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/Theme.APatch\"\n        android:usesCleartextTraffic=\"true\"\n        tools:targetApi=\"34\">\n\n        <activity\n            android:name=\".ui.MainActivity\"\n            android:exported=\"true\"\n            android:theme=\"@style/Theme.Splash\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\".ui.WebUIActivity\"\n            android:autoRemoveFromRecents=\"true\"\n            android:documentLaunchMode=\"intoExisting\"\n            android:exported=\"false\"\n            android:theme=\"@style/Theme.APatch.WebUI\" />\n\n        <activity\n            android:name=\".ui.CrashHandleActivity\"\n            android:exported=\"false\" />\n\n        <provider\n            android:name=\"androidx.core.content.FileProvider\"\n            android:authorities=\"${applicationId}.fileprovider\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/file_paths\" />\n        </provider>\n\n        <service\n            android:name=\"androidx.appcompat.app.AppLocalesMetadataHolderService\"\n            android:enabled=\"false\"\n            android:exported=\"false\">\n            <meta-data\n                android:name=\"autoStoreLocales\"\n                android:value=\"true\" />\n        </service>\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/aidl/me/bmax/apatch/IAPRootService.aidl",
    "content": "// IAPRootService.aidl\npackage me.bmax.apatch;\n\nimport android.content.pm.PackageInfo;\nimport rikka.parcelablelist.ParcelableListSlice;\n\ninterface IAPRootService {\n    ParcelableListSlice<PackageInfo> getPackages(int flags);\n}"
  },
  {
    "path": "app/src/main/assets/.gitignore",
    "content": "kpimg\n*.kpm"
  },
  {
    "path": "app/src/main/assets/InstallAP.sh",
    "content": "#!/bin/sh\n# By SakuraKyuo\n\nOUTFD=/proc/self/fd/$2\n\nfunction ui_print() {\n  echo -e \"ui_print $1\\nui_print\" >> $OUTFD\n}\n\nfunction ui_printfile() {\n  while IFS='' read -r line || $BB [[ -n \"$line\" ]]; do\n    ui_print \"$line\";\n  done < $1;\n}\n\nfunction kernelFlagsErr(){\n\tui_print \"- Installation has Aborted!\"\n\tui_print \"- APatch requires CONFIG_KALLSYMS to be Enabled.\"\n\tui_print \"- But your kernel seems NOT enabled it.\"\n\texit\n}\n\nfunction apatchNote(){\n\tui_print \"- APatch Patch Done\"\n\tui_print \"- APatch Key is: Ap$skey\"\n\tui_print \"- We do have saved Origin Boot image to /data\"\n\tui_print \"- If you encounter bootloop, reboot into Recovery and flash it\"\n\texit\n}\n\nfunction failed(){\n\tui_printfile /dev/tmp/install/log\n\tui_print \"- APatch Patch Failed.\"\n\tui_print \"- Please feedback to the developer with the screenshots.\"\n\texit\n}\n\nfunction boot_execute_ab(){\n\t./lib/arm64-v8a/libkptools.so unpack boot.img\n\tif [[ ! $(./lib/arm64-v8a/libkptools.so -i ./kernel -f | grep CONFIG_KALLSYMS=y) ]]; then\n\t\tkernelFlagsErr\n\tfi\n\tmv kernel kernel-origin\n\t./lib/arm64-v8a/libkptools.so -p --image kernel-origin --skey \"Ap$skey\" --kpimg ./assets/kpimg --out ./kernel 2>&1 | tee /dev/tmp/install/log\n\tif [[ ! $(cat /dev/tmp/install/log | grep \"patch done\") ]]; then\n\t\tfailed\n\tfi\n\tui_printfile /dev/tmp/install/log\n\t./lib/arm64-v8a/libkptools.so repack boot.img\n\tdd if=/dev/tmp/install/new-boot.img of=/dev/block/by-name/boot$slot\n\tmv boot.img /data/boot.img\n\tapatchNote\n}\n\nfunction boot_execute(){\n\t./lib/arm64-v8a/libkptools.so unpack boot.img\n\tif [[ ! $(./lib/arm64-v8a/libkptools.so -i ./kernel -f | grep CONFIG_KALLSYMS=y) ]]; then\n\t\tkernelFlagsErr\n\tfi\n\tmv kernel kernel-origin\n\t./lib/arm64-v8a/libkptools.so -p --image kernel-origin --skey \"Ap$skey\" --kpimg ./assets/kpimg --out ./kernel 2>&1 | tee /dev/tmp/install/log\n\tif [[ ! $(cat /dev/tmp/install/log | grep \"patch done\") ]]; then\n\t\tfailed\n\tfi\n\tui_printfile /dev/tmp/install/log\n\t./lib/arm64-v8a/libkptools.so repack boot.img\n\tdd if=/dev/tmp/install/new-boot.img of=/dev/block/by-name/boot$slot\n\tmv boot.img /data/boot.img\n\tapatchNote\n}\n\nfunction main(){\n\ncd /dev/tmp/install\n\nchmod a+x ./assets/kpimg\nchmod a+x ./lib/arm64-v8a/libkptools.so\n\nslot=$(getprop ro.boot.slot_suffix)\n\nskey=$(cat /proc/sys/kernel/random/uuid | cut -d \\- -f1)\n\nif [[ ! \"$slot\" == \"\" ]]; then\n\n\tui_print \"\"\n\tui_print \"- You are using A/B device.\"\n\n\t# Script author\n\tui_print \"- Install Script by SakuraKyuo\"\n\n\t# Get kernel\n\tui_print \"\"\n\tdd if=/dev/block/by-name/boot$slot of=/dev/tmp/install/boot.img\n\tif [[ \"$?\" == 0 ]]; then\n\t\tui_print \"- Detected boot partition.\"\n\t\tboot_execute_ab\n\tfi\n\nelse\n\n\tui_print \"You are using A Only device.\"\n\n\t# Get kernel\n\tui_print \"\"\n\tdd if=/dev/block/by-name/boot of=/dev/tmp/install/boot.img\n\tif [[ \"$?\" == 0 ]]; then\n\t\tui_print \"- Detected boot partition.\"\n\t\tboot_execute\n\tfi\n\nfi\n\n}\n\nmain\n"
  },
  {
    "path": "app/src/main/assets/UninstallAP.sh",
    "content": "#!/bin/sh\n# By SakuraKyuo\n\nOUTFD=/proc/self/fd/$2\n\nfunction ui_print() {\n  echo -e \"ui_print $1\\nui_print\" >> $OUTFD\n}\n\nfunction ui_printfile() {\n  while IFS='' read -r line || $BB [[ -n \"$line\" ]]; do\n    ui_print \"$line\";\n  done < $1;\n}\n\nfunction apatchNote(){\n\tui_print \"- APatch Unpatch Done\"\n\texit\n}\n\nfunction failed(){\n\tui_print \"- APatch Unpatch Failed.\"\n\tui_print \"- Please feedback to the developer with the screenshots.\"\n\texit\n}\n\nfunction boot_execute_ab(){\n\t./lib/arm64-v8a/libkptools.so unpack boot.img\n\tmv kernel kernel-origin\n\t./lib/arm64-v8a/libkptools.so -u --image kernel-origin  --out ./kernel\n\tif [[ ! \"$?\" == 0 ]]; then\n\t\tfailed\n\tfi\n\t./lib/arm64-v8a/libkptools.so repack boot.img\n\tdd if=/dev/tmp/install/new-boot.img of=/dev/block/by-name/boot$slot\n\tapatchNote\n}\n\nfunction boot_execute(){\n\t./lib/arm64-v8a/libkptools.so unpack boot.img\n\tmv kernel kernel-origin\n\t./lib/arm64-v8a/libkptools.so -u --image kernel-origin  --out ./kernel\n\tif [[ ! \"$?\" == 0 ]]; then\n\t\tfailed\n\tfi\n\t./lib/arm64-v8a/libkptools.so repack boot.img\n\tdd if=/dev/tmp/install/new-boot.img of=/dev/block/by-name/boot\n\tapatchNote\n}\n\nfunction main(){\n\ncd /dev/tmp/install\n\nchmod a+x ./lib/arm64-v8a/libkptools.so\n\n\nslot=$(getprop ro.boot.slot_suffix)\n\nif [[ ! \"$slot\" == \"\" ]]; then\n\n\tui_print \"\"\n\tui_print \"- You are using A/B device.\"\n\n\t# Get kernel\n\tui_print \"\"\n\tdd if=/dev/block/by-name/boot$slot of=/dev/tmp/install/boot.img\n\tif [[ \"$?\" == 0 ]]; then\n\t\tui_print \"- Detected boot partition.\"\n\t\tboot_execute_ab\n\tfi\n\nelse\n\n\tui_print \"You are using A Only device.\"\n\n\t# Get kernel\n\tui_print \"\"\n\tdd if=/dev/block/by-name/boot of=/dev/tmp/install/boot.img\n\tif [[ \"$?\" == 0 ]]; then\n\t\tui_print \"- Detected boot partition.\"\n\t\tboot_execute\n\tfi\n\nfi\n\n}\n\nmain"
  },
  {
    "path": "app/src/main/assets/boot_extract.sh",
    "content": "#!/system/bin/sh\n\nARCH=$(getprop ro.product.cpu.abi)\n\nIS_INSTALL_NEXT_SLOT=$1\n\n# Load utility functions\n. ./util_functions.sh\n\nif [ \"$IS_INSTALL_NEXT_SLOT\" = \"true\" ]; then\n  get_next_slot\nelse\n  get_current_slot\nfi\n\nfind_boot_image\n\n[ -e \"$BOOTIMAGE\" ] || { >&2 echo \"- can't find boot.img!\"; exit 1; }\n\ntrue\n"
  },
  {
    "path": "app/src/main/assets/boot_patch.sh",
    "content": "#!/system/bin/sh\n#######################################################################################\n# APatch Boot Image Patcher\n#######################################################################################\n#\n# Usage: boot_patch.sh <superkey> <bootimage> [ARGS_PASS_TO_KPTOOLS]\n#\n# This script should be placed in a directory with the following files:\n#\n# File name          Type          Description\n#\n# boot_patch.sh      script        A script to patch boot image for APatch.\n#                  (this file)      The script will use files in its same\n#                                  directory to complete the patching process.\n# bootimg            binary        The target boot image\n# kpimg              binary        KernelPatch core Image\n# kptools            executable    The KernelPatch tools binary to inject kpimg to kernel Image\n#\n#######################################################################################\n\nARCH=$(getprop ro.product.cpu.abi)\n\n# Load utility functions\n. ./util_functions.sh\n\necho \"****************************\"\necho \" APatch Boot Image Patcher\"\necho \"****************************\"\n\nSUPERKEY=\"$1\"\nBOOTIMAGE=$2\nFLASH_TO_DEVICE=$3\nshift 2\n\n[ -z \"$SUPERKEY\" ] && { >&2 echo \"- SuperKey empty!\"; exit 1; }\n[ -e \"$BOOTIMAGE\" ] || { >&2 echo \"- $BOOTIMAGE does not exist!\"; exit 1; }\n\n# Check for dependencies\n\ncommand -v ./kptools >/dev/null 2>&1 || { >&2 echo \"- Command kptools not found!\"; exit 1; }\n\nif [ ! -f kernel ]; then\necho \"- Unpacking boot image\"\n\nset -x\n./kptools unpack \"$BOOTIMAGE\" \"$@\"\npatch_rc=$?\nset +x\n  if [ $patch_rc -ne 0 ]; then\n    >&2 echo \"- Unpack error: $patch_rc\"\n    exit $?\n  fi\nfi\n\nif [ ! $(./kptools -i kernel -f | grep CONFIG_KALLSYMS=y) ]; then\n\techo \"- Patcher has Aborted!\"\n\techo \"- APatch requires CONFIG_KALLSYMS to be Enabled.\"\n\techo \"- But your kernel seems NOT enabled it.\"\n\texit 0\nfi\n\nif [  $(./kptools -i kernel -l | grep patched=false) ]; then\n\techo \"- Backing boot.img \"\n  cp \"$BOOTIMAGE\" \"ori.img\" >/dev/null 2>&1\nfi\n\nmv kernel kernel.ori\n\necho \"- Patching kernel\"\n\nset -x\n./kptools -p -i kernel.ori -S \"$SUPERKEY\" -k kpimg -o kernel \"$@\"\npatch_rc=$?\nset +x\n\nif [ $patch_rc -ne 0 ]; then\n  >&2 echo \"- Patch kernel error: $patch_rc\"\n  exit $?\nfi\n\necho \"- Repacking boot image\"\n./kptools repack \"$BOOTIMAGE\"\n\nif [ ! $(./kptools -i kernel.ori -f | grep CONFIG_KALLSYMS_ALL=y) ]; then\n\techo \"- Detected CONFIG_KALLSYMS_ALL is not set!\"\n\techo \"- APatch has patched but maybe your device won't boot.\"\n\techo \"- Make sure you have original boot image backup.\"\nfi\n\nif [ $? -ne 0 ]; then\n  >&2 echo \"- Repack error: $?\"\n  exit $?\nfi\n\nif [ \"$FLASH_TO_DEVICE\" = \"true\" ]; then\n  # flash\n  if [ -b \"$BOOTIMAGE\" ] || [ -c \"$BOOTIMAGE\" ] && [ -f \"new-boot.img\" ]; then\n    echo \"- Flashing new boot image\"\n    flash_image new-boot.img \"$BOOTIMAGE\"\n    if [ $? -ne 0 ]; then\n      >&2 echo \"- Flash error: $?\"\n      exit $?\n    fi\n  fi\n\n  echo \"- Successfully Flashed!\"\nelse\n  echo \"- Successfully Patched!\"\nfi\n\n"
  },
  {
    "path": "app/src/main/assets/boot_unpatch.sh",
    "content": "#!/system/bin/sh\n#######################################################################################\n# APatch Boot Image Unpatcher\n#######################################################################################\n\nARCH=$(getprop ro.product.cpu.abi)\n\n# Load utility functions\n. ./util_functions.sh\n\necho \"****************************\"\necho \" APatch Boot Image Unpatcher\"\necho \"****************************\"\n\nBOOTIMAGE=$1\n\n[ -e \"$BOOTIMAGE\" ] || { echo \"- $BOOTIMAGE does not exist!\"; exit 1; }\n\necho \"- Target image: $BOOTIMAGE\"\n\n  # Check for dependencies\n\ncommand -v ./kptools >/dev/null 2>&1 || { echo \"- Command kptools not found!\"; exit 1; }\n\nif [ ! -f kernel ]; then\necho \"- Unpacking boot image\"\n\nset -x\n./kptools unpack \"$BOOTIMAGE\" \"$@\"\npatch_rc=$?\nif [ $patch_rc -ne 0 ]; then\n    >&2 echo \"- Unpack error: $patch_rc\"\n    exit $patch_rc\n  fi\nfi\n\nif [ ! $(./kptools -i kernel -l | grep patched=false) ]; then\n\techo \"- kernel has been patched \"\n  if [ -f \"new-boot.img\" ]; then\n    echo \"- found backup boot.img ,use it for recovery\"\n  else\n    mv kernel kernel.ori\n    echo \"- Unpatching kernel\"\n    ./kptools -u --image kernel.ori --out kernel \"$@\"\n    if [ $? -ne 0 ]; then\n      >&2 echo \"- Unpatch error: $?\"\n      exit $?\n    fi\n    echo \"- Repacking boot image\"\n    ./kptools repack \"$BOOTIMAGE\"\n    if [ $? -ne 0 ]; then\n      >&2 echo \"- Repack error: $?\"\n      exit $?\n    fi\n  fi\n\nelse\n  echo \"- no need unpatch\"\n  exit 0\nfi\n\n\n\nif [ -f \"new-boot.img\" ]; then\n  echo \"- Flashing boot image\"\n  flash_image new-boot.img \"$BOOTIMAGE\"\n\n  if [ $? -ne 0 ]; then\n    >&2 echo \"- Flash error: $?\"\n    exit $?\n  fi\nfi\n\necho \"- Flash successful\"\n\n# Reset any error code\ntrue\n"
  },
  {
    "path": "app/src/main/assets/util_functions.sh",
    "content": "#!/system/bin/sh\n#######################################################################################\n# Helper Functions (credits to topjohnwu)\n#######################################################################################\nAPATCH_VER='0.10.4'\nAPATCH_VER_CODE=164\n\nui_print() {\n  if $BOOTMODE; then\n    echo \"$1\"\n  else\n    echo -e \"ui_print $1\\nui_print\" >> /proc/self/fd/$OUTFD\n  fi\n}\n\ntoupper() {\n  echo \"$@\" | tr '[:lower:]' '[:upper:]'\n}\n\ngrep_cmdline() {\n  local REGEX=\"s/^$1=//p\"\n  { echo $(cat /proc/cmdline)$(sed -e 's/[^\"]//g' -e 's/\"\"//g' /proc/cmdline) | xargs -n 1; \\\n    sed -e 's/ = /=/g' -e 's/, /,/g' -e 's/\"//g' /proc/bootconfig; \\\n  } 2>/dev/null | sed -n \"$REGEX\"\n}\n\ngrep_prop() {\n  local REGEX=\"s/^$1=//p\"\n  shift\n  local FILES=$@\n  [ -z \"$FILES\" ] && FILES='/system/build.prop'\n  cat $FILES 2>/dev/null | dos2unix | sed -n \"$REGEX\" | head -n 1\n}\n\ngetvar() {\n  local VARNAME=$1\n  local VALUE\n  local PROPPATH='/data/.magisk /cache/.magisk'\n  [ ! -z $MAGISKTMP ] && PROPPATH=\"$MAGISKTMP/.magisk/config $PROPPATH\"\n  VALUE=$(grep_prop $VARNAME $PROPPATH)\n  [ ! -z $VALUE ] && eval $VARNAME=\\$VALUE\n}\n\nis_mounted() {\n  grep -q \" $(readlink -f $1) \" /proc/mounts 2>/dev/null\n  return $?\n}\nabort() {\n  ui_print \"$1\"\n  $BOOTMODE || recovery_cleanup\n  [ ! -z $MODPATH ] && rm -rf $MODPATH\n  rm -rf $TMPDIR\n  exit 1\n}\nset_nvbase() {\n  NVBASE=\"$1\"\n  MAGISKBIN=\"$1/magisk\"\n}\n\nprint_title() {\n  local len line1len line2len bar\n  line1len=$(echo -n $1 | wc -c)\n  line2len=$(echo -n $2 | wc -c)\n  len=$line2len\n  [ $line1len -gt $line2len ] && len=$line1len\n  len=$((len + 2))\n  bar=$(printf \"%${len}s\" | tr ' ' '*')\n  ui_print \"$bar\"\n  ui_print \" $1 \"\n  [ \"$2\" ] && ui_print \" $2 \"\n  ui_print \"$bar\"\n}\nsetup_flashable() {\n  ensure_bb\n  $BOOTMODE && return\n  if [ -z $OUTFD ] || readlink /proc/$$/fd/$OUTFD | grep -q /tmp; then\n    # We will have to manually find out OUTFD\n    for FD in $(ls /proc/$$/fd); do\n      if readlink /proc/$$/fd/$FD | grep -q pipe; then\n        if ps | grep -v grep | grep -qE \" 3 $FD |status_fd=$FD\"; then\n          OUTFD=$FD\n          break\n        fi\n      fi\n    done\n  fi\n  recovery_actions\n}\n\nensure_bb() {\n  if set -o | grep -q standalone; then\n    # We are definitely in busybox ash\n    set -o standalone\n    return\n  fi\n\n  # Find our busybox binary\n  local bb\n  if [ -f $TMPDIR/busybox ]; then\n    bb=$TMPDIR/busybox\n  elif [ -f $MAGISKBIN/busybox ]; then\n    bb=$MAGISKBIN/busybox\n  else\n    abort \"! Cannot find BusyBox\"\n  fi\n  chmod 755 $bb\n\n  # Busybox could be a script, make sure /system/bin/sh exists\n  if [ ! -f /system/bin/sh ]; then\n    umount -l /system 2>/dev/null\n    mkdir -p /system/bin\n    ln -s $(command -v sh) /system/bin/sh\n  fi\n\n  export ASH_STANDALONE=1\n\n  # Find our current arguments\n  # Run in busybox environment to ensure consistent results\n  # /proc/<pid>/cmdline shall be <interpreter> <script> <arguments...>\n  local cmds=\"$($bb sh -c \"\n  for arg in \\$(tr '\\0' '\\n' < /proc/$$/cmdline); do\n    if [ -z \\\"\\$cmds\\\" ]; then\n      # Skip the first argument as we want to change the interpreter\n      cmds=\\\"sh\\\"\n    else\n      cmds=\\\"\\$cmds '\\$arg'\\\"\n    fi\n  done\n  echo \\$cmds\")\"\n\n  # Re-exec our script\n  echo $cmds | $bb xargs $bb\n  exit\n}\nrecovery_actions() {\n  # Make sure random won't get blocked\n  mount -o bind /dev/urandom /dev/random\n  # Unset library paths\n  OLD_LD_LIB=$LD_LIBRARY_PATH\n  OLD_LD_PRE=$LD_PRELOAD\n  OLD_LD_CFG=$LD_CONFIG_FILE\n  unset LD_LIBRARY_PATH\n  unset LD_PRELOAD\n  unset LD_CONFIG_FILE\n}\nrecovery_cleanup() {\n  local DIR\n  ui_print \"- Unmounting partitions\"\n  (\n  if [ ! -d /postinstall/tmp ]; then\n    umount -l /system\n    umount -l /system_root\n  fi\n  umount -l /vendor\n  umount -l /persist\n  umount -l /metadata\n  for DIR in /apex /system /system_root; do\n    if [ -L \"${DIR}_link\" ]; then\n      rmdir $DIR\n      mv -f ${DIR}_link $DIR\n    fi\n  done\n  umount -l /dev/random\n  ) 2>/dev/null\n  [ -z $OLD_LD_LIB ] || export LD_LIBRARY_PATH=$OLD_LD_LIB\n  [ -z $OLD_LD_PRE ] || export LD_PRELOAD=$OLD_LD_PRE\n  [ -z $OLD_LD_CFG ] || export LD_CONFIG_FILE=$OLD_LD_CFG\n}\n\nfind_block() {\n  local BLOCK DEV DEVICE DEVNAME PARTNAME UEVENT\n  for BLOCK in \"$@\"; do\n    DEVICE=$(find /dev/block \\( -type b -o -type c -o -type l \\) -iname $BLOCK | head -n 1) 2>/dev/null\n    if [ ! -z $DEVICE ]; then\n      readlink -f $DEVICE\n      return 0\n    fi\n  done\n  # Fallback by parsing sysfs uevents\n  for UEVENT in /sys/dev/block/*/uevent; do\n    DEVNAME=$(grep_prop DEVNAME $UEVENT)\n    PARTNAME=$(grep_prop PARTNAME $UEVENT)\n    for BLOCK in \"$@\"; do\n      if [ \"$(toupper $BLOCK)\" = \"$(toupper $PARTNAME)\" ]; then\n        echo /dev/block/$DEVNAME\n        return 0\n      fi\n    done\n  done\n  # Look just in /dev in case we're dealing with MTD/NAND without /dev/block devices/links\n  for DEV in \"$@\"; do\n    DEVICE=$(find /dev \\( -type b -o -type c -o -type l \\) -maxdepth 1 -iname $DEV | head -n 1) 2>/dev/null\n    if [ ! -z $DEVICE ]; then\n      readlink -f $DEVICE\n      return 0\n    fi\n  done\n  return 1\n}\n\n# After calling this method, the following variables will be set:\n# SLOT\nget_current_slot() {\n  # Check A/B slot\n  SLOT=$(grep_cmdline androidboot.slot_suffix)\n  if [ -z $SLOT ]; then\n    SLOT=$(grep_cmdline androidboot.slot)\n    [ -z $SLOT ] || SLOT=_${SLOT}\n  fi\n  if [ -z $SLOT ]; then\n    SLOT=$(getprop ro.boot.slot_suffix)\n  fi\n  [ \"$SLOT\" = \"normal\" ] && unset SLOT\n  [ -z $SLOT ] || echo \"SLOT=$SLOT\"\n}\n\n# After calling this method, the following variables will be set:\n# SLOT\n# This is used after OTA\nget_next_slot() {\n  # Check A/B slot\n  SLOT=$(grep_cmdline androidboot.slot_suffix)\n  if [ -z $SLOT ]; then\n    SLOT=$(grep_cmdline androidboot.slot)\n    [ -z $SLOT ] || SLOT=_${SLOT}\n  fi\n  if [ -z $SLOT ]; then\n    SLOT=$(getprop ro.boot.slot_suffix)\n  fi\n   [ -z $SLOT ] && { >&2 echo \"can't determined next boot slot! check your devices is A/B\"; exit 1; }\n   [ \"$SLOT\" = \"normal\" ] &&  { >&2 echo \"can't determined next boot slot! check your devices is A/B\"; exit 1; }\n  if [[ $SLOT == *_a ]]; then\n    SLOT='_b'\n  else\n    SLOT='_a'\n  fi\n  echo \"SLOT=$SLOT\"\n}\n\nfind_boot_image() {\n  if [ ! -z $SLOT ]; then\n    BOOTIMAGE=$(find_block \"boot$SLOT\")\n  fi\n  if [ -z $BOOTIMAGE ]; then\n    BOOTIMAGE=$(find_block kern-a android_boot kernel bootimg boot lnx boot_a)\n  fi\n  if [ -z $BOOTIMAGE ]; then\n    # Lets see what fstabs tells me\n    BOOTIMAGE=$(grep -v '#' /etc/*fstab* | grep -E '/boot(img)?[^a-zA-Z]' | grep -oE '/dev/[a-zA-Z0-9_./-]*' | head -n 1)\n  fi\n  [ -z $BOOTIMAGE ] || echo \"BOOTIMAGE=$BOOTIMAGE\"\n}\n\nflash_image() {\n  local CMD1\n  case \"$1\" in\n    *.gz) CMD1=\"gzip -d < '$1' 2>/dev/null\";;\n    *)    CMD1=\"cat '$1'\";;\n  esac\n  if [ -b \"$2\" ]; then {\n      local img_sz=$(stat -c '%s' \"$1\")\n      local blk_sz=$(blockdev --getsize64 \"$2\")\n      local blk_bs=$(blockdev --getbsz \"$2\")\n      [ \"$img_sz\" -gt \"$blk_sz\" ] && return 1\n      blockdev --setrw \"$2\"\n      local blk_ro=$(blockdev --getro \"$2\")\n      [ \"$blk_ro\" -eq 1 ] && return 2\n      eval \"$CMD1\" | dd of=\"$2\" bs=\"$blk_bs\" iflag=fullblock conv=notrunc,fsync 2>/dev/null\n      sync\n  } elif [ -c \"$2\" ]; then {\n      flash_eraseall \"$2\" >&2\n      eval \"$CMD1\" | nandwrite -p \"$2\" - >&2\n  } else {\n      echo \"- Not block or char device, storing image\"\n      eval \"$CMD1\" > \"$2\" 2>/dev/null\n  } fi\n  return 0\n}\n\nsetup_mntpoint() {\n  local POINT=$1\n  [ -L $POINT ] && mv -f $POINT ${POINT}_link\n  if [ ! -d $POINT ]; then\n    rm -f $POINT\n    mkdir -p $POINT\n  fi\n}\n\nmount_name() {\n  local PART=$1\n  local POINT=$2\n  local FLAG=$3\n  setup_mntpoint $POINT\n  is_mounted $POINT && return\n  # First try mounting with fstab\n  mount $FLAG $POINT 2>/dev/null\n  if ! is_mounted $POINT; then\n    local BLOCK=$(find_block $PART)\n    mount $FLAG $BLOCK $POINT || return\n  fi\n  ui_print \"- Mounting $POINT\"\n}\n\nmount_ro_ensure() {\n  # We handle ro partitions only in recovery\n  $BOOTMODE && return\n  local PART=$1\n  local POINT=$2\n  mount_name \"$PART\" $POINT '-o ro'\n  is_mounted $POINT || abort \"! Cannot mount $POINT\"\n}\n\n# After calling this method, the following variables will be set:\n# SLOT, SYSTEM_AS_ROOT, LEGACYSAR\nmount_partitions() {\n  # Check A/B slot\n  SLOT=$(grep_cmdline androidboot.slot_suffix)\n  if [ -z $SLOT ]; then\n    SLOT=$(grep_cmdline androidboot.slot)\n    [ -z $SLOT ] || SLOT=_${SLOT}\n  fi\n  [ \"$SLOT\" = \"normal\" ] && unset SLOT\n  [ -z $SLOT ] || ui_print \"- Current boot slot: $SLOT\"\n\n  # Mount ro partitions\n  if is_mounted /system_root; then\n    umount /system 2>/dev/null\n    umount /system_root 2>/dev/null\n  fi\n  mount_ro_ensure \"system$SLOT app$SLOT\" /system\n  if [ -f /system/init -o -L /system/init ]; then\n    SYSTEM_AS_ROOT=true\n    setup_mntpoint /system_root\n    if ! mount --move /system /system_root; then\n      umount /system\n      umount -l /system 2>/dev/null\n      mount_ro_ensure \"system$SLOT app$SLOT\" /system_root\n    fi\n    mount -o bind /system_root/system /system\n  else\n    if grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts; then\n      SYSTEM_AS_ROOT=true\n    else\n      SYSTEM_AS_ROOT=false\n    fi\n  fi\n  $SYSTEM_AS_ROOT && ui_print \"- Device is system-as-root\"\n\n  LEGACYSAR=false\n  if $BOOTMODE; then\n    grep ' / ' /proc/mounts | grep -q '/dev/root' && LEGACYSAR=true\n  else\n    # Recovery mode, assume devices that don't use dynamic partitions are legacy SAR\n    local IS_DYNAMIC=false\n    if grep -q 'androidboot.super_partition' /proc/cmdline; then\n      IS_DYNAMIC=true\n    elif [ -n \"$(find_block super)\" ]; then\n      IS_DYNAMIC=true\n    fi\n    if $SYSTEM_AS_ROOT && ! $IS_DYNAMIC; then\n      LEGACYSAR=true\n      ui_print \"- Legacy SAR, force kernel to load rootfs\"\n    fi\n  fi\n}\n\nget_flags() {\n  if grep ' /data ' /proc/mounts | grep -q 'dm-'; then\n    ISENCRYPTED=true\n  elif [ \"$(getprop ro.crypto.state)\" = \"encrypted\" ]; then\n    ISENCRYPTED=true\n  elif [ \"$DATA\" = \"false\" ]; then\n    # No data access means unable to decrypt in recovery\n    ISENCRYPTED=true\n  else\n    ISENCRYPTED=false\n  fi\n  if [ -n \"$(find_block vbmeta vbmeta_a)\" ]; then\n    PATCHVBMETAFLAG=false\n  else\n    PATCHVBMETAFLAG=true\n    ui_print \"- No vbmeta partition, patch vbmeta in boot image\"\n  fi\n\n  # Overridable config flags with safe defaults\n  getvar KEEPVERITY\n  getvar KEEPFORCEENCRYPT\n  getvar RECOVERYMODE\n  if [ -z $KEEPVERITY ]; then\n    if $SYSTEM_AS_ROOT; then\n      KEEPVERITY=true\n      ui_print \"- System-as-root, keep dm-verity\"\n    else\n      KEEPVERITY=false\n    fi\n  fi\n  if [ -z $KEEPFORCEENCRYPT ]; then\n    if $ISENCRYPTED; then\n      KEEPFORCEENCRYPT=true\n      ui_print \"- Encrypted data, keep forceencrypt\"\n    else\n      KEEPFORCEENCRYPT=false\n    fi\n  fi\n  [ -z $RECOVERYMODE ] && RECOVERYMODE=false\n}\n\ninstall_apatch() {\n  cd $MAGISKBIN\n\n  # Source the boot patcher\n  SOURCEDMODE=true\n  . ./boot_patch.sh \"$BOOTIMAGE\"\n  ui_print \"- Flashing new boot image\"\n  flash_image new-boot.img \"$BOOTIMAGE\"\n  case $? in\n    1)\n      abort \"! Insufficient partition size\"\n      ;;\n    2)\n      abort \"! $BOOTIMAGE is read only\"\n      ;;\n  esac\n  \n  rm -f new-boot.img\n\n  run_migrations\n}\n\ncheck_data() {\n  DATA=false\n  DATA_DE=false\n  if grep ' /data ' /proc/mounts | grep -vq 'tmpfs'; then\n    # Test if data is writable\n    touch /data/.rw && rm /data/.rw && DATA=true\n    # Test if data is decrypted\n    $DATA && [ -d /data/adb ] && touch /data/adb/.rw && rm /data/adb/.rw && DATA_DE=true\n    $DATA_DE && [ -d /data/adb/magisk ] || mkdir /data/adb/magisk || DATA_DE=false\n  fi\n  set_nvbase \"/data\"\n  $DATA || set_nvbase \"/cache/data_adb\"\n  $DATA_DE && set_nvbase \"/data/adb\"\n}\n\napi_level_arch_detect() {\n  API=$(grep_get_prop ro.build.version.sdk)\n  ABI=$(grep_get_prop ro.product.cpu.abi)\n  if [ \"$ABI\" = \"x86\" ]; then\n    ARCH=x86\n    ABI32=x86\n    IS64BIT=false\n  elif [ \"$ABI\" = \"arm64-v8a\" ]; then\n    ARCH=arm64\n    ABI32=armeabi-v7a\n    IS64BIT=true\n  elif [ \"$ABI\" = \"x86_64\" ]; then\n    ARCH=x64\n    ABI32=x86\n    IS64BIT=true\n  else\n    ARCH=arm\n    ABI=armeabi-v7a\n    ABI32=armeabi-v7a\n    IS64BIT=false\n  fi\n}\n\nremove_system_su() {\n  [ -d /postinstall/tmp ] && POSTINST=/postinstall\n  cd $POSTINST/system\n  if [ -f bin/su -o -f xbin/su ] && [ ! -f /su/bin/su ]; then\n    ui_print \"- Removing system installed root\"\n    blockdev --setrw /dev/block/mapper/system$SLOT 2>/dev/null\n    mount -o rw,remount $POSTINST/system\n    # SuperSU\n    cd bin\n    if [ -e .ext/.su ]; then\n      mv -f app_process32_original app_process32 2>/dev/null\n      mv -f app_process64_original app_process64 2>/dev/null\n      mv -f install-recovery_original.sh install-recovery.sh 2>/dev/null\n      if [ -e app_process64 ]; then\n        ln -sf app_process64 app_process\n      elif [ -e app_process32 ]; then\n        ln -sf app_process32 app_process\n      fi\n    fi\n    # More SuperSU, SuperUser & ROM su\n    cd ..\n    rm -rf .pin bin/.ext etc/.installed_su_daemon etc/.has_su_daemon \\\n    xbin/daemonsu xbin/su xbin/sugote xbin/sugote-mksh xbin/supolicy \\\n    bin/app_process_init bin/su /cache/su lib/libsupol.so lib64/libsupol.so \\\n    su.d etc/init.d/99SuperSUDaemon etc/install-recovery.sh /cache/install-recovery.sh \\\n    .supersu /cache/.supersu /data/.supersu \\\n    app/Superuser.apk app/SuperSU /cache/Superuser.apk\n  elif [ -f /cache/su.img -o -f /data/su.img -o -d /data/su -o -d /data/adb/su ]; then\n    ui_print \"- Removing systemless installed root\"\n    umount -l /su 2>/dev/null\n    rm -rf /cache/su.img /data/su.img /data/su /data/adb/su /data/adb/suhide \\\n    /cache/.supersu /data/.supersu /cache/supersu_install /data/supersu_install\n  fi\n  cd $TMPDIR\n}\n\nrun_migrations() {\n  local LOCSHA1\n  local TARGET\n  # Legacy app installation\n  local BACKUP=$MAGISKBIN/stock_boot*.gz\n  if [ -f $BACKUP ]; then\n    cp $BACKUP /data\n    rm -f $BACKUP\n  fi\n\n  # Legacy backup\n  for gz in /data/stock_boot*.gz; do\n    [ -f $gz ] || break\n    LOCSHA1=$(basename $gz | sed -e 's/stock_boot_//' -e 's/.img.gz//')\n    [ -z $LOCSHA1 ] && break\n    mkdir /data/magisk_backup_${LOCSHA1} 2>/dev/null\n    mv $gz /data/magisk_backup_${LOCSHA1}/boot.img.gz\n  done\n\n  # Stock backups\n  LOCSHA1=$SHA1\n  for name in boot dtb dtbo dtbs; do\n    BACKUP=$MAGISKBIN/stock_${name}.img\n    [ -f $BACKUP ] || continue\n    if [ $name = 'boot' ]; then\n      LOCSHA1=$($MAGISKBIN/kptools sha1 $BACKUP)\n      mkdir /data/magisk_backup_${LOCSHA1} 2>/dev/null\n    fi\n    TARGET=/data/magisk_backup_${LOCSHA1}/${name}.img\n    cp $BACKUP $TARGET\n    rm -f $BACKUP\n    gzip -9f $TARGET\n  done\n}"
  },
  {
    "path": "app/src/main/cpp/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.28.0)\nproject(\"apjni\")\n\nfind_program(CCACHE ccache)\n\nif (CCACHE)\n        set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})\n        set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE})\nendif ()\n\nfind_package(cxx REQUIRED CONFIG)\nlink_libraries(cxx::cxx)\n\nmacro(SET_OPTION option value)\n        set(${option} ${value} CACHE INTERNAL \"\" FORCE)\nendmacro()\n\nset(CHERISH_POLLY_FLAGS \"-mllvm -polly -mllvm -polly-run-dce -mllvm -polly-run-inliner -mllvm -polly-reschedule=1 -mllvm -polly-loopfusion-greedy=1 -mllvm -polly-postopts=1 -mllvm -polly-num-threads=0 -mllvm -polly-omp-backend=LLVM -mllvm -polly-scheduling=dynamic -mllvm -polly-scheduling-chunksize=1 -mllvm -polly-isl-arg=--no-schedule-serialize-sccs -mllvm -polly-ast-use-context -mllvm -polly-detect-keep-going -mllvm -polly-position=before-vectorizer -mllvm -polly-vectorizer=stripmine -mllvm -polly-detect-profitability-min-per-loop-insts=40 -mllvm -polly-invariant-load-hoisting\")\nset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${CHERISH_POLLY_FLAGS} -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -O3 -flto -Wno-vla-cxx-extension\")\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} ${CHERISH_POLLY_FLAGS} -ffunction-sections -fdata-sections -fvisibility=hidden -fvisibility-inlines-hidden -fno-rtti -fno-exceptions -O3 -flto -Wno-vla-cxx-extension\")\nset(CMAKE_CXX_STANDARD 23)\n\nadd_library(${PROJECT_NAME} SHARED apjni.cpp)\nadd_custom_command(TARGET ${PROJECT_NAME} POST_BUILD\n        COMMAND ${CMAKE_STRIP} --strip-all --remove-section=.note.gnu.build-id --remove-section=.note.android.ident $<TARGET_FILE:${PROJECT_NAME}>)\n\ntarget_link_libraries(${PROJECT_NAME} PRIVATE log)\ntarget_compile_options(${PROJECT_NAME} PRIVATE -flto)\ntarget_link_options(${PROJECT_NAME} PRIVATE \"-Wl,--build-id=none\" \"-Wl,-icf=all,--lto-O3\" \"-Wl,-s,-x,--gc-sections\" \"-Wl,--no-undefined\")\n"
  },
  {
    "path": "app/src/main/cpp/apjni.cpp",
    "content": "/* SPDX-License-Identifier: GPL-2.0-or-later */\n/* \n * Copyright (C) 2023 bmax121. All Rights Reserved.\n * Copyright (C) 2024 GarfieldHan. All Rights Reserved.\n * Copyright (C) 2024 1f2003d5. All Rights Reserved.\n */\n\n#include <cstring>\n#include <vector>\n\n#include \"apjni.hpp\"\n#include \"supercall.h\"\n\njboolean nativeReady(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    return sc_ready(super_key.get());\n}\n\njlong nativeKernelPatchVersion(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n\n    return sc_kp_ver(super_key.get());\n}\n\njstring nativeKernelPatchBuildTime(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    char buf[4096] = { '\\0' };\n\n    sc_get_build_time(super_key.get(), buf, sizeof(buf));\n    return env->NewStringUTF(buf);\n}\n\njlong nativeSu(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jint to_uid, jstring selinux_context_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    const char *selinux_context = nullptr;\n    if (selinux_context_jstr) selinux_context = JUTFString(env, selinux_context_jstr);\n    struct su_profile profile{};\n    profile.uid = getuid();\n    profile.to_uid = (uid_t)to_uid;\n    if (selinux_context) strncpy(profile.scontext, selinux_context, sizeof(profile.scontext) - 1);\n    long rc = sc_su(super_key.get(), &profile);\n    if (rc < 0) [[unlikely]] {\n        LOGE(\"nativeSu error: %ld\", rc);\n    }\n\n    return rc;\n}\n\njint nativeSetUidExclude(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jint uid, jint exclude) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    return static_cast<int>(sc_set_ap_mod_exclude(super_key.get(), (uid_t) uid, exclude));\n}\n\njint nativeGetUidExclude(JNIEnv *env, jobject /* this */, jstring super_key_jstr, uid_t uid) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    return static_cast<int>(sc_get_ap_mod_exclude(super_key.get(), uid));\n}\n\njintArray nativeSuUids(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    int num = static_cast<int>(sc_su_uid_nums(super_key.get()));\n\n    if (num <= 0) [[unlikely]] {\n        LOGW(\"SuperUser Count less than 1, skip allocating vector...\");\n        return env->NewIntArray(0);\n    }\n\n    std::vector<int> uids(num);\n\n    long n = sc_su_allow_uids(super_key.get(), (uid_t *) uids.data(), num);\n    if (n > 0) [[unlikely]] {\n        auto array = env->NewIntArray(n);\n        env->SetIntArrayRegion(array, 0, n, uids.data());\n        return array;\n    }\n\n    return env->NewIntArray(0);\n}\n\njobject nativeSuProfile(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jint uid) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    struct su_profile profile{};\n    long rc = sc_su_uid_profile(super_key.get(), (uid_t) uid, &profile);\n    if (rc < 0) [[unlikely]] {\n        LOGE(\"nativeSuProfile error: %ld\\n\", rc);\n        return nullptr;\n    }\n    jclass cls = env->FindClass(\"me/bmax/apatch/Natives$Profile\");\n    jmethodID constructor = env->GetMethodID(cls, \"<init>\", \"()V\");\n    jfieldID uidField = env->GetFieldID(cls, \"uid\", \"I\");\n    jfieldID toUidField = env->GetFieldID(cls, \"toUid\", \"I\");\n    jfieldID scontextFild = env->GetFieldID(cls, \"scontext\", \"Ljava/lang/String;\");\n\n    jobject obj = env->NewObject(cls, constructor);\n    env->SetIntField(obj, uidField, (int) profile.uid);\n    env->SetIntField(obj, toUidField, (int) profile.to_uid);\n    env->SetObjectField(obj, scontextFild, env->NewStringUTF(profile.scontext));\n\n    return obj;\n}\n\njlong nativeLoadKernelPatchModule(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jstring module_path_jstr, jstring args_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    const auto module_path = JUTFString(env, module_path_jstr);\n    const auto args = JUTFString(env, args_jstr);\n    long rc = sc_kpm_load(super_key.get(), module_path.get(), args.get(), nullptr);\n    if (rc < 0) [[unlikely]] {\n        LOGE(\"nativeLoadKernelPatchModule error: %ld\", rc);\n    }\n\n    return rc;\n}\n\njobject nativeControlKernelPatchModule(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jstring module_name_jstr, jstring control_args_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    const auto module_name = JUTFString(env, module_name_jstr);\n    const auto control_args = JUTFString(env, control_args_jstr);\n\n    char buf[4096] = { '\\0' };\n    long rc = sc_kpm_control(super_key.get(), module_name.get(), control_args.get(), buf, sizeof(buf));\n    if (rc < 0) [[unlikely]] {\n        LOGE(\"nativeControlKernelPatchModule error: %ld\", rc);\n    }\n\n    jclass cls = env->FindClass(\"me/bmax/apatch/Natives$KPMCtlRes\");\n    jmethodID constructor = env->GetMethodID(cls, \"<init>\", \"()V\");\n    jfieldID rcField = env->GetFieldID(cls, \"rc\", \"J\");\n    jfieldID outMsg = env->GetFieldID(cls, \"outMsg\", \"Ljava/lang/String;\");\n\n    jobject obj = env->NewObject(cls, constructor);\n    env->SetLongField(obj, rcField, rc);\n    env->SetObjectField(obj, outMsg, env->NewStringUTF(buf));\n\n    return obj;\n}\n\njlong nativeUnloadKernelPatchModule(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jstring module_name_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    const auto module_name = JUTFString(env, module_name_jstr);\n    long rc = sc_kpm_unload(super_key.get(), module_name.get(), nullptr);\n    if (rc < 0) [[unlikely]] {\n        LOGE(\"nativeUnloadKernelPatchModule error: %ld\", rc);\n    }\n\n    return rc;\n}\n\njlong nativeKernelPatchModuleNum(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    long rc = sc_kpm_nums(super_key.get());\n    if (rc < 0) [[unlikely]] {\n        LOGE(\"nativeKernelPatchModuleNum error: %ld\", rc);\n    }\n\n    return rc;\n}\n\njstring nativeKernelPatchModuleList(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n\n    char buf[4096] = { '\\0' };\n    long rc = sc_kpm_list(super_key.get(), buf, sizeof(buf));\n    if (rc < 0) [[unlikely]] {\n        LOGE(\"nativeKernelPatchModuleList error: %ld\", rc);\n    }\n\n    return env->NewStringUTF(buf);\n}\n\njstring nativeKernelPatchModuleInfo(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jstring module_name_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    const auto module_name = JUTFString(env, module_name_jstr);\n    char buf[1024] = { '\\0' };\n    long rc = sc_kpm_info(super_key.get(), module_name.get(), buf, sizeof(buf));\n    if (rc < 0) [[unlikely]] {\n        LOGE(\"nativeKernelPatchModuleInfo error: %ld\", rc);\n    }\n\n    return env->NewStringUTF(buf);\n}\n\njlong nativeGrantSu(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jint uid, jint to_uid, jstring selinux_context_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    const auto selinux_context = JUTFString(env, selinux_context_jstr);\n    struct su_profile profile{};\n    profile.uid = uid;\n    profile.to_uid = to_uid;\n    if (selinux_context) strncpy(profile.scontext, selinux_context, sizeof(profile.scontext) - 1);\n    return sc_su_grant_uid(super_key.get(), &profile);\n}\n\njlong nativeRevokeSu(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jint uid) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    return sc_su_revoke_uid(super_key.get(), (uid_t) uid);\n}\n\njstring nativeSuPath(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    char buf[SU_PATH_MAX_LEN] = { '\\0' };\n    long rc = sc_su_get_path(super_key.get(), buf, sizeof(buf));\n    if (rc < 0) [[unlikely]] {\n        LOGE(\"nativeSuPath error: %ld\", rc);\n    }\n\n    return env->NewStringUTF(buf);\n}\n\njboolean nativeResetSuPath(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jstring su_path_jstr) {\n    ensureSuperKeyNonNull(super_key_jstr);\n\n    const auto super_key = JUTFString(env, super_key_jstr);\n    const auto su_path = JUTFString(env, su_path_jstr);\n\n    return sc_su_reset_path(super_key.get(), su_path.get()) == 0;\n}\n\nJNIEXPORT jint JNI_OnLoad(JavaVM* vm, void * /*reserved*/) {\n    LOGI(\"Enter OnLoad\");\n\n    JNIEnv* env{};\n    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) [[unlikely]] {\n        LOGE(\"Get JNIEnv error!\");\n        return JNI_FALSE;\n    }\n\n    auto clazz = JNI_FindClass(env, \"me/bmax/apatch/Natives\");\n    if (clazz.get() == nullptr) [[unlikely]] {\n        LOGE(\"Failed to find Natives class\");\n        return JNI_FALSE;\n    }\n\n    const static JNINativeMethod gMethods[] = {\n        {\"nativeReady\", \"(Ljava/lang/String;)Z\", reinterpret_cast<void *>(&nativeReady)},\n        {\"nativeKernelPatchVersion\", \"(Ljava/lang/String;)J\", reinterpret_cast<void *>(&nativeKernelPatchVersion)},\n        {\"nativeKernelPatchBuildTime\", \"(Ljava/lang/String;)Ljava/lang/String;\", reinterpret_cast<void *>(&nativeKernelPatchBuildTime)},\n        {\"nativeSu\", \"(Ljava/lang/String;ILjava/lang/String;)J\", reinterpret_cast<void *>(&nativeSu)},\n        {\"nativeSetUidExclude\", \"(Ljava/lang/String;II)I\", reinterpret_cast<void *>(&nativeSetUidExclude)},\n        {\"nativeGetUidExclude\", \"(Ljava/lang/String;I)I\", reinterpret_cast<void *>(&nativeGetUidExclude)},\n        {\"nativeSuUids\", \"(Ljava/lang/String;)[I\", reinterpret_cast<void *>(&nativeSuUids)},\n        {\"nativeSuProfile\", \"(Ljava/lang/String;I)Lme/bmax/apatch/Natives$Profile;\", reinterpret_cast<void *>(&nativeSuProfile)},\n        {\"nativeLoadKernelPatchModule\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J\", reinterpret_cast<void *>(&nativeLoadKernelPatchModule)},\n        {\"nativeControlKernelPatchModule\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lme/bmax/apatch/Natives$KPMCtlRes;\", reinterpret_cast<void *>(&nativeControlKernelPatchModule)},\n        {\"nativeUnloadKernelPatchModule\", \"(Ljava/lang/String;Ljava/lang/String;)J\", reinterpret_cast<void *>(&nativeUnloadKernelPatchModule)},\n        {\"nativeKernelPatchModuleNum\", \"(Ljava/lang/String;)J\", reinterpret_cast<void *>(&nativeKernelPatchModuleNum)},\n        {\"nativeKernelPatchModuleList\", \"(Ljava/lang/String;)Ljava/lang/String;\", reinterpret_cast<void *>(&nativeKernelPatchModuleList)},\n        {\"nativeKernelPatchModuleInfo\", \"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;\", reinterpret_cast<void *>(&nativeKernelPatchModuleInfo)},\n        {\"nativeGrantSu\", \"(Ljava/lang/String;IILjava/lang/String;)J\", reinterpret_cast<void *>(&nativeGrantSu)},\n        {\"nativeRevokeSu\", \"(Ljava/lang/String;I)J\", reinterpret_cast<void *>(&nativeRevokeSu)},\n        {\"nativeSuPath\", \"(Ljava/lang/String;)Ljava/lang/String;\", reinterpret_cast<void *>(&nativeSuPath)},\n        {\"nativeResetSuPath\", \"(Ljava/lang/String;Ljava/lang/String;)Z\", reinterpret_cast<void *>(&nativeResetSuPath)},\n    };\n\n    if (JNI_RegisterNatives(env, clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0) [[unlikely]] {\n        LOGE(\"Failed to register native methods\");\n        return JNI_FALSE;\n    }\n    \n    LOGI(\"JNI_OnLoad Done!\");\n    return JNI_VERSION_1_6;\n}\n"
  },
  {
    "path": "app/src/main/cpp/apjni.hpp",
    "content": "//\n// Created by GarfieldHan on 2024/6/11.\n//\n\n#ifndef APATCH_APJNI_HPP\n#define APATCH_APJNI_HPP\n\n#include <jni.h>\n#include <android/log.h>\n#include \"jni_helper.hpp\"\n\nusing namespace lsplant;\n\n#define LOG_TAG \"APatchNative\"\n#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)\n#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)\n#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)\n#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)\n#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)\n\nvoid ensureSuperKeyNonNull(jstring super_key_jstr) {\n    if (!super_key_jstr) [[unlikely]] {\n        LOGE(\"[%s] Super Key is null!\", __PRETTY_FUNCTION__);\n        abort();\n    }\n}\n\n#endif //APATCH_APJNI_HPP\n"
  },
  {
    "path": "app/src/main/cpp/jni_helper.hpp",
    "content": "#pragma once\n\n#include <android/log.h>\n#include <jni.h>\n\n#include <string>\n#include <string_view>\n\n#include \"type_traits.hpp\"\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Winvalid-partial-specialization\"\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"\n#pragma ide diagnostic ignored \"OCUnusedGlobalDeclarationInspection\"\n\n#define DISALLOW_COPY_AND_ASSIGN(TypeName)                                                         \\\n    TypeName(const TypeName &) = delete;                                                           \\\n    void operator=(const TypeName &) = delete\n\nnamespace lsplant {\ntemplate <typename T>\nconcept JObject = std::is_base_of_v<std::remove_pointer_t<_jobject>, std::remove_pointer_t<T>>;\n\ntemplate <JObject T>\nclass ScopedLocalRef {\npublic:\n    using BaseType [[maybe_unused]] = T;\n\n    ScopedLocalRef(JNIEnv *env, T local_ref) : env_(env), local_ref_(nullptr) { reset(local_ref); }\n\n    ScopedLocalRef(ScopedLocalRef &&s) noexcept : ScopedLocalRef(s.env_, s.release()) {}\n\n    template <JObject U>\n    ScopedLocalRef(ScopedLocalRef<U> &&s) noexcept : ScopedLocalRef(s.env_, (T)s.release()) {}\n\n    explicit ScopedLocalRef(JNIEnv *env) noexcept : ScopedLocalRef(env, T{nullptr}) {}\n\n    ~ScopedLocalRef() { reset(); }\n\n    void reset(T ptr = nullptr) {\n        if (ptr != local_ref_) {\n            if (local_ref_ != nullptr) {\n                env_->DeleteLocalRef(local_ref_);\n            }\n            local_ref_ = ptr;\n        }\n    }\n\n    [[nodiscard]] T release() {\n        T localRef = local_ref_;\n        local_ref_ = nullptr;\n        return localRef;\n    }\n\n    T get() const { return local_ref_; }\n\n    ScopedLocalRef<T> clone() const {\n        return ScopedLocalRef<T>(env_, (T)env_->NewLocalRef(local_ref_));\n    }\n\n    ScopedLocalRef &operator=(ScopedLocalRef &&s) noexcept {\n        reset(s.release());\n        env_ = s.env_;\n        return *this;\n    }\n\n    operator bool() const { return local_ref_; }\n\n    template <JObject U>\n    friend class ScopedLocalRef;\n\n    friend class JUTFString;\n\nprivate:\n    JNIEnv *env_;\n    T local_ref_;\n    DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);\n};\n\nclass JObjectArrayElement;\n\ntemplate <typename T>\nconcept JArray = std::is_base_of_v<std::remove_pointer_t<_jarray>, std::remove_pointer_t<T>>;\n\ntemplate <JArray T>\nclass ScopedLocalRef<T>;\n\nclass JNIScopeFrame {\n    JNIEnv *env_;\n\n    DISALLOW_COPY_AND_ASSIGN(JNIScopeFrame);\n\npublic:\n    JNIScopeFrame(JNIEnv *env, jint size) : env_(env) { env_->PushLocalFrame(size); }\n\n    ~JNIScopeFrame() { env_->PopLocalFrame(nullptr); }\n};\n\nclass JNIMonitor {\n    JNIEnv *env_;\n    jobject obj_;\n\n    DISALLOW_COPY_AND_ASSIGN(JNIMonitor);\n\npublic:\n    JNIMonitor(JNIEnv *env, jobject obj) : env_(env), obj_(obj) { env_->MonitorEnter(obj_); }\n\n    ~JNIMonitor() { env_->MonitorExit(obj_); }\n};\n\ntemplate <typename T, typename U>\nconcept ScopeOrRaw =\n    std::is_convertible_v<T, U> ||\n    (is_instance_v<std::decay_t<T>, ScopedLocalRef> &&\n     std::is_convertible_v<typename std::decay_t<T>::BaseType, U>) ||\n    (std::is_same_v<std::decay_t<T>, JObjectArrayElement> && std::is_convertible_v<jobject, U>);\n\ntemplate <typename T>\nconcept ScopeOrClass = ScopeOrRaw<T, jclass>;\n\ntemplate <typename T>\nconcept ScopeOrObject = ScopeOrRaw<T, jobject>;\n\ninline ScopedLocalRef<jstring> ClearException(JNIEnv *env) {\n    if (auto exception = env->ExceptionOccurred()) {\n        env->ExceptionClear();\n        jclass log = (jclass)env->FindClass(\"android/util/Log\");\n        static jmethodID toString = env->GetStaticMethodID(\n            log, \"getStackTraceString\", \"(Ljava/lang/Throwable;)Ljava/lang/String;\");\n        auto str = (jstring)env->CallStaticObjectMethod(log, toString, exception);\n        env->DeleteLocalRef(log);\n        env->DeleteLocalRef(exception);\n        return {env, str};\n    }\n    return {env, nullptr};\n}\n\ntemplate <typename T>\n[[maybe_unused]] inline auto UnwrapScope(T &&x) {\n    if constexpr (std::is_same_v<std::decay_t<T>, std::string_view>)\n        return x.data();\n    else if constexpr (is_instance_v<std::decay_t<T>, ScopedLocalRef>)\n        return x.get();\n    else if constexpr (std::is_same_v<std::decay_t<T>, JObjectArrayElement>)\n        return x.get();\n    else\n        return std::forward<T>(x);\n}\n\ntemplate <typename T>\n[[maybe_unused]] inline auto WrapScope(JNIEnv *env, T &&x) {\n    if constexpr (std::is_convertible_v<T, _jobject *>) {\n        return ScopedLocalRef(env, std::forward<T>(x));\n    } else\n        return x;\n}\n\ntemplate <typename... T, size_t... I>\n[[maybe_unused]] inline auto WrapScope(JNIEnv *env, std::tuple<T...> &&x,\n                                       std::index_sequence<I...>) {\n    return std::make_tuple(WrapScope(env, std::forward<T>(std::get<I>(x)))...);\n}\n\ntemplate <typename... T>\n[[maybe_unused]] inline auto WrapScope(JNIEnv *env, std::tuple<T...> &&x) {\n    return WrapScope(env, std::forward<std::tuple<T...>>(x),\n                     std::make_index_sequence<sizeof...(T)>());\n}\n\ninline auto JNI_NewStringUTF(JNIEnv *env, std::string_view sv) {\n    return ScopedLocalRef(env, env->NewStringUTF(sv.data()));\n}\n\nclass JUTFString {\npublic:\n    JUTFString(JNIEnv *env, jstring jstr) : JUTFString(env, jstr, nullptr) {}\n\n    JUTFString(const ScopedLocalRef<jstring> &jstr)\n        : JUTFString(jstr.env_, jstr.local_ref_, nullptr) {}\n\n    JUTFString(JNIEnv *env, jstring jstr, const char *default_cstr) : env_(env), jstr_(jstr) {\n        if (env_ && jstr_)\n            cstr_ = env_->GetStringUTFChars(jstr, nullptr);\n        else\n            cstr_ = default_cstr;\n    }\n\n    operator const char *() const { return cstr_; }\n\n    operator const std::string() const { return cstr_; }\n\n    operator const bool() const { return cstr_ != nullptr; }\n\n    auto get() const { return cstr_; }\n\n    ~JUTFString() {\n        if (env_ && jstr_) env_->ReleaseStringUTFChars(jstr_, cstr_);\n    }\n\n    JUTFString(JUTFString &&other)\n        : env_(std::move(other.env_)),\n          jstr_(std::move(other.jstr_)),\n          cstr_(std::move(other.cstr_)) {\n        other.cstr_ = nullptr;\n    }\n\n    JUTFString &operator=(JUTFString &&other) {\n        if (&other != this) {\n            env_ = std::move(other.env_);\n            jstr_ = std::move(other.jstr_);\n            cstr_ = std::move(other.cstr_);\n            other.cstr_ = nullptr;\n        }\n        return *this;\n    }\n\nprivate:\n    JNIEnv *env_;\n    jstring jstr_;\n    const char *cstr_;\n\n    JUTFString(const JUTFString &) = delete;\n\n    JUTFString &operator=(const JUTFString &) = delete;\n};\n\ntemplate <typename Func, typename... Args>\n    requires(std::is_function_v<Func>)\n[[maybe_unused]] inline auto JNI_SafeInvoke(JNIEnv *env, Func JNIEnv::*f, Args &&...args) {\n    struct finally {\n        finally(JNIEnv *env) : env_(env) {}\n\n        ~finally() {\n            if (auto exception = ClearException(env_)) {\n                __android_log_print(ANDROID_LOG_ERROR,\n#ifdef LOG_TAG\n                                    LOG_TAG,\n#else\n                                    \"JNIHelper\",\n#endif\n                                    \"%s\", JUTFString(env_, exception.get()).get());\n            }\n        }\n\n        JNIEnv *env_;\n    } _(env);\n\n    if constexpr (!std::is_same_v<void,\n                                  std::invoke_result_t<Func, decltype(UnwrapScope(\n                                                                 std::forward<Args>(args)))...>>)\n        return WrapScope(env, (env->*f)(UnwrapScope(std::forward<Args>(args))...));\n    else\n        (env->*f)(UnwrapScope(std::forward<Args>(args))...);\n}\n\n// functions to class\n\n[[maybe_unused]] inline auto JNI_FindClass(JNIEnv *env, std::string_view name) {\n    return JNI_SafeInvoke(env, &JNIEnv::FindClass, name);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetObjectClass(JNIEnv *env, const Object &obj) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetObjectClass, obj);\n}\n\n// functions to field\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetFieldID(JNIEnv *env, Class &&clazz, std::string_view name,\n                                            std::string_view sig) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetFieldID, std::forward<Class>(clazz), name, sig);\n}\n\n// getters\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetObjectField(JNIEnv *env, Object &&obj, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetObjectField, std::forward<Object>(obj), fieldId);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetBooleanField(JNIEnv *env, Object &&obj, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetBooleanField, std::forward<Object>(obj), fieldId);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetByteField(JNIEnv *env, Object &&obj, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetByteField, std::forward<Object>(obj), fieldId);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetCharField(JNIEnv *env, Object &&obj, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetCharField, std::forward<Object>(obj), fieldId);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetShortField(JNIEnv *env, Object &&obj, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetShortField, std::forward<Object>(obj), fieldId);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetIntField(JNIEnv *env, Object &&obj, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetIntField, std::forward<Object>(obj), fieldId);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetLongField(JNIEnv *env, Object &&obj, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetLongField, std::forward<Object>(obj), fieldId);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetFloatField(JNIEnv *env, Object &&obj, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetFloatField, std::forward<Object>(obj), fieldId);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetDoubleField(JNIEnv *env, Object &&obj, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetDoubleField, std::forward<Object>(obj), fieldId);\n}\n\n// setters\n\ntemplate <ScopeOrObject Object, ScopeOrObject Value>\n[[maybe_unused]] inline auto JNI_SetObjectField(JNIEnv *env, Object &&obj, jfieldID fieldId,\n                                                const Value &value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetObjectField, std::forward<Object>(obj), fieldId, value);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_SetBooleanField(JNIEnv *env, Object &&obj, jfieldID fieldId,\n                                                 jboolean value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetBooleanField, std::forward<Object>(obj), fieldId, value);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_SetByteField(JNIEnv *env, Object &&obj, jfieldID fieldId,\n                                              jbyte value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetByteField, std::forward<Object>(obj), fieldId, value);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_SetCharField(JNIEnv *env, Object &&obj, jfieldID fieldId,\n                                              jchar value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetCharField, std::forward<Object>(obj), fieldId, value);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_SetShortField(JNIEnv *env, Object &&obj, jfieldID fieldId,\n                                               jshort value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetShortField, std::forward<Object>(obj), fieldId, value);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_SetIntField(JNIEnv *env, Object &&obj, jfieldID fieldId,\n                                             jint value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetIntField, std::forward<Object>(obj), fieldId, value);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_SetLongField(JNIEnv *env, Object &&obj, jfieldID fieldId,\n                                              jlong value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetLongField, std::forward<Object>(obj), fieldId, value);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_SetFloatField(JNIEnv *env, Object &&obj, jfieldID fieldId,\n                                               jfloat value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetFloatField, std::forward<Object>(obj), fieldId, value);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_SetDoubleField(JNIEnv *env, Object &&obj, jfieldID fieldId,\n                                                jdouble value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetDoubleField, std::forward<Object>(obj), fieldId, value);\n}\n\n// functions to static field\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticFieldID(JNIEnv *env, Class &&clazz, std::string_view name,\n                                                  std::string_view sig) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticFieldID, std::forward<Class>(clazz), name, sig);\n}\n\n// getters\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticObjectField(JNIEnv *env, Class &&clazz,\n                                                      jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticObjectField, std::forward<Class>(clazz), fieldId);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticBooleanField(JNIEnv *env, Class &&clazz,\n                                                       jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticBooleanField, std::forward<Class>(clazz), fieldId);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticByteField(JNIEnv *env, Class &&clazz, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticByteField, std::forward<Class>(clazz), fieldId);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticCharField(JNIEnv *env, Class &&clazz, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticCharField, std::forward<Class>(clazz), fieldId);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticShortField(JNIEnv *env, Class &&clazz, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticShortField, std::forward<Class>(clazz), fieldId);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticIntField(JNIEnv *env, Class &&clazz, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticIntField, std::forward<Class>(clazz), fieldId);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticLongField(JNIEnv *env, Class &&clazz, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticLongField, std::forward<Class>(clazz), fieldId);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticFloatField(JNIEnv *env, Class &&clazz, jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticFloatField, std::forward<Class>(clazz), fieldId);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticDoubleField(JNIEnv *env, Class &&clazz,\n                                                      jfieldID fieldId) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticDoubleField, std::forward<Class>(clazz), fieldId);\n}\n\n// setters\n\ntemplate <ScopeOrClass Class, ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_SetStaticObjectField(JNIEnv *env, Class &&clazz, jfieldID fieldId,\n                                                      const Object &value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetStaticObjectField, std::forward<Class>(clazz), fieldId,\n                          value);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_SetStaticBooleanField(JNIEnv *env, Class &&clazz, jfieldID fieldId,\n                                                       jboolean value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetStaticBooleanField, std::forward<Class>(clazz), fieldId,\n                          value);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_SetStaticByteField(JNIEnv *env, Class &&clazz, jfieldID fieldId,\n                                                    jbyte value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetStaticByteField, std::forward<Class>(clazz), fieldId,\n                          value);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_SetStaticCharField(JNIEnv *env, Class &&clazz, jfieldID fieldId,\n                                                    jchar value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetStaticCharField, std::forward<Class>(clazz), fieldId,\n                          value);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_SetStaticShortField(JNIEnv *env, Class &&clazz, jfieldID fieldId,\n                                                     jshort value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetStaticShortField, std::forward<Class>(clazz), fieldId,\n                          value);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_SetStaticIntField(JNIEnv *env, Class &&clazz, jfieldID fieldId,\n                                                   jint value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetStaticIntField, std::forward<Class>(clazz), fieldId,\n                          value);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_SetStaticLongField(JNIEnv *env, Class &&clazz, jfieldID fieldId,\n                                                    jlong value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetStaticLongField, std::forward<Class>(clazz), fieldId,\n                          value);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_SetStaticFloatField(JNIEnv *env, Class &&clazz, jfieldID fieldId,\n                                                     jfloat value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetStaticFloatField, std::forward<Class>(clazz), fieldId,\n                          value);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_SetStaticDoubleField(JNIEnv *env, Class &&clazz, jfieldID fieldId,\n                                                      jdouble value) {\n    return JNI_SafeInvoke(env, &JNIEnv::SetStaticDoubleField, std::forward<Class>(clazz), fieldId,\n                          value);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_ToReflectedMethod(JNIEnv *env, Class &&clazz, jmethodID method,\n                                                   jboolean isStatic = JNI_FALSE) {\n    return JNI_SafeInvoke(env, &JNIEnv::ToReflectedMethod, std::forward<Class>(clazz), method,\n                          isStatic);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_ToReflectedField(JNIEnv *env, Class &&clazz, jfieldID field,\n                                                   jboolean isStatic = JNI_FALSE) {\n    return JNI_SafeInvoke(env, &JNIEnv::ToReflectedField, std::forward<Class>(clazz), field,\n                          isStatic);\n}\n\n// functions to method\n\n// virtual methods\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetMethodID(JNIEnv *env, Class &&clazz, std::string_view name,\n                                             std::string_view sig) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetMethodID, std::forward<Class>(clazz), name, sig);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallVoidMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                                Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallVoidMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallObjectMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                                  Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallObjectMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallBooleanMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                                   Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallBooleanMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallByteMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                                Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallByteMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallCharMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                                Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallCharMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallShortMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                                 Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallShortMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallIntMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                               Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallIntMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallLongMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                                Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallLongMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallFloatMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                                 Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallFloatMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, typename... Args>\n[[maybe_unused]] inline auto JNI_CallDoubleMethod(JNIEnv *env, Object &&obj, jmethodID method,\n                                                  Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallDoubleMethod, std::forward<Object>(obj), method,\n                          std::forward<Args>(args)...);\n}\n\n// static methods\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_GetStaticMethodID(JNIEnv *env, Class &&clazz,\n                                                   std::string_view name, std::string_view sig) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetStaticMethodID, std::forward<Class>(clazz), name, sig);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticVoidMethod(JNIEnv *env, Class &&clazz, jmethodID method,\n                                                      Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticVoidMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticObjectMethod(JNIEnv *env, Class &&clazz,\n                                                        jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticObjectMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticBooleanMethod(JNIEnv *env, Class &&clazz,\n                                                         jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticBooleanMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticByteMethod(JNIEnv *env, Class &&clazz, jmethodID method,\n                                                      Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticByteMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticCharMethod(JNIEnv *env, Class &&clazz, jmethodID method,\n                                                      Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticCharMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticShortMethod(JNIEnv *env, Class &&clazz, jmethodID method,\n                                                       Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticShortMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticIntMethod(JNIEnv *env, Class &&clazz, jmethodID method,\n                                                     Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticIntMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticLongMethod(JNIEnv *env, Class &&clazz, jmethodID method,\n                                                      Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticLongMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticFloatMethod(JNIEnv *env, Class &&clazz, jmethodID method,\n                                                       Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticFloatMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallStaticDoubleMethod(JNIEnv *env, Class &&clazz,\n                                                        jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallStaticDoubleMethod, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\n// non-virtual methods\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualVoidMethod(JNIEnv *env, Object &&obj, Class &&clazz,\n                                                          jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualVoidMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualObjectMethod(JNIEnv *env, Object &&obj,\n                                                            Class &&clazz, jmethodID method,\n                                                            Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualObjectMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualBooleanMethod(JNIEnv *env, Object &&obj,\n                                                             Class &&clazz, jmethodID method,\n                                                             Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualBooleanMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualByteMethod(JNIEnv *env, Object &&obj, Class &&clazz,\n                                                          jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualByteMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualCharMethod(JNIEnv *env, Object &&obj, Class &&clazz,\n                                                          jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualCharMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualShortMethod(JNIEnv *env, Object &&obj, Class &&clazz,\n                                                           jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualShortMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualIntMethod(JNIEnv *env, Object &&obj, Class &&clazz,\n                                                         jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualIntMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualLongMethod(JNIEnv *env, Object &&obj, Class &&clazz,\n                                                          jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualLongMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualFloatMethod(JNIEnv *env, Object &&obj, Class &&clazz,\n                                                           jmethodID method, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualFloatMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_CallNonvirtualDoubleMethod(JNIEnv *env, Object &&obj,\n                                                            Class &&clazz, jmethodID method,\n                                                            Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::CallNonvirtualDoubleMethod, std::forward<Object>(obj),\n                          std::forward<Class>(clazz), method, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class, typename... Args>\n[[maybe_unused]] inline auto JNI_NewObject(JNIEnv *env, Class &&clazz, jmethodID method,\n                                           Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewObject, std::forward<Class>(clazz), method,\n                          std::forward<Args>(args)...);\n}\n\ntemplate <typename... Args>\n[[maybe_unused]] inline auto JNI_NewDirectByteBuffer(JNIEnv *env, Args &&...args) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewDirectByteBuffer, std::forward<Args>(args)...);\n}\n\ntemplate <ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_RegisterNatives(JNIEnv *env, Class &&clazz,\n                                                 const JNINativeMethod *methods, jint size) {\n    return JNI_SafeInvoke(env, &JNIEnv::RegisterNatives, std::forward<Class>(clazz), methods, size);\n}\n\ntemplate <ScopeOrObject Object, ScopeOrClass Class>\n[[maybe_unused]] inline auto JNI_IsInstanceOf(JNIEnv *env, Object &&obj, Class &&clazz) {\n    return JNI_SafeInvoke(env, &JNIEnv::IsInstanceOf, std::forward<Object>(obj),\n                          std::forward<Class>(clazz));\n}\n\ntemplate <ScopeOrObject Object1, ScopeOrObject Object2>\n[[maybe_unused]] inline auto JNI_IsSameObject(JNIEnv *env, Object1 &&a, Object2 &&b) {\n    return JNI_SafeInvoke(env, &JNIEnv::IsSameObject, std::forward<Object1>(a),\n                          std::forward<Object2>(b));\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_NewGlobalRef(JNIEnv *env, Object &&x) {\n    return (decltype(UnwrapScope(std::forward<Object>(x))))env->NewGlobalRef(\n        UnwrapScope(std::forward<Object>(x)));\n}\n\ntemplate <typename U, typename T>\n[[maybe_unused]] inline auto JNI_Cast(ScopedLocalRef<T> &&x)\n    requires(std::is_convertible_v<T, _jobject *>)\n{\n    return ScopedLocalRef<U>(std::move(x));\n}\n\ntemplate <typename U>\n[[maybe_unused]] inline auto JNI_Cast(JObjectArrayElement &&x) {\n    return JNI_Cast<U, jobject>(std::move(x));\n}\n\n[[maybe_unused]] inline auto JNI_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewDirectByteBuffer, address, capacity);\n}\n\ntemplate <JArray T>\nstruct JArrayUnderlyingTypeHelper;\n\ntemplate <>\nstruct JArrayUnderlyingTypeHelper<jbooleanArray> {\n    using Type = jboolean;\n};\n\ntemplate <>\nstruct JArrayUnderlyingTypeHelper<jbyteArray> {\n    using Type = jbyte;\n};\n\ntemplate <>\nstruct JArrayUnderlyingTypeHelper<jcharArray> {\n    using Type = jchar;\n};\n\ntemplate <>\nstruct JArrayUnderlyingTypeHelper<jshortArray> {\n    using Type = jshort;\n};\n\ntemplate <>\nstruct JArrayUnderlyingTypeHelper<jintArray> {\n    using Type = jint;\n};\n\ntemplate <>\nstruct JArrayUnderlyingTypeHelper<jlongArray> {\n    using Type = jlong;\n};\n\ntemplate <>\nstruct JArrayUnderlyingTypeHelper<jfloatArray> {\n    using Type = jfloat;\n};\n\ntemplate <>\nstruct JArrayUnderlyingTypeHelper<jdoubleArray> {\n    using Type = jdouble;\n};\n\ntemplate <JArray T>\nusing JArrayUnderlyingType = typename JArrayUnderlyingTypeHelper<T>::Type;\n\ntemplate <JArray T>\nclass ScopedLocalRef<T> {\npublic:\n    class Iterator {\n        friend class ScopedLocalRef<T>;\n        Iterator(JArrayUnderlyingType<T> *e) : e_(e) {}\n        JArrayUnderlyingType<T> *e_;\n\n    public:\n        auto &operator*() { return *e_; }\n        auto *operator->() { return e_; }\n        Iterator &operator++() { return ++e_, *this; }\n        Iterator &operator--() { return --e_, *this; }\n        Iterator operator++(int) { return Iterator(e_++); }\n        Iterator operator--(int) { return Iterator(e_--); }\n        bool operator==(const Iterator &other) const { return other.e_ == e_; }\n        bool operator!=(const Iterator &other) const { return other.e_ != e_; }\n    };\n\n    class ConstIterator {\n        friend class ScopedLocalRef<T>;\n        ConstIterator(const JArrayUnderlyingType<T> *e) : e_(e) {}\n        const JArrayUnderlyingType<T> *e_;\n\n    public:\n        const auto &operator*() { return *e_; }\n        const auto *operator->() { return e_; }\n        ConstIterator &operator++() { return ++e_, *this; }\n        ConstIterator &operator--() { return --e_, *this; }\n        ConstIterator operator++(int) { return ConstIterator(e_++); }\n        ConstIterator operator--(int) { return ConstIterator(e_--); }\n        bool operator==(const ConstIterator &other) const { return other.e_ == e_; }\n        bool operator!=(const ConstIterator &other) const { return other.e_ != e_; }\n    };\n\n    auto begin() {\n        modified_ = true;\n        return Iterator(elements_);\n    }\n\n    auto end() {\n        modified_ = true;\n        return Iterator(elements_ + size_);\n    }\n\n    const auto begin() const { return ConstIterator(elements_); }\n\n    auto end() const { return ConstIterator(elements_ + size_); }\n\n    const auto cbegin() const { return ConstIterator(elements_); }\n\n    auto cend() const { return ConstIterator(elements_ + size_); }\n\n    using BaseType [[maybe_unused]] = T;\n\n    ScopedLocalRef(JNIEnv *env, T local_ref) noexcept : env_(env), local_ref_(nullptr) {\n        reset(local_ref);\n    }\n\n    ScopedLocalRef(ScopedLocalRef &&s) noexcept { *this = std::move(s); }\n\n    template <JObject U>\n    ScopedLocalRef(ScopedLocalRef<U> &&s) noexcept : ScopedLocalRef(s.env_, (T)s.release()) {}\n\n    explicit ScopedLocalRef(JNIEnv *env) noexcept : ScopedLocalRef(env, T{nullptr}) {}\n\n    ~ScopedLocalRef() { env_->DeleteLocalRef(release()); }\n\n    void reset(T ptr = nullptr) {\n        if (ptr != local_ref_) {\n            if (local_ref_ != nullptr) {\n                ReleaseElements(modified_ ? 0 : JNI_ABORT);\n                env_->DeleteLocalRef(local_ref_);\n                elements_ = nullptr;\n            }\n            local_ref_ = ptr;\n            size_ = local_ref_ ? env_->GetArrayLength(local_ref_) : 0;\n            if (!local_ref_) return;\n            static_assert(!std::is_same_v<T, jobjectArray>);\n            if constexpr (std::is_same_v<T, jbooleanArray>) {\n                elements_ = env_->GetBooleanArrayElements(local_ref_, nullptr);\n            } else if constexpr (std::is_same_v<T, jbyteArray>) {\n                elements_ = env_->GetByteArrayElements(local_ref_, nullptr);\n            } else if constexpr (std::is_same_v<T, jcharArray>) {\n                elements_ = env_->GetCharArrayElements(local_ref_, nullptr);\n            } else if constexpr (std::is_same_v<T, jshortArray>) {\n                elements_ = env_->GetShortArrayElements(local_ref_, nullptr);\n            } else if constexpr (std::is_same_v<T, jintArray>) {\n                elements_ = env_->GetIntArrayElements(local_ref_, nullptr);\n            } else if constexpr (std::is_same_v<T, jlongArray>) {\n                elements_ = env_->GetLongArrayElements(local_ref_, nullptr);\n            } else if constexpr (std::is_same_v<T, jfloatArray>) {\n                elements_ = env_->GetFloatArrayElements(local_ref_, nullptr);\n            } else if constexpr (std::is_same_v<T, jdoubleArray>) {\n                elements_ = env_->GetDoubleArrayElements(local_ref_, nullptr);\n            }\n        }\n    }\n\n    [[nodiscard]] T release() {\n        T localRef = local_ref_;\n        size_ = 0;\n        local_ref_ = nullptr;\n        ReleaseElements(modified_ ? 0 : JNI_ABORT);\n        elements_ = nullptr;\n        return localRef;\n    }\n\n    T get() const { return local_ref_; }\n\n    JArrayUnderlyingType<T> &operator[](size_t index) {\n        modified_ = true;\n        return elements_[index];\n    }\n\n    const JArrayUnderlyingType<T> &operator[](size_t index) const { return elements_[index]; }\n\n    void commit() {\n        ReleaseElements(JNI_COMMIT);\n        modified_ = false;\n    }\n\n    // We do not expose an empty constructor as it can easily lead to errors\n    // using common idioms, e.g.:\n    //   ScopedLocalRef<...> ref;\n    //   ref.reset(...);\n    // Move assignment operator.\n    ScopedLocalRef &operator=(ScopedLocalRef &&s) noexcept {\n        env_ = s.env_;\n        local_ref_ = s.local_ref_;\n        size_ = s.size_;\n        elements_ = s.elements_;\n        modified_ = s.modified_;\n        s.elements_ = nullptr;\n        s.size_ = 0;\n        s.modified_ = false;\n        s.local_ref_ = nullptr;\n        return *this;\n    }\n\n    size_t size() const { return size_; }\n\n    operator bool() const { return local_ref_; }\n\n    template <JObject U>\n    friend class ScopedLocalRef;\n\n    friend class JUTFString;\n\nprivate:\n    void ReleaseElements(jint mode) {\n        if (!local_ref_ || !elements_) return;\n        if constexpr (std::is_same_v<T, jbooleanArray>) {\n            env_->ReleaseBooleanArrayElements(local_ref_, elements_, mode);\n        } else if constexpr (std::is_same_v<T, jbyteArray>) {\n            env_->ReleaseByteArrayElements(local_ref_, elements_, mode);\n        } else if constexpr (std::is_same_v<T, jcharArray>) {\n            env_->ReleaseCharArrayElements(local_ref_, elements_, mode);\n        } else if constexpr (std::is_same_v<T, jshortArray>) {\n            env_->ReleaseShortArrayElements(local_ref_, elements_, mode);\n        } else if constexpr (std::is_same_v<T, jintArray>) {\n            env_->ReleaseIntArrayElements(local_ref_, elements_, mode);\n        } else if constexpr (std::is_same_v<T, jlongArray>) {\n            env_->ReleaseLongArrayElements(local_ref_, elements_, mode);\n        } else if constexpr (std::is_same_v<T, jfloatArray>) {\n            env_->ReleaseFloatArrayElements(local_ref_, elements_, mode);\n        } else if constexpr (std::is_same_v<T, jdoubleArray>) {\n            env_->ReleaseDoubleArrayElements(local_ref_, elements_, mode);\n        }\n    }\n\n    JNIEnv *env_;\n    T local_ref_;\n    size_t size_;\n    JArrayUnderlyingType<T> *elements_{nullptr};\n    bool modified_ = false;\n    DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);\n};\n\nclass JObjectArrayElement {\n    friend class ScopedLocalRef<jobjectArray>;\n\n    auto obtain() {\n        if (i_ < 0 || i_ >= size_) return ScopedLocalRef<jobject>{nullptr};\n        return JNI_SafeInvoke(env_, &JNIEnv::GetObjectArrayElement, array_, i_);\n    }\n\n    explicit JObjectArrayElement(JNIEnv *env, jobjectArray array, int i, size_t size)\n        : env_(env), array_(array), i_(i), size_(size), item_(obtain()) {}\n\n    JObjectArrayElement &operator++() {\n        ++i_;\n        item_ = obtain();\n        return *this;\n    }\n\n    JObjectArrayElement &operator--() {\n        --i_;\n        item_ = obtain();\n        return *this;\n    }\n\n    JObjectArrayElement operator++(int) { return JObjectArrayElement(env_, array_, i_ + 1, size_); }\n\n    JObjectArrayElement operator--(int) { return JObjectArrayElement(env_, array_, i_ - 1, size_); }\n\npublic:\n    JObjectArrayElement(JObjectArrayElement &&s)\n        : env_(s.env_), array_(s.array_), i_(s.i_), size_(s.size_), item_(std::move(s.item_)) {}\n\n    operator ScopedLocalRef<jobject> &() & { return item_; }\n\n    operator ScopedLocalRef<jobject> &&() && { return std::move(item_); }\n\n    JObjectArrayElement &operator=(JObjectArrayElement &&s) {\n        reset(s.item_.release());\n        return *this;\n    }\n\n    JObjectArrayElement &operator=(const JObjectArrayElement &s) {\n        reset(env_->NewLocalRef(s.item_.get()));\n        return *this;\n    }\n\n    template<JObject T>\n    JObjectArrayElement &operator=(ScopedLocalRef<T> &&s) {\n        reset(s.release());\n        return *this;\n    }\n\n    template<JObject T>\n    JObjectArrayElement &operator=(const ScopedLocalRef<T> &s) {\n        reset(s.clone());\n        return *this;\n    }\n\n    JObjectArrayElement &operator=(jobject s) {\n        reset(env_->NewLocalRef(s));\n        return *this;\n    }\n\n    void reset(jobject item) {\n        item_.reset(item);\n        JNI_SafeInvoke(env_, &JNIEnv::SetObjectArrayElement, array_, i_, item_);\n    }\n\n    ScopedLocalRef<jobject> clone() const { return item_.clone(); }\n\n    jobject get() const { return item_.get(); }\n\n    jobject release() { return item_.release(); }\n\n    jobject operator->() const { return item_.get(); }\n\n    jobject operator*() const { return item_.get(); }\n\nprivate:\n    JNIEnv *env_;\n    jobjectArray array_;\n    int i_;\n    int size_;\n    ScopedLocalRef<jobject> item_;\n    JObjectArrayElement(const JObjectArrayElement &) = delete;\n};\n\ntemplate <>\nclass ScopedLocalRef<jobjectArray> {\npublic:\n    class Iterator {\n        friend class ScopedLocalRef<jobjectArray>;\n\n        Iterator(JObjectArrayElement &&e) : e_(std::move(e)) {}\n        Iterator(JNIEnv *env, jobjectArray array, int i, size_t size) : e_(env, array, i, size) {}\n\n    public:\n        auto &operator*() { return e_; }\n\n        auto *operator->() { return e_.get(); }\n\n        Iterator &operator++() {\n            ++e_;\n            return *this;\n        }\n\n        Iterator &operator--() {\n            --e_;\n            return *this;\n        }\n\n        Iterator operator++(int) { return Iterator(e_++); }\n\n        Iterator operator--(int) { return Iterator(e_--); }\n\n        bool operator==(const Iterator &other) const { return other.e_.i_ == e_.i_; }\n\n        bool operator!=(const Iterator &other) const { return other.e_.i_ != e_.i_; }\n\n    private:\n        JObjectArrayElement e_;\n    };\n\n    class ConstIterator {\n        friend class ScopedLocalRef<jobjectArray>;\n\n        auto obtain() {\n            if (i_ < 0 || i_ >= size_) return ScopedLocalRef<jobject>{nullptr};\n            return JNI_SafeInvoke(env_, &JNIEnv::GetObjectArrayElement, array_, i_);\n        }\n\n        ConstIterator(JNIEnv *env, jobjectArray array, int i, int size)\n            : env_(env), array_(array), i_(i), size_(size), item_(obtain()) {}\n\n    public:\n        auto &operator*() { return item_; }\n\n        auto *operator->() { return &item_; }\n\n        ConstIterator &operator++() {\n            ++i_;\n            item_ = obtain();\n            return *this;\n        }\n\n        ConstIterator &operator--() {\n            --i_;\n            item_ = obtain();\n            return *this;\n        }\n\n        ConstIterator operator++(int) { return ConstIterator(env_, array_, i_ + 1, size_); }\n\n        ConstIterator operator--(int) { return ConstIterator(env_, array_, i_ - 1, size_); }\n\n        bool operator==(const ConstIterator &other) const { return other.i_ == i_; }\n\n        bool operator!=(const ConstIterator &other) const { return other.i_ != i_; }\n\n    private:\n        JNIEnv *env_;\n        jobjectArray array_;\n        int i_;\n        int size_;\n        ScopedLocalRef<jobject> item_;\n    };\n\n    auto begin() { return Iterator(env_, local_ref_, 0, size_); }\n\n    auto end() { return Iterator(env_, local_ref_, size_, size_); }\n\n    const auto begin() const { return ConstIterator(env_, local_ref_, 0, size_); }\n\n    auto end() const { return ConstIterator(env_, local_ref_, size_, size_); }\n\n    const auto cbegin() const { return ConstIterator(env_, local_ref_, 0, size_); }\n\n    auto cend() const { return ConstIterator(env_, local_ref_, size_, size_); }\n\n    ScopedLocalRef(JNIEnv *env, jobjectArray local_ref) noexcept : env_(env), local_ref_(nullptr) {\n        reset(local_ref);\n    }\n\n    ScopedLocalRef(ScopedLocalRef &&s) noexcept { *this = std::move(s); }\n\n    template <JObject U>\n    ScopedLocalRef(ScopedLocalRef<U> &&s) noexcept\n        : ScopedLocalRef(s.env_, (jobjectArray)s.release()) {}\n\n    explicit ScopedLocalRef(JNIEnv *env) noexcept : ScopedLocalRef(env, jobjectArray{nullptr}) {}\n\n    ~ScopedLocalRef() { env_->DeleteLocalRef(release()); }\n\n    void reset(jobjectArray ptr = nullptr) {\n        if (ptr != local_ref_) {\n            if (local_ref_ != nullptr) {\n                env_->DeleteLocalRef(local_ref_);\n            }\n            local_ref_ = ptr;\n            size_ = local_ref_ ? env_->GetArrayLength(local_ref_) : 0;\n            if (!local_ref_) return;\n        }\n    }\n\n    [[nodiscard]] jobjectArray release() {\n        jobjectArray localRef = local_ref_;\n        size_ = 0;\n        local_ref_ = nullptr;\n        return localRef;\n    }\n\n    jobjectArray get() const { return local_ref_; }\n\n    JObjectArrayElement operator[](size_t index) {\n        return JObjectArrayElement(env_, local_ref_, index, size_);\n    }\n\n    const ScopedLocalRef<jobject> operator[](size_t index) const {\n        return JNI_SafeInvoke(env_, &JNIEnv::GetObjectArrayElement, local_ref_, index);\n    }\n\n    // We do not expose an empty constructor as it can easily lead to errors\n    // using common idioms, e.g.:\n    //   ScopedLocalRef<...> ref;\n    //   ref.reset(...);\n    // Move assignment operator.\n    ScopedLocalRef &operator=(ScopedLocalRef &&s) noexcept {\n        env_ = s.env_;\n        local_ref_ = s.local_ref_;\n        size_ = s.size_;\n        s.size_ = 0;\n        s.local_ref_ = nullptr;\n        return *this;\n    }\n\n    size_t size() const { return size_; }\n\n    operator bool() const { return local_ref_; }\n\n    template <JObject U>\n    friend class ScopedLocalRef;\n\n    friend class JUTFString;\n\nprivate:\n    JNIEnv *env_;\n    jobjectArray local_ref_;\n    size_t size_;\n    DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);\n};\n// functions to array\n\ntemplate <ScopeOrRaw<jarray> Array>\n[[maybe_unused]] inline auto JNI_GetArrayLength(JNIEnv *env, const Array &array) {\n    return JNI_SafeInvoke(env, &JNIEnv::GetArrayLength, array);\n}\n\n// newers\n\ntemplate <ScopeOrClass Class, ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_NewObjectArray(JNIEnv *env, jsize len, Class &&clazz,\n                                                const Object &init) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewObjectArray, len, std::forward<Class>(clazz), init);\n}\n\n[[maybe_unused]] inline auto JNI_NewBooleanArray(JNIEnv *env, jsize len) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewBooleanArray, len);\n}\n\n[[maybe_unused]] inline auto JNI_NewByteArray(JNIEnv *env, jsize len) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewByteArray, len);\n}\n\n[[maybe_unused]] inline auto JNI_NewCharArray(JNIEnv *env, jsize len) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewCharArray, len);\n}\n\n[[maybe_unused]] inline auto JNI_NewShortArray(JNIEnv *env, jsize len) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewShortArray, len);\n}\n\n[[maybe_unused]] inline auto JNI_NewIntArray(JNIEnv *env, jsize len) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewIntArray, len);\n}\n\n[[maybe_unused]] inline auto JNI_NewLongArray(JNIEnv *env, jsize len) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewLongArray, len);\n}\n\n[[maybe_unused]] inline auto JNI_NewFloatArray(JNIEnv *env, jsize len) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewFloatArray, len);\n}\n\n[[maybe_unused]] inline auto JNI_NewDoubleArray(JNIEnv *env, jsize len) {\n    return JNI_SafeInvoke(env, &JNIEnv::NewDoubleArray, len);\n}\n\ntemplate <ScopeOrObject Object>\n[[maybe_unused]] inline auto JNI_GetObjectFieldOf(JNIEnv *env, Object &&object,\n                                                  std::string_view field_name,\n                                                  std::string_view field_class) {\n    auto &&o = std::forward<Object>(object);\n    return JNI_GetObjectField(\n        env, o, JNI_GetFieldID(env, JNI_GetObjectClass(env, o), field_name, field_class));\n}\n\n}  // namespace lsplant\n\n#undef DISALLOW_COPY_AND_ASSIGN\n\n#pragma clang diagnostic pop\n"
  },
  {
    "path": "app/src/main/cpp/supercall.h",
    "content": "/* SPDX-License-Identifier: GPL-2.0-or-later */\n/* \n * Copyright (C) 2023 bmax121. All Rights Reserved.\n */\n\n#ifndef _KPU_SUPERCALL_H_\n#define _KPU_SUPERCALL_H_\n\n#include <unistd.h>\n#include <sys/syscall.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n#include <errno.h>\n\n#include \"uapi/scdefs.h\"\n#include \"version\"\n\n/// KernelPatch version is greater than or equal to 0x0a05\nstatic inline long ver_and_cmd(const char *key, long cmd)\n{\n    uint32_t version_code = (MAJOR << 16) + (MINOR << 8) + PATCH;\n    return ((long)version_code << 32) | (0x1158 << 16) | (cmd & 0xFFFF);\n}\n\n/**\n * @brief If KernelPatch installed, @see SUPERCALL_HELLO_ECHO will echoed.\n * \n * @param key : superkey or 'su' string if caller uid is su allowed \n * @return long \n */\nstatic inline long sc_hello(const char *key)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_HELLO));\n    return ret;\n}\n\n/**\n * @brief Is KernelPatch installed?\n * \n * @param key : superkey or 'su' string if caller uid is su allowed \n * @return true \n * @return false \n */\nstatic inline bool sc_ready(const char *key)\n{\n    return sc_hello(key) == SUPERCALL_HELLO_MAGIC;\n}\n\n/**\n * @brief Print messages by printk in the kernel\n * \n * @param key : superkey or 'su' string if caller uid is su allowed \n * @param msg \n * @return long \n */\nstatic inline long sc_klog(const char *key, const char *msg)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!msg || strlen(msg) <= 0) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KLOG), msg);\n    return ret;\n}\n\n/**\n * @brief Print build kernel time\n * \n * @param key : superkey or 'su' string if caller uid is su allowed \n * @param buildtime \n * @param timestamp\n * @return long \n */\n static inline long sc_get_build_time(const char *key, const char *buildtime, size_t len)\n {\n     if (!key || !key[0]) return -EINVAL;\n     if (!buildtime) return -EINVAL;\n     long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_BUILD_TIME), buildtime,len);\n     return ret;\n }\n\n/**\n * @brief KernelPatch version number\n * \n * @param key \n * @return uint32_t \n */\nstatic inline uint32_t sc_kp_ver(const char *key)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KERNELPATCH_VER));\n    return (uint32_t)ret;\n}\n\n/**\n * @brief Kernel version number\n * \n * @param key : superkey or 'su' string if caller uid is su allowed \n * @return uint32_t \n */\nstatic inline uint32_t sc_k_ver(const char *key)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KERNEL_VER));\n    return (uint32_t)ret;\n}\n\n/**\n * @brief Substitute user of current thread\n * \n * @param key : superkey or 'su' string if caller uid is su allowed \n * @param profile : if scontext is invalid or illegal, all selinux permission checks will bypass via hook\n * @see struct su_profile\n * @return long : 0 if succeed\n */\nstatic inline long sc_su(const char *key, struct su_profile *profile)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (strlen(profile->scontext) >= SUPERCALL_SCONTEXT_LEN) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU), profile);\n    return ret;\n}\n\n/**\n * @brief Substitute user of tid specfied thread\n * \n * @param key : superkey or 'su' string if caller uid is su allowed \n * @param tid : target thread id\n * @param profile : if scontext is invalid or illegal, all selinux permission checks will bypass via hook\n * @see struct su_profile\n * @return long : 0 if succeed \n */\nstatic inline long sc_su_task(const char *key, pid_t tid, struct su_profile *profile)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_TASK), tid, profile);\n    return ret;\n}\n\n/**\n * @brief \n * \n * @param key \n * @param gid group id\n * @param did data id\n * @param data \n * @param dlen \n * @return long \n */\nstatic inline long sc_kstorage_write(const char *key, int gid, long did, void *data, int offset, int dlen)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_WRITE), gid, did, data, (((long)offset << 32) | dlen));\n    return ret;\n}\n\n/**\n * @brief \n * \n * @param key \n * @param gid \n * @param did \n * @param out_data \n * @param dlen \n * @return long \n */\nstatic inline long sc_kstorage_read(const char *key, int gid, long did, void *out_data, int offset, int dlen)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_READ), gid, did, out_data, (((long)offset << 32) | dlen));\n    return ret;\n}\n\n\n/**\n * @brief \n * \n * @param key \n * @param gid \n * @param ids \n * @param ids_len \n * @return long numbers of listed ids\n */\nstatic inline long sc_kstorage_list_ids(const char *key, int gid, long *ids, int ids_len)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_LIST_IDS), gid, ids, ids_len);\n    return ret;\n}\n\n\n/**\n * @brief \n * \n * @param key \n * @param gid \n * @param did \n * @return long \n */\nstatic inline long sc_kstorage_remove(const char *key, int gid, long did)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KSTORAGE_REMOVE), gid, did);\n    return ret;\n}\n\n#ifdef ANDROID\n/**\n * @brief \n * \n * @param key \n * @param uid \n * @param exclude \n * @return long \n */\nstatic inline long sc_set_ap_mod_exclude(const char *key, uid_t uid, int exclude)\n{\n    if(exclude) {\n        return sc_kstorage_write(key, KSTORAGE_EXCLUDE_LIST_GROUP, uid, &exclude, 0, sizeof(exclude));\n    } else {\n        return sc_kstorage_remove(key, KSTORAGE_EXCLUDE_LIST_GROUP, uid);\n    }\n}\n\n\n/**\n * @brief \n * \n * @param key \n * @param uid \n * @param exclude \n * @return long \n */\nstatic inline int sc_get_ap_mod_exclude(const char *key, uid_t uid)\n{\n    int exclude = 0;\n    int rc = sc_kstorage_read(key, KSTORAGE_EXCLUDE_LIST_GROUP, uid, &exclude, 0, sizeof(exclude));\n    if (rc < 0) return 0;\n    return exclude;\n}\n\n/**\n *\n */\nstatic inline int sc_list_ap_mod_exclude(const char *key, uid_t *uids, int uids_len)\n{\n    if(uids_len < 0 || uids_len > 512) return -E2BIG;\n    long ids[uids_len];\n    int rc = sc_kstorage_list_ids(key, KSTORAGE_EXCLUDE_LIST_GROUP, ids, uids_len);\n    if (rc < 0) return 0;\n    for(int i = 0; i < rc; i ++) {\n        uids[i] = (uid_t)ids[i];\n    }\n    return rc;\n}\n\n#endif\n\n/**\n * @brief Grant su permission\n * \n * @param key \n * @param profile : if scontext is invalid or illegal, all selinux permission checks will bypass via hook\n * @return long : 0 if succeed\n */\nstatic inline long sc_su_grant_uid(const char *key, struct su_profile *profile)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_GRANT_UID), profile);\n    return ret;\n}\n\n/**\n * @brief Revoke su permission\n * \n * @param key \n * @param uid \n * @return long 0 if succeed\n */\nstatic inline long sc_su_revoke_uid(const char *key, uid_t uid)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_REVOKE_UID), uid);\n    return ret;\n}\n\n/**\n * @brief Get numbers of su allowed uids\n * \n * @param key \n * @return long \n */\nstatic inline long sc_su_uid_nums(const char *key)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_NUMS));\n    return ret;\n}\n\n/**\n * @brief \n * \n * @param key : superkey or 'su' string if caller uid is su allowed \n * @param buf \n * @param num \n * @return long : The numbers of uids if succeed, nagative value if failed\n */\nstatic inline long sc_su_allow_uids(const char *key, uid_t *buf, int num)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!buf || num <= 0) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_LIST), buf, num);\n    return ret;\n}\n\n/**\n * @brief Get su profile of specified uid\n * \n * @param key \n * @param uid \n * @param out_profile \n * @return long : 0 if succeed\n */\nstatic inline long sc_su_uid_profile(const char *key, uid_t uid, struct su_profile *out_profile)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_PROFILE), uid, out_profile);\n    return ret;\n}\n\n/**\n * @brief Get full path of current 'su' command \n * \n * @param key : superkey or 'su' string if caller uid is su allowed \n * @param out_path \n * @param path_len \n * @return long : The length of result string if succeed, negative if failed\n */\nstatic inline long sc_su_get_path(const char *key, char *out_path, int path_len)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!out_path || path_len <= 0) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_GET_PATH), out_path, path_len);\n    return ret;\n}\n\n/**\n * @brief Reset full path of 'su' command \n * \n * @param key \n * @param path \n * @return long : 0 if succeed\n */\nstatic inline long sc_su_reset_path(const char *key, const char *path)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!path || !path[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_RESET_PATH), path);\n    return ret;\n}\n\n/**\n * @brief Get current all-allowed selinux context\n * \n * @param key : superkey or 'su' string if caller uid is su allowed  \n * @param out_sctx \n * @param sctx_len\n * @return long 0 if there is a all-allowed selinux context now\n */\nstatic inline long sc_su_get_all_allow_sctx(const char *key, char *out_sctx, int sctx_len)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!out_sctx) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_GET_ALLOW_SCTX), out_sctx);\n    return ret;\n}\n\n/**\n * @brief Reset current all-allowed selinux context\n * \n * @param key : superkey or 'su' string if caller uid is su allowed  \n * @param sctx If sctx is empty string, clear all-allowed selinux, \n * otherwise, try to reset a new all-allowed selinux context\n * @return long 0 if succeed\n */\nstatic inline long sc_su_reset_all_allow_sctx(const char *key, const char *sctx)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!sctx) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_SET_ALLOW_SCTX), sctx);\n    return ret;\n}\n\n/**\n * @brief Load module\n * \n * @param key : superkey\n * @param path \n * @param args \n * @param reserved \n * @return long : 0 if succeed\n */\nstatic inline long sc_kpm_load(const char *key, const char *path, const char *args, void *reserved)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!path || strlen(path) <= 0) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_LOAD), path, args, reserved);\n    return ret;\n}\n\n/**\n * @brief Control module with arguments \n * \n * @param key : superkey\n * @param name : module name\n * @param ctl_args : control argument\n * @param out_msg : output message buffer\n * @param outlen : buffer length of out_msg\n * @return long : 0 if succeed\n */\nstatic inline long sc_kpm_control(const char *key, const char *name, const char *ctl_args, char *out_msg, long outlen)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!name || strlen(name) <= 0) return -EINVAL;\n    if (!ctl_args || strlen(ctl_args) <= 0) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_CONTROL), name, ctl_args, out_msg, outlen);\n    return ret;\n}\n\n/**\n * @brief Unload module\n * \n * @param key : superkey\n * @param name : module name\n * @param reserved \n * @return long : 0 if succeed\n */\nstatic inline long sc_kpm_unload(const char *key, const char *name, void *reserved)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!name || strlen(name) <= 0) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_UNLOAD), name, reserved);\n    return ret;\n}\n\n/**\n * @brief Current loaded module numbers\n * \n * @param key : superkey\n * @return long\n */\nstatic inline long sc_kpm_nums(const char *key)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_NUMS));\n    return ret;\n}\n\n/**\n * @brief List names of current loaded modules, splited with '\\n'\n * \n * @param key : superkey\n * @param names_buf : output buffer\n * @param buf_len : the length of names_buf\n * @return long : the length of result string if succeed, negative if failed\n */\nstatic inline long sc_kpm_list(const char *key, char *names_buf, int buf_len)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!names_buf || buf_len <= 0) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_LIST), names_buf, buf_len);\n    return ret;\n}\n\n/**\n * @brief Get module information. \n * \n * @param key : superkey\n * @param name : module name\n * @param buf : \n * @param buf_len : \n * @return long : The length of result string if succeed, negative if failed\n */\nstatic inline long sc_kpm_info(const char *key, const char *name, char *buf, int buf_len)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!buf || buf_len <= 0) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_KPM_INFO), name, buf, buf_len);\n    return ret;\n}\n\n/**\n * @brief Get current superkey\n * \n * @param key : superkey\n * @param out_key \n * @param outlen \n * @return long : 0 if succeed\n */\nstatic inline long sc_skey_get(const char *key, char *out_key, int outlen)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (outlen < SUPERCALL_KEY_MAX_LEN) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SKEY_GET), out_key, outlen);\n    return ret;\n}\n\n/**\n * @brief Reset current superkey\n * \n * @param key : superkey\n * @param new_key \n * @return long : 0 if succeed\n */\nstatic inline long sc_skey_set(const char *key, const char *new_key)\n{\n    if (!key || !key[0]) return -EINVAL;\n    if (!new_key || !new_key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SKEY_SET), new_key);\n    return ret;\n}\n\n/**\n * @brief Whether to enable hash verification for root superkey.\n * \n * @param key : superkey\n * @param enable \n * @return long \n */\nstatic inline long sc_skey_root_enable(const char *key, bool enable)\n{\n    if (!key || !key[0]) return -EINVAL;\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SKEY_ROOT_ENABLE), (long)enable);\n    return ret;\n}\n\n/**\n * @brief Get whether in safe mode\n *\n * @param key\n * @return long\n */\nstatic inline long sc_su_get_safemode(const char *key)\n{\n    if (!key || !key[0]) return -EINVAL;\n    return syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_SU_GET_SAFEMODE));\n}\n\n\nstatic inline long sc_bootlog(const char *key)\n{\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_BOOTLOG));\n    return ret;\n}\n\nstatic inline long sc_panic(const char *key)\n{\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_PANIC));\n    return ret;\n}\n\nstatic inline long __sc_test(const char *key, long a1, long a2, long a3)\n{\n    long ret = syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_TEST), a1, a2, a3);\n    return ret;\n}\n\n#endif"
  },
  {
    "path": "app/src/main/cpp/type_traits.hpp",
    "content": "#pragma once\n\n#include <type_traits>\n\nnamespace lsplant {\ntemplate <class, template <class, class...> class>\nstruct is_instance : public std::false_type {};\n\ntemplate <class... Ts, template <class, class...> class U>\nstruct is_instance<U<Ts...>, U> : public std::true_type {};\n\ntemplate <class T, template <class, class...> class U>\ninline constexpr bool is_instance_v = is_instance<T, U>::value;\n}  // namespace lsplant\n"
  },
  {
    "path": "app/src/main/cpp/uapi/scdefs.h",
    "content": "/* SPDX-License-Identifier: GPL-2.0-or-later */\n/* \n * Copyright (C) 2023 bmax121. All Rights Reserved.\n */\n\n#ifndef _KP_UAPI_SCDEF_H_\n#define _KP_UAPI_SCDEF_H_\n\nstatic inline long hash_key(const char *key)\n{\n    long hash = 1000000007;\n    for (int i = 0; key[i]; i++) {\n        hash = hash * 31 + key[i];\n    }\n    return hash;\n}\n\n#define SUPERCALL_HELLO_ECHO \"hello1158\"\n\n// #define __NR_supercall __NR3264_truncate // 45\n#define __NR_supercall 45\n\n#define SUPERCALL_HELLO 0x1000\n#define SUPERCALL_KLOG 0x1004\n\n#define SUPERCALL_BUILD_TIME 0x1007\n#define SUPERCALL_KERNELPATCH_VER 0x1008\n#define SUPERCALL_KERNEL_VER 0x1009\n\n#define SUPERCALL_SKEY_GET 0x100a\n#define SUPERCALL_SKEY_SET 0x100b\n#define SUPERCALL_SKEY_ROOT_ENABLE 0x100c\n\n#define SUPERCALL_SU 0x1010\n#define SUPERCALL_SU_TASK 0x1011 // syscall(__NR_gettid)\n\n#define SUPERCALL_KPM_LOAD 0x1020\n#define SUPERCALL_KPM_UNLOAD 0x1021\n#define SUPERCALL_KPM_CONTROL 0x1022\n\n#define SUPERCALL_KPM_NUMS 0x1030\n#define SUPERCALL_KPM_LIST 0x1031\n#define SUPERCALL_KPM_INFO 0x1032\n\nstruct kernel_storage\n{\n    void *data;\n    int len;\n};\n\n#define SUPERCALL_KSTORAGE_ALLOC_GROUP 0x1040\n#define SUPERCALL_KSTORAGE_WRITE 0x1041\n#define SUPERCALL_KSTORAGE_READ 0x1042\n#define SUPERCALL_KSTORAGE_LIST_IDS 0x1043\n#define SUPERCALL_KSTORAGE_REMOVE 0x1044\n#define SUPERCALL_KSTORAGE_REMOVE_GROUP 0x1045\n\n#define KSTORAGE_SU_LIST_GROUP 0\n#define KSTORAGE_EXCLUDE_LIST_GROUP 1\n#define KSTORAGE_UNUSED_GROUP_2 2\n#define KSTORAGE_UNUSED_GROUP_3 3\n\n#define SUPERCALL_BOOTLOG 0x10fd\n#define SUPERCALL_PANIC 0x10fe\n#define SUPERCALL_TEST 0x10ff\n\n#define SUPERCALL_KEY_MAX_LEN 0x40\n#define SUPERCALL_SCONTEXT_LEN 0x60\n\nstruct su_profile\n{\n    uid_t uid;\n    uid_t to_uid;\n    char scontext[SUPERCALL_SCONTEXT_LEN];\n};\n\n#ifdef ANDROID\n#define SH_PATH \"/system/bin/sh\"\n#define SU_PATH \"/system/bin/kp\"\n#define LEGACY_SU_PATH \"/system/bin/su\"\n#define ECHO_PATH \"/system/bin/echo\"\n#define KERNELPATCH_DATA_DIR \"/data/adb/kp\"\n#define KERNELPATCH_MODULE_DATA_DIR KERNELPATCH_DATA_DIR \"/modules\"\n#define APD_PATH \"/data/adb/apd\"\n#define ALL_ALLOW_SCONTEXT \"u:r:kp:s0\"\n#define ALL_ALLOW_SCONTEXT_MAGISK \"u:r:magisk:s0\"\n#define ALL_ALLOW_SCONTEXT_KERNEL \"u:r:kernel:s0\"\n#else\n#define SH_PATH \"/usr/bin/sh\"\n#define ECHO_PATH \"/usr/bin/echo\"\n#define SU_PATH \"/usr/bin/kp\"\n#define ALL_ALLOW_SCONTEXT \"u:r:kernel:s0\"\n#endif\n\n#define SU_PATH_MAX_LEN 128\n\n#define SUPERCMD \"/system/bin/truncate\"\n\n#define SAFE_MODE_FLAG_FILE \"/dev/.safemode\"\n\n#define SUPERCALL_SU_GRANT_UID 0x1100\n#define SUPERCALL_SU_REVOKE_UID 0x1101\n#define SUPERCALL_SU_NUMS 0x1102\n#define SUPERCALL_SU_LIST 0x1103\n#define SUPERCALL_SU_PROFILE 0x1104\n#define SUPERCALL_SU_GET_ALLOW_SCTX 0x1105\n#define SUPERCALL_SU_SET_ALLOW_SCTX 0x1106\n#define SUPERCALL_SU_GET_PATH 0x1110\n#define SUPERCALL_SU_RESET_PATH 0x1111\n#define SUPERCALL_SU_GET_SAFEMODE 0x1112\n\n#define SUPERCALL_MAX 0x1200\n\n#define SUPERCALL_RES_SUCCEED 0\n\n#define SUPERCALL_HELLO_MAGIC 0x11581158\n\n#endif\n"
  },
  {
    "path": "app/src/main/cpp/version",
    "content": "#define MAJOR 0\n#define MINOR 13\n#define PATCH 0\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/APatchApp.kt",
    "content": "package me.bmax.apatch\n\nimport android.app.Application\nimport android.content.Context\nimport android.content.Intent\nimport android.content.SharedPreferences\nimport android.os.Build\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.core.content.edit\nimport androidx.core.net.toUri\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport com.topjohnwu.superuser.CallbackList\nimport me.bmax.apatch.ui.CrashHandleActivity\nimport me.bmax.apatch.util.APatchCli\nimport me.bmax.apatch.util.APatchKeyHelper\nimport me.bmax.apatch.util.Version\nimport me.bmax.apatch.util.getRootShell\nimport me.bmax.apatch.util.rootShellForResult\nimport me.bmax.apatch.util.verifyAppSignature\nimport okhttp3.Cache\nimport okhttp3.OkHttpClient\nimport java.io.File\nimport java.util.Locale\nimport kotlin.concurrent.thread\nimport kotlin.system.exitProcess\n\nlateinit var apApp: APApplication\n\nconst val TAG = \"APatch\"\n\nclass APApplication : Application(), Thread.UncaughtExceptionHandler {\n    lateinit var okhttpClient: OkHttpClient\n\n    init {\n        Thread.setDefaultUncaughtExceptionHandler(this)\n    }\n\n    enum class State {\n        UNKNOWN_STATE,\n\n        KERNELPATCH_INSTALLED, KERNELPATCH_NEED_UPDATE, KERNELPATCH_NEED_REBOOT, KERNELPATCH_UNINSTALLING,\n\n        ANDROIDPATCH_NOT_INSTALLED, ANDROIDPATCH_INSTALLED, ANDROIDPATCH_INSTALLING, ANDROIDPATCH_NEED_UPDATE, ANDROIDPATCH_UNINSTALLING,\n    }\n\n\n    companion object {\n        const val APD_PATH = \"/data/adb/apd\"\n\n        @Deprecated(\"No more KPatch ELF from 0.11.0-dev\")\n        const val KPATCH_PATH = \"/data/adb/kpatch\"\n        const val SUPERCMD = \"/system/bin/truncate\"\n        const val APATCH_FOLDER = \"/data/adb/ap/\"\n        private const val APATCH_BIN_FOLDER = APATCH_FOLDER + \"bin/\"\n        private const val APATCH_LOG_FOLDER = APATCH_FOLDER + \"log/\"\n        private const val APD_LINK_PATH = APATCH_BIN_FOLDER + \"apd\"\n        const val PACKAGE_CONFIG_FILE = APATCH_FOLDER + \"package_config\"\n        const val SU_PATH_FILE = APATCH_FOLDER + \"su_path\"\n        const val SAFEMODE_FILE = \"/dev/.safemode\"\n        private const val NEED_REBOOT_FILE = \"/dev/.need_reboot\"\n        const val GLOBAL_NAMESPACE_FILE = \"/data/adb/.global_namespace_enable\"\n        const val KPMS_DIR = APATCH_FOLDER + \"kpms/\"\n\n        @Deprecated(\"Use 'apd -V'\")\n        const val APATCH_VERSION_PATH = APATCH_FOLDER + \"version\"\n        private const val MAGISKPOLICY_BIN_PATH = APATCH_BIN_FOLDER + \"magiskpolicy\"\n        private const val BUSYBOX_BIN_PATH = APATCH_BIN_FOLDER + \"busybox\"\n        private const val RESETPROP_BIN_PATH = APATCH_BIN_FOLDER + \"resetprop\"\n        private const val KPTOOLS_BIN_PATH = APATCH_BIN_FOLDER + \"kptools\"\n        const val DEFAULT_SCONTEXT = \"u:r:untrusted_app:s0\"\n        const val MAGISK_SCONTEXT = \"u:r:magisk:s0\"\n\n        private const val DEFAULT_SU_PATH = \"/system/bin/kp\"\n        private const val LEGACY_SU_PATH = \"/system/bin/su\"\n\n        const val SP_NAME = \"config\"\n        private const val SHOW_BACKUP_WARN = \"show_backup_warning\"\n        lateinit var sharedPreferences: SharedPreferences\n\n        private val logCallback: CallbackList<String?> = object : CallbackList<String?>() {\n            override fun onAddElement(s: String?) {\n                Log.d(TAG, s.toString())\n            }\n        }\n\n        private val _kpStateLiveData = MutableLiveData(State.UNKNOWN_STATE)\n        val kpStateLiveData: LiveData<State> = _kpStateLiveData\n\n        private val _apStateLiveData = MutableLiveData(State.UNKNOWN_STATE)\n        val apStateLiveData: LiveData<State> = _apStateLiveData\n\n        @Suppress(\"DEPRECATION\")\n        fun uninstallApatch() {\n            if (_apStateLiveData.value != State.ANDROIDPATCH_INSTALLED) return\n            _apStateLiveData.value = State.ANDROIDPATCH_UNINSTALLING\n\n            Natives.resetSuPath(DEFAULT_SU_PATH)\n\n            val cmds = arrayOf(\n                \"rm -f $APD_PATH\",\n                \"rm -f $KPATCH_PATH\",\n                \"rm -rf $APATCH_BIN_FOLDER\",\n                \"rm -rf $APATCH_LOG_FOLDER\",\n                \"rm -rf $APATCH_VERSION_PATH\",\n            )\n\n            val shell = getRootShell()\n            shell.newJob().add(*cmds).to(logCallback, logCallback).exec()\n\n            Log.d(TAG, \"APatch uninstalled...\")\n            if (_kpStateLiveData.value == State.UNKNOWN_STATE) {\n                _apStateLiveData.postValue(State.UNKNOWN_STATE)\n            } else {\n                _apStateLiveData.postValue(State.ANDROIDPATCH_NOT_INSTALLED)\n            }\n        }\n\n        @Suppress(\"DEPRECATION\")\n        fun installApatch() {\n            val state = _apStateLiveData.value\n            if (state != State.ANDROIDPATCH_NOT_INSTALLED && state != State.ANDROIDPATCH_NEED_UPDATE) {\n                return\n            }\n            _apStateLiveData.value = State.ANDROIDPATCH_INSTALLING\n            val nativeDir = apApp.applicationInfo.nativeLibraryDir\n\n            Natives.resetSuPath(LEGACY_SU_PATH)\n\n            val cmds = arrayOf(\n                \"mkdir -p $APATCH_BIN_FOLDER\",\n                \"mkdir -p $APATCH_LOG_FOLDER\",\n\n                \"cp -f ${nativeDir}/libapd.so $APD_PATH\",\n                \"chmod +x $APD_PATH\",\n                \"ln -s $APD_PATH $APD_LINK_PATH\",\n                \"restorecon $APD_PATH\",\n\n                \"cp -f ${nativeDir}/libmagiskpolicy.so $MAGISKPOLICY_BIN_PATH\",\n                \"chmod +x $MAGISKPOLICY_BIN_PATH\",\n                \"cp -f ${nativeDir}/libresetprop.so $RESETPROP_BIN_PATH\",\n                \"chmod +x $RESETPROP_BIN_PATH\",\n                \"cp -f ${nativeDir}/libbusybox.so $BUSYBOX_BIN_PATH\",\n                \"chmod +x $BUSYBOX_BIN_PATH\",\n                \"cp -f ${nativeDir}/libkptools.so $KPTOOLS_BIN_PATH\",\n                \"chmod +x $KPTOOLS_BIN_PATH\",\n\n\n\n                \"touch $PACKAGE_CONFIG_FILE\",\n                \"touch $SU_PATH_FILE\",\n                \"[ -s $SU_PATH_FILE ] || echo $LEGACY_SU_PATH > $SU_PATH_FILE\",\n                \"echo ${Version.getManagerVersion().second} > $APATCH_VERSION_PATH\",\n                \"restorecon -R $APATCH_FOLDER\",\n\n                \"${nativeDir}/libmagiskpolicy.so --magisk --live\",\n            )\n\n            val shell = getRootShell()\n            shell.newJob().add(*cmds).to(logCallback, logCallback).exec()\n\n            // clear shell cache\n            APatchCli.refresh()\n\n            Log.d(TAG, \"APatch installed...\")\n            _apStateLiveData.postValue(State.ANDROIDPATCH_INSTALLED)\n        }\n\n        fun markNeedReboot() {\n            val result = rootShellForResult(\"touch $NEED_REBOOT_FILE\")\n            _kpStateLiveData.postValue(State.KERNELPATCH_NEED_REBOOT)\n            Log.d(TAG, \"mark reboot ${result.code}\")\n        }\n\n\n        var superKey: String = \"\"\n            set(value) {\n                field = value\n                val ready = Natives.nativeReady(value)\n                _kpStateLiveData.value =\n                    if (ready) State.KERNELPATCH_INSTALLED else State.UNKNOWN_STATE\n                _apStateLiveData.value =\n                    if (ready) State.ANDROIDPATCH_NOT_INSTALLED else State.UNKNOWN_STATE\n                Log.d(TAG, \"state: \" + _kpStateLiveData.value)\n                if (!ready) return\n\n                APatchKeyHelper.writeSPSuperKey(value)\n\n                thread {\n                    val rc = Natives.su(0, null)\n                    if (!rc) {\n                        Log.e(TAG, \"Native.su failed\")\n                        return@thread\n                    }\n\n                    // KernelPatch version\n                    //val buildV = Version.buildKPVUInt()\n                    //val installedV = Version.installedKPVUInt()\n                    //use build time to check update\n                    val buildV = Version.getKpImg()\n                    val installedV = Version.installedKPTime()\n\n\n                    Log.d(TAG, \"kp installed version: ${installedV}, build version: $buildV\")\n\n                    // use != instead of > to enable downgrade,\n                    if (buildV != installedV) {\n                        _kpStateLiveData.postValue(State.KERNELPATCH_NEED_UPDATE)\n                    }\n                    Log.d(TAG, \"kp state: \" + _kpStateLiveData.value)\n\n                    if (File(NEED_REBOOT_FILE).exists()) {\n                        _kpStateLiveData.postValue(State.KERNELPATCH_NEED_REBOOT)\n                    }\n                    Log.d(TAG, \"kp state: \" + _kpStateLiveData.value)\n\n                    // AndroidPatch version\n                    val mgv = Version.getManagerVersion().second\n                    val installedApdVInt = Version.installedApdVUInt()\n                    Log.d(TAG, \"manager version: $mgv, installed apd version: $installedApdVInt\")\n\n                    if (Version.installedApdVInt > 0) {\n                        _apStateLiveData.postValue(State.ANDROIDPATCH_INSTALLED)\n                    }\n\n                    if (Version.installedApdVInt > 0 && mgv.toInt() != Version.installedApdVInt) {\n                        _apStateLiveData.postValue(State.ANDROIDPATCH_NEED_UPDATE)\n                        // su path\n                        val suPathFile = File(SU_PATH_FILE)\n                        if (suPathFile.exists()) {\n                            val suPath = suPathFile.readLines()[0].trim()\n                            if (Natives.suPath() != suPath) {\n                                Log.d(TAG, \"su path: $suPath\")\n                                Natives.resetSuPath(suPath)\n                            }\n                        }\n                    }\n                    Log.d(TAG, \"ap state: \" + _apStateLiveData.value)\n\n                    return@thread\n                }\n            }\n    }\n\n    override fun onCreate() {\n        super.onCreate()\n        apApp = this\n\n        val isArm64 = Build.SUPPORTED_ABIS.any { it == \"arm64-v8a\" }\n        if (!isArm64) {\n            Toast.makeText(applicationContext, \"Unsupported architecture!\", Toast.LENGTH_LONG)\n                .show()\n            Thread.sleep(5000)\n            exitProcess(0)\n        }\n\n        if (!BuildConfig.DEBUG && !verifyAppSignature(\"1x2twMoHvfWUODv7KkRRNKBzOfEqJwRKGzJpgaz18xk=\")) {\n            while (true) {\n                val intent = Intent(Intent.ACTION_DELETE)\n                intent.data = \"package:$packageName\".toUri()\n                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)\n                startActivity(intent)\n                exitProcess(0)\n            }\n        }\n\n        // TODO: We can't totally protect superkey from be stolen by root or LSPosed-like injection tools in user space, the only way is don't use superkey,\n        // TODO: 1. make me root by kernel\n        // TODO: 2. remove all usage of superkey\n        sharedPreferences = getSharedPreferences(SP_NAME, Context.MODE_PRIVATE)\n        APatchKeyHelper.setSharedPreferences(sharedPreferences)\n        superKey = APatchKeyHelper.readSPSuperKey()\n\n        okhttpClient =\n            OkHttpClient.Builder().cache(Cache(File(cacheDir, \"okhttp\"), 10 * 1024 * 1024))\n                .addInterceptor { block ->\n                    block.proceed(\n                        block.request().newBuilder()\n                            .header(\"User-Agent\", \"APatch/${BuildConfig.VERSION_CODE}\")\n                            .header(\"Accept-Language\", Locale.getDefault().toLanguageTag()).build()\n                    )\n                }.build()\n    }\n\n    fun getBackupWarningState(): Boolean {\n        return sharedPreferences.getBoolean(SHOW_BACKUP_WARN, true)\n    }\n\n    fun updateBackupWarningState(state: Boolean) {\n        sharedPreferences.edit { putBoolean(SHOW_BACKUP_WARN, state) }\n    }\n\n    override fun uncaughtException(t: Thread, e: Throwable) {\n        val exceptionMessage = Log.getStackTraceString(e)\n        val threadName = t.name\n        Log.e(TAG, \"Error on thread $threadName:\\n $exceptionMessage\")\n        val intent = Intent(this, CrashHandleActivity::class.java).apply {\n            putExtra(\"exception_message\", exceptionMessage)\n            putExtra(\"thread\", threadName)\n            flags = Intent.FLAG_ACTIVITY_NEW_TASK\n        }\n        startActivity(intent)\n        exitProcess(10)\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/Natives.kt",
    "content": "package me.bmax.apatch\n\nimport android.os.Parcelable\nimport androidx.annotation.Keep\nimport androidx.compose.runtime.Immutable\nimport dalvik.annotation.optimization.FastNative\nimport kotlinx.parcelize.Parcelize\n\nobject Natives {\n    init {\n        System.loadLibrary(\"apjni\")\n    }\n\n    @Immutable\n    @Parcelize\n    @Keep\n    data class Profile(\n        var uid: Int = 0,\n        var toUid: Int = 0,\n        var scontext: String = APApplication.DEFAULT_SCONTEXT,\n    ) : Parcelable\n\n    @Keep\n    class KPMCtlRes {\n        var rc: Long = 0\n        var outMsg: String? = null\n\n        constructor()\n\n        constructor(rc: Long, outMsg: String?) {\n            this.rc = rc\n            this.outMsg = outMsg\n        }\n    }\n\n\n    @FastNative\n    private external fun nativeSu(superKey: String, toUid: Int, scontext: String?): Long\n\n    fun su(toUid: Int, scontext: String?): Boolean {\n        return nativeSu(APApplication.superKey, toUid, scontext) == 0L\n    }\n\n    fun su(): Boolean {\n        return su(0, \"\")\n    }\n\n    @FastNative\n    external fun nativeReady(superKey: String): Boolean\n\n    @FastNative\n    private external fun nativeSuPath(superKey: String): String\n\n    fun suPath(): String {\n        return nativeSuPath(APApplication.superKey)\n    }\n\n    @FastNative\n    private external fun nativeSuUids(superKey: String): IntArray\n\n    fun suUids(): IntArray {\n        return nativeSuUids(APApplication.superKey)\n    }\n\n    @FastNative\n    private external fun nativeKernelPatchVersion(superKey: String): Long\n    fun kernelPatchVersion(): Long {\n        return nativeKernelPatchVersion(APApplication.superKey)\n    }\n\n    @FastNative\n    private external fun nativeKernelPatchBuildTime(superKey: String): String\n    fun kernelPatchBuildTime(): String {\n        return nativeKernelPatchBuildTime(APApplication.superKey)\n    }\n\n    private external fun nativeLoadKernelPatchModule(\n        superKey: String, modulePath: String, args: String\n    ): Long\n\n    fun loadKernelPatchModule(modulePath: String, args: String): Long {\n        return nativeLoadKernelPatchModule(APApplication.superKey, modulePath, args)\n    }\n\n    private external fun nativeUnloadKernelPatchModule(superKey: String, moduleName: String): Long\n    fun unloadKernelPatchModule(moduleName: String): Long {\n        return nativeUnloadKernelPatchModule(APApplication.superKey, moduleName)\n    }\n\n    @FastNative\n    private external fun nativeKernelPatchModuleNum(superKey: String): Long\n\n    fun kernelPatchModuleNum(): Long {\n        return nativeKernelPatchModuleNum(APApplication.superKey)\n    }\n\n    @FastNative\n    private external fun nativeKernelPatchModuleList(superKey: String): String\n    fun kernelPatchModuleList(): String {\n        return nativeKernelPatchModuleList(APApplication.superKey)\n    }\n\n    @FastNative\n    private external fun nativeKernelPatchModuleInfo(superKey: String, moduleName: String): String\n    fun kernelPatchModuleInfo(moduleName: String): String {\n        return nativeKernelPatchModuleInfo(APApplication.superKey, moduleName)\n    }\n\n    private external fun nativeControlKernelPatchModule(\n        superKey: String, modName: String, jctlargs: String\n    ): KPMCtlRes\n\n    fun kernelPatchModuleControl(moduleName: String, controlArg: String): KPMCtlRes {\n        return nativeControlKernelPatchModule(APApplication.superKey, moduleName, controlArg)\n    }\n\n    @FastNative\n    private external fun nativeGrantSu(\n        superKey: String, uid: Int, toUid: Int, scontext: String?\n    ): Long\n\n    fun grantSu(uid: Int, toUid: Int, scontext: String?): Long {\n        return nativeGrantSu(APApplication.superKey, uid, toUid, scontext)\n    }\n\n    @FastNative\n    private external fun nativeRevokeSu(superKey: String, uid: Int): Long\n    fun revokeSu(uid: Int): Long {\n        return nativeRevokeSu(APApplication.superKey, uid)\n    }\n\n    @FastNative\n    private external fun nativeSetUidExclude(superKey: String, uid: Int, exclude: Int): Int\n    fun setUidExclude(uid: Int, exclude: Int): Int {\n        return nativeSetUidExclude(APApplication.superKey, uid, exclude)\n    }\n\n    @FastNative\n    private external fun nativeGetUidExclude(superKey: String, uid: Int): Int\n    fun isUidExcluded(uid: Int): Int {\n        return nativeGetUidExclude(APApplication.superKey, uid)\n    }\n\n    @FastNative\n    private external fun nativeSuProfile(superKey: String, uid: Int): Profile\n    fun suProfile(uid: Int): Profile {\n        return nativeSuProfile(APApplication.superKey, uid)\n    }\n\n    @FastNative\n    private external fun nativeResetSuPath(superKey: String, path: String): Boolean\n    fun resetSuPath(path: String): Boolean {\n        return nativeResetSuPath(APApplication.superKey, path)\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/services/RootServices.java",
    "content": "package me.bmax.apatch.services;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.IBinder;\nimport android.os.UserHandle;\nimport android.os.UserManager;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\n\nimport com.topjohnwu.superuser.ipc.RootService;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport me.bmax.apatch.IAPRootService;\nimport rikka.parcelablelist.ParcelableListSlice;\n\npublic class RootServices extends RootService {\n    private static final String TAG = \"RootServices\";\n\n    @Override\n    public IBinder onBind(@NonNull Intent intent) {\n        return new Stub();\n    }\n\n    List<Integer> getUserIds() {\n        List<Integer> result = new ArrayList<>();\n        UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);\n        List<UserHandle> userProfiles = um.getUserProfiles();\n        for (UserHandle userProfile : userProfiles) {\n            int userId = userProfile.hashCode();\n            result.add(userProfile.hashCode());\n        }\n        return result;\n    }\n\n    ArrayList<PackageInfo> getInstalledPackagesAll(int flags) {\n        ArrayList<PackageInfo> packages = new ArrayList<>();\n        for (Integer userId : getUserIds()) {\n            Log.i(TAG, \"getInstalledPackagesAll: \" + userId);\n            packages.addAll(getInstalledPackagesAsUser(flags, userId));\n        }\n        return packages;\n    }\n\n    List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {\n        try {\n            PackageManager pm = getPackageManager();\n            Method getInstalledPackagesAsUser = pm.getClass().getDeclaredMethod(\"getInstalledPackagesAsUser\", int.class, int.class);\n            return (List<PackageInfo>) getInstalledPackagesAsUser.invoke(pm, flags, userId);\n        } catch (Throwable e) {\n            Log.e(TAG, \"err\", e);\n        }\n\n        return new ArrayList<>();\n    }\n\n    class Stub extends IAPRootService.Stub {\n        @Override\n        public ParcelableListSlice<PackageInfo> getPackages(int flags) {\n            List<PackageInfo> list = getInstalledPackagesAll(flags);\n            Log.i(TAG, \"getPackages: \" + list.size());\n            return new ParcelableListSlice<>(list);\n        }\n\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/CrashHandleActivity.kt",
    "content": "package me.bmax.apatch.ui\n\nimport android.content.ClipData\nimport android.os.Build\nimport android.os.Bundle\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.activity.enableEdgeToEdge\nimport androidx.compose.foundation.layout.WindowInsets\nimport androidx.compose.foundation.layout.WindowInsetsSides\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.only\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.safeDrawing\nimport androidx.compose.foundation.layout.windowInsetsPadding\nimport androidx.compose.foundation.rememberScrollState\nimport androidx.compose.foundation.text.selection.SelectionContainer\nimport androidx.compose.foundation.verticalScroll\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.outlined.ContentCopy\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.ExtendedFloatingActionButton\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.LargeTopAppBar\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TopAppBarDefaults\nimport androidx.compose.material3.rememberTopAppBarState\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.input.nestedscroll.nestedScroll\nimport androidx.compose.ui.platform.ClipEntry\nimport androidx.compose.ui.platform.LocalClipboard\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.TextStyle\nimport androidx.compose.ui.text.font.FontFamily\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.unit.sp\nimport kotlinx.coroutines.launch\nimport me.bmax.apatch.BuildConfig\nimport me.bmax.apatch.R\nimport me.bmax.apatch.ui.theme.APatchTheme\nimport java.text.SimpleDateFormat\nimport java.util.Calendar\nimport java.util.Locale\n\nclass CrashHandleActivity : ComponentActivity() {\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n\n        enableEdgeToEdge()\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            window.isNavigationBarContrastEnforced = false\n        }\n\n        super.onCreate(savedInstanceState)\n\n        val appName = getString(R.string.app_name)\n        val versionName = BuildConfig.VERSION_NAME\n        val versionCode = BuildConfig.VERSION_CODE\n\n        val deviceBrand = Build.BRAND\n        val deviceModel = Build.MODEL\n        val sdkLevel = Build.VERSION.SDK_INT\n        val currentDateTime = Calendar.getInstance().time\n        val formatter = SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\", Locale.getDefault())\n        val formattedDateTime = formatter.format(currentDateTime)\n\n        val exceptionMessage = intent.getStringExtra(\"exception_message\")\n        val threadName = intent.getStringExtra(\"thread\")\n\n        val message = buildString {\n            append(appName).append(\" version: \").append(versionName).append(\" ($versionCode)\")\n                .append(\"\\n\\n\")\n            append(\"Brand: \").append(deviceBrand).append(\"\\n\")\n            append(\"Model: \").append(deviceModel).append(\"\\n\")\n            append(\"SDK Level: \").append(sdkLevel).append(\"\\n\")\n            append(\"Time: \").append(formattedDateTime).append(\"\\n\\n\")\n            append(\"Thread: \").append(threadName).append(\"\\n\")\n            append(\"Crash Info: \\n\").append(exceptionMessage)\n        }\n\n        setContent {\n            APatchTheme {\n                CrashHandleScreen(message)\n            }\n        }\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun CrashHandleScreen(\n    message: String\n) {\n    val scrollBehavior =\n        TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())\n    val clipboard = LocalClipboard.current\n    val scope = rememberCoroutineScope()\n\n    Scaffold(contentWindowInsets = WindowInsets.safeDrawing, topBar = {\n        LargeTopAppBar(\n            title = { Text(text = stringResource(R.string.crash_handle_title)) },\n            scrollBehavior = scrollBehavior,\n            windowInsets = WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)\n        )\n    }, floatingActionButton = {\n        ExtendedFloatingActionButton(\n            onClick = {\n            scope.launch {\n                clipboard.setClipEntry(\n                    ClipEntry(ClipData.newPlainText(\"CrashLog\", message)),\n                )\n            }\n        }, text = { Text(text = stringResource(R.string.crash_handle_copy)) }, icon = {\n            Icon(\n                imageVector = Icons.Outlined.ContentCopy, contentDescription = null\n            )\n        }, modifier = Modifier.windowInsetsPadding(\n            WindowInsets.safeDrawing.only(WindowInsetsSides.End)\n        )\n        )\n    }) {\n        SelectionContainer(\n            modifier = Modifier\n                .fillMaxSize()\n                .nestedScroll(scrollBehavior.nestedScrollConnection)\n                .verticalScroll(rememberScrollState())\n                .padding(it)\n                .padding(\n                    start = 16.dp, top = 16.dp, end = 16.dp, bottom = 16.dp + 56.dp + 16.dp\n                )\n        ) {\n            Text(\n                text = message, style = TextStyle(\n                    fontFamily = FontFamily.Monospace, fontSize = 11.sp\n                )\n            )\n        }\n    }\n}\n\n@Preview\n@Composable\nfun CrashHandleScreenPreview() {\n    APatchTheme {\n        CrashHandleScreen(\"Crash log here\")\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/MainActivity.kt",
    "content": "package me.bmax.apatch.ui\n\nimport android.annotation.SuppressLint\nimport android.content.res.Configuration\nimport android.os.Build\nimport android.os.Bundle\nimport androidx.activity.compose.setContent\nimport androidx.activity.enableEdgeToEdge\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.compose.animation.AnimatedContentTransitionScope\nimport androidx.compose.animation.Crossfade\nimport androidx.compose.animation.EnterTransition\nimport androidx.compose.animation.ExitTransition\nimport androidx.compose.animation.core.tween\nimport androidx.compose.animation.fadeIn\nimport androidx.compose.animation.fadeOut\nimport androidx.compose.animation.scaleOut\nimport androidx.compose.animation.slideInHorizontally\nimport androidx.compose.animation.slideOutHorizontally\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.WindowInsets\nimport androidx.compose.foundation.layout.WindowInsetsSides\nimport androidx.compose.foundation.layout.consumeWindowInsets\nimport androidx.compose.foundation.layout.fillMaxHeight\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.only\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.safeDrawing\nimport androidx.compose.foundation.layout.systemBars\nimport androidx.compose.foundation.layout.windowInsetsPadding\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.NavigationBar\nimport androidx.compose.material3.NavigationBarItem\nimport androidx.compose.material3.NavigationRail\nimport androidx.compose.material3.NavigationRailItem\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.SnackbarHostState\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.CompositionLocalProvider\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.livedata.observeAsState\nimport androidx.compose.runtime.remember\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.platform.LocalConfiguration\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.style.TextOverflow\nimport androidx.compose.ui.unit.dp\nimport androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen\nimport androidx.navigation.NavBackStackEntry\nimport androidx.navigation.NavHostController\nimport androidx.navigation.compose.rememberNavController\nimport coil.Coil\nimport coil.ImageLoader\nimport com.ramcosta.composedestinations.DestinationsNavHost\nimport com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationStyle\nimport com.ramcosta.composedestinations.generated.NavGraphs\nimport com.ramcosta.composedestinations.rememberNavHostEngine\nimport com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState\nimport com.ramcosta.composedestinations.utils.rememberDestinationsNavigator\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.ui.screen.BottomBarDestination\nimport me.bmax.apatch.ui.theme.APatchTheme\nimport me.bmax.apatch.ui.viewmodel.SuperUserViewModel\nimport me.bmax.apatch.util.ui.LocalSnackbarHost\nimport me.zhanghai.android.appiconloader.coil.AppIconFetcher\nimport me.zhanghai.android.appiconloader.coil.AppIconKeyer\n\nclass MainActivity : AppCompatActivity() {\n\n    private var isLoading = true\n\n    @SuppressLint(\"UnusedMaterial3ScaffoldPaddingParameter\")\n    override fun onCreate(savedInstanceState: Bundle?) {\n\n        installSplashScreen().setKeepOnScreenCondition { isLoading }\n\n        enableEdgeToEdge()\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            window.isNavigationBarContrastEnforced = false\n        }\n\n        super.onCreate(savedInstanceState)\n\n        setContent {\n            APatchTheme {\n                val navController = rememberNavController()\n                val snackBarHostState = remember { SnackbarHostState() }\n                val configuration = LocalConfiguration.current\n                val bottomBarRoutes = remember {\n                    BottomBarDestination.entries.map { it.direction.route }.toSet()\n                }\n                val state by APApplication.apStateLiveData.observeAsState(APApplication.State.UNKNOWN_STATE)\n                val kPatchReady = state != APApplication.State.UNKNOWN_STATE\n                val aPatchReady = state == APApplication.State.ANDROIDPATCH_INSTALLED\n                val visibleDestinations = remember(state) {\n                    BottomBarDestination.entries.filter { destination ->\n                        !(destination.kPatchRequired && !kPatchReady) && !(destination.aPatchRequired && !aPatchReady)\n                    }.toSet()\n                }\n\n                val defaultTransitions = object : NavHostAnimatedDestinationStyle() {\n                    override val enterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition =\n                        {\n                            // If the target is a detail page (not a bottom navigation page), slide in from the right\n                            if (targetState.destination.route !in bottomBarRoutes) {\n                                slideInHorizontally(initialOffsetX = { it })\n                            } else {\n                                // Otherwise (switching between bottom navigation pages), use fade in\n                                fadeIn(animationSpec = tween(340))\n                            }\n                        }\n\n                    override val exitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition =\n                        {\n                            // If navigating from the home page (bottom navigation page) to a detail page, slide out to the left\n                            if (initialState.destination.route in bottomBarRoutes && targetState.destination.route !in bottomBarRoutes) {\n                                slideOutHorizontally(targetOffsetX = { -it / 4 }) + fadeOut()\n                            } else {\n                                // Otherwise (switching between bottom navigation pages), use fade out\n                                fadeOut(animationSpec = tween(340))\n                            }\n                        }\n\n                    override val popEnterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition =\n                        {\n                            // If returning to the home page (bottom navigation page), slide in from the left\n                            if (targetState.destination.route in bottomBarRoutes) {\n                                slideInHorizontally(initialOffsetX = { -it / 4 }) + fadeIn()\n                            } else {\n                                // Otherwise (e.g., returning between multiple detail pages), use default fade in\n                                fadeIn(animationSpec = tween(340))\n                            }\n                        }\n\n                    override val popExitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition =\n                        {\n                            // If returning from a detail page (not a bottom navigation page), scale down and fade out\n                            if (initialState.destination.route !in bottomBarRoutes) {\n                                scaleOut(targetScale = 0.9f) + fadeOut()\n                            } else {\n                                // Otherwise, use default fade out\n                                fadeOut(animationSpec = tween(340))\n                            }\n                        }\n                }\n\n                LaunchedEffect(Unit) {\n                    if (SuperUserViewModel.apps.isEmpty()) {\n                        SuperUserViewModel().fetchAppList()\n                    }\n                }\n\n                Scaffold(\n                    bottomBar = {\n                        if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {\n                            BottomBar(navController, visibleDestinations)\n                        }\n                    },\n                    contentWindowInsets = WindowInsets(0, 0, 0, 0)\n                ) { innerPadding ->\n                    CompositionLocalProvider(\n                        LocalSnackbarHost provides snackBarHostState,\n                    ) {\n                        if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {\n                            Row(modifier = Modifier.fillMaxSize().windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Horizontal))) {\n                                SideBar(\n                                    navController = navController,\n                                    modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top)),\n                                    visibleDestinations = visibleDestinations\n                                )\n                                DestinationsNavHost(\n                                    modifier = Modifier\n                                        .weight(1f)\n                                        .consumeWindowInsets(WindowInsets.safeDrawing.only(WindowInsetsSides.Start)),\n                                    navGraph = NavGraphs.root,\n                                    navController = navController,\n                                    engine = rememberNavHostEngine(navHostContentAlignment = Alignment.TopCenter),\n                                    defaultTransitions = defaultTransitions\n                                )\n                            }\n                        } else {\n                            DestinationsNavHost(\n                                modifier = Modifier.padding(innerPadding).consumeWindowInsets(innerPadding),\n                                navGraph = NavGraphs.root,\n                                navController = navController,\n                                engine = rememberNavHostEngine(navHostContentAlignment = Alignment.TopCenter),\n                                defaultTransitions = defaultTransitions\n                            )\n                        }\n                    }\n                }\n            }\n        }\n\n        // Initialize Coil\n        val iconSize = resources.getDimensionPixelSize(android.R.dimen.app_icon_size)\n        Coil.setImageLoader(\n            ImageLoader.Builder(this)\n                .components {\n                    add(AppIconKeyer())\n                    add(AppIconFetcher.Factory(iconSize, false, this@MainActivity))\n                }\n                .build()\n        )\n\n        isLoading = false\n    }\n}\n\n@Composable\nprivate fun BottomBar(navController: NavHostController, visibleDestinations: Set<BottomBarDestination>) {\n    val navigator = navController.rememberDestinationsNavigator()\n\n    Crossfade(\n        targetState = visibleDestinations,\n        label = \"BottomBarStateCrossfade\"\n    ) { visibleDestinations ->\n        NavigationBar(tonalElevation = 8.dp) {\n            visibleDestinations.forEach { destination ->\n                val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)\n\n                NavigationBarItem(\n                    selected = isCurrentDestOnBackStack,\n                    onClick = {\n                        if (isCurrentDestOnBackStack) {\n                            navigator.popBackStack(destination.direction, false)\n                        }\n                        navigator.navigate(destination.direction) {\n                            popUpTo(NavGraphs.root) {\n                                saveState = true\n                            }\n                            launchSingleTop = true\n                            restoreState = true\n                        }\n                    },\n                    icon = {\n                        if (isCurrentDestOnBackStack) {\n                            Icon(destination.iconSelected, stringResource(destination.label))\n                        } else {\n                            Icon(destination.iconNotSelected, stringResource(destination.label))\n                        }\n                    },\n                    label = {\n                        Text(\n                            text = stringResource(destination.label),\n                            overflow = TextOverflow.Visible,\n                            maxLines = 1,\n                            softWrap = false\n                        )\n                    },\n                    alwaysShowLabel = false\n                )\n            }\n        }\n    }\n}\n\n@Composable\nprivate fun SideBar(navController: NavHostController, modifier: Modifier = Modifier, visibleDestinations: Set<BottomBarDestination>) {\n    val navigator = navController.rememberDestinationsNavigator()\n\n    Crossfade(\n        targetState = visibleDestinations,\n        label = \"SideBarStateCrossfade\"\n    ) { visibleDestinations ->\n        NavigationRail(\n            modifier = modifier,\n            containerColor = MaterialTheme.colorScheme.background,\n        ) {\n            Column(\n                modifier = Modifier.fillMaxHeight(),\n                verticalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterVertically)\n            ) {\n                visibleDestinations.forEach { destination ->\n                    val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)\n                    NavigationRailItem(\n                        selected = isCurrentDestOnBackStack,\n                        onClick = {\n                            if (isCurrentDestOnBackStack) {\n                                navigator.popBackStack(destination.direction, false)\n                            }\n                            navigator.navigate(destination.direction) {\n                                popUpTo(NavGraphs.root) {\n                                    saveState = true\n                                }\n                                launchSingleTop = true\n                                restoreState = true\n                            }\n                        },\n                        icon = {\n                            if (isCurrentDestOnBackStack) {\n                                Icon(destination.iconSelected, stringResource(destination.label))\n                            } else {\n                                Icon(destination.iconNotSelected, stringResource(destination.label))\n                            }\n                        },\n                        label = { Text(stringResource(destination.label)) },\n                        alwaysShowLabel = false,\n                        modifier = Modifier.padding(start = 8.dp)\n                    )\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/WebUIActivity.kt",
    "content": "package me.bmax.apatch.ui\n\nimport android.annotation.SuppressLint\nimport android.app.ActivityManager\nimport android.content.ActivityNotFoundException\nimport android.content.Intent\nimport android.graphics.Color\nimport android.net.Uri\nimport android.os.Build\nimport android.os.Bundle\nimport android.view.ViewGroup\nimport android.webkit.ValueCallback\nimport android.webkit.WebChromeClient\nimport android.webkit.WebResourceRequest\nimport android.webkit.WebResourceResponse\nimport android.webkit.WebView\nimport android.webkit.WebViewClient\nimport android.widget.FrameLayout\nimport androidx.activity.ComponentActivity\nimport androidx.activity.compose.setContent\nimport androidx.activity.enableEdgeToEdge\nimport androidx.activity.result.ActivityResultLauncher\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.material3.CircularProgressIndicator\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.core.view.ViewCompat\nimport androidx.core.view.WindowInsetsCompat\nimport androidx.lifecycle.lifecycleScope\nimport androidx.webkit.WebViewAssetLoader\nimport kotlinx.coroutines.CancellableContinuation\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.suspendCancellableCoroutine\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.ui.theme.APatchTheme\nimport me.bmax.apatch.ui.viewmodel.SuperUserViewModel\nimport me.bmax.apatch.ui.webui.AppIconUtil\nimport me.bmax.apatch.ui.webui.Insets\nimport me.bmax.apatch.ui.webui.SuFilePathHandler\nimport me.bmax.apatch.ui.webui.WebViewInterface\nimport java.io.File\n\n@SuppressLint(\"SetJavaScriptEnabled\")\nclass WebUIActivity : ComponentActivity() {\n    private lateinit var webViewInterface: WebViewInterface\n    private var webView: WebView? = null\n    private lateinit var container: FrameLayout\n    private lateinit var insets: Insets\n    private var insetsContinuation: CancellableContinuation<Unit>? = null\n    private var isInsetsEnabled = false\n    private lateinit var fileChooserLauncher: ActivityResultLauncher<Intent>\n    private var filePathCallback: ValueCallback<Array<Uri>>? = null\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n\n        enableEdgeToEdge()\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            window.isNavigationBarContrastEnforced = false\n        }\n\n        super.onCreate(savedInstanceState)\n\n        setContent {\n            APatchTheme {\n                Box(\n                    modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background),\n                    contentAlignment = Alignment.Center\n                ) {\n                    CircularProgressIndicator()\n                }\n            }\n        }\n\n        lifecycleScope.launch {\n            if (SuperUserViewModel.apps.isEmpty()) {\n                SuperUserViewModel().fetchAppList()\n            }\n            setupWebView()\n        }\n\n        fileChooserLauncher = registerForActivityResult(\n            ActivityResultContracts.StartActivityForResult()\n        ) { result ->\n            val uris: Array<Uri>? = when (result.resultCode) {\n                RESULT_OK -> result.data?.let { data ->\n                    when {\n                        data.clipData != null -> {\n                            Array(data.clipData!!.itemCount) { i ->\n                                data.clipData!!.getItemAt(i).uri // Multiple files\n                            }\n                        }\n                        data.data != null -> { arrayOf(data.data!!) } // Single file\n                        else -> null\n                    }\n                }\n                else -> null\n            }\n            filePathCallback?.onReceiveValue(uris)\n            filePathCallback = null\n        }\n    }\n\n    private suspend fun setupWebView() {\n        val moduleId = intent.getStringExtra(\"id\")!!\n        val name = intent.getStringExtra(\"name\")!!\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {\n            @Suppress(\"DEPRECATION\")\n            setTaskDescription(ActivityManager.TaskDescription(\"APatch - $name\"))\n        } else {\n            val taskDescription = ActivityManager.TaskDescription.Builder().setLabel(\"APatch - $name\").build()\n            setTaskDescription(taskDescription)\n        }\n\n        val prefs = APApplication.sharedPreferences\n        WebView.setWebContentsDebuggingEnabled(prefs.getBoolean(\"enable_web_debugging\", false))\n\n        val webRoot = File(\"/data/adb/modules/${moduleId}/webroot\")\n        insets = Insets(0, 0, 0, 0)\n\n        container = FrameLayout(this).apply {\n            layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)\n        }\n\n        this.webView = WebView(this).apply {\n            setBackgroundColor(Color.TRANSPARENT)\n        }\n\n        val density = resources.displayMetrics.density\n        ViewCompat.setOnApplyWindowInsetsListener(container) { view, windowInsets ->\n            val inset = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout())\n            insets = Insets(\n                top = (inset.top / density).toInt(),\n                bottom = (inset.bottom / density).toInt(),\n                left = (inset.left / density).toInt(),\n                right = (inset.right / density).toInt()\n            )\n            if (isInsetsEnabled) {\n                view.setPadding(0, 0, 0, 0)\n            } else {\n                view.setPadding(inset.left, inset.top, inset.right, inset.bottom)\n            }\n            insetsContinuation?.resumeWith(Result.success(Unit))\n            insetsContinuation = null\n            WindowInsetsCompat.CONSUMED\n        }\n        container.addView(this.webView)\n\n        suspendCancellableCoroutine { cont ->\n            insetsContinuation = cont\n            cont.invokeOnCancellation {\n                insetsContinuation = null\n            }\n            setContentView(container)\n\n            if (insets != Insets(0, 0, 0, 0)) {\n                cont.resumeWith(Result.success(Unit))\n                insetsContinuation = null\n            }\n        }\n\n        val webViewAssetLoader = WebViewAssetLoader.Builder()\n            .setDomain(\"mui.kernelsu.org\")\n            .addPathHandler(\n                \"/\",\n                SuFilePathHandler(this, webRoot, { insets }, { enable -> enableInsets(enable) })\n            )\n            .build()\n\n        val webViewClient = object : WebViewClient() {\n            override fun shouldInterceptRequest(\n                view: WebView,\n                request: WebResourceRequest\n            ): WebResourceResponse? {\n                val url = request.url\n\n                // Handle ksu://icon/[packageName] to serve app icon via WebView\n                if (url.scheme.equals(\"ksu\", ignoreCase = true) && url.host.equals(\"icon\", ignoreCase = true)) {\n                    val packageName = url.path?.substring(1)\n                    if (!packageName.isNullOrEmpty()) {\n                        val icon = AppIconUtil.loadAppIconSync(this@WebUIActivity, packageName, 512)\n                        if (icon != null) {\n                            val stream = java.io.ByteArrayOutputStream()\n                            icon.compress(android.graphics.Bitmap.CompressFormat.PNG, 100, stream)\n                            val inputStream = java.io.ByteArrayInputStream(stream.toByteArray())\n                            return WebResourceResponse(\"image/png\", null, inputStream)\n                        }\n                    }\n                }\n\n                return webViewAssetLoader.shouldInterceptRequest(url)\n            }\n        }\n\n        webView?.apply {\n            settings.javaScriptEnabled = true\n            settings.domStorageEnabled = true\n            settings.allowFileAccess = false\n            webViewInterface = WebViewInterface(this@WebUIActivity, this)\n            addJavascriptInterface(webViewInterface, \"ksu\")\n            setWebViewClient(webViewClient)\n            webChromeClient = object : WebChromeClient() {\n                override fun onShowFileChooser(\n                    webView: WebView?,\n                    filePathCallback: ValueCallback<Array<Uri>>?,\n                    fileChooserParams: FileChooserParams?\n                ): Boolean {\n                    this@WebUIActivity.filePathCallback?.onReceiveValue(null)\n                    this@WebUIActivity.filePathCallback = filePathCallback\n                    val intent = fileChooserParams?.createIntent() ?: Intent(Intent.ACTION_GET_CONTENT).apply { type = \"*/*\" }\n                    if (fileChooserParams?.mode == FileChooserParams.MODE_OPEN_MULTIPLE) {\n                        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)\n                    }\n                    try {\n                        fileChooserLauncher.launch(intent)\n                    } catch (_: ActivityNotFoundException) {\n                        filePathCallback?.onReceiveValue(null)\n                        this@WebUIActivity.filePathCallback = null\n                        return false\n                    }\n                    return true\n                }\n            }\n            loadUrl(\"https://mui.kernelsu.org/index.html\")\n        }\n    }\n\n    fun enableInsets(enable: Boolean = true) {\n        runOnUiThread {\n            if (isInsetsEnabled != enable) {\n                isInsetsEnabled = enable\n                ViewCompat.requestApplyInsets(container)\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/component/Dialog.kt",
    "content": "package me.bmax.apatch.ui.component\n\nimport android.graphics.text.LineBreaker\nimport android.os.Build\nimport android.os.Parcelable\nimport android.text.Layout\nimport android.text.method.LinkMovementMethod\nimport android.util.Log\nimport android.view.ViewGroup\nimport android.widget.TextView\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.layout.wrapContentHeight\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.material3.AlertDialogDefaults\nimport androidx.compose.material3.BasicAlertDialog\nimport androidx.compose.material3.CircularProgressIndicator\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.LocalContentColor\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TextButton\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.MutableState\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.rememberUpdatedState\nimport androidx.compose.runtime.saveable.Saver\nimport androidx.compose.runtime.saveable.rememberSaveable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.toArgb\nimport androidx.compose.ui.platform.LocalView\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.viewinterop.AndroidView\nimport androidx.compose.ui.window.Dialog\nimport androidx.compose.ui.window.DialogProperties\nimport androidx.compose.ui.window.DialogWindowProvider\nimport androidx.compose.ui.window.SecureFlagPolicy\nimport io.noties.markwon.Markwon\nimport io.noties.markwon.utils.NoCopySpannableFactory\nimport kotlinx.coroutines.CancellableContinuation\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.async\nimport kotlinx.coroutines.channels.Channel\nimport kotlinx.coroutines.channels.ReceiveChannel\nimport kotlinx.coroutines.flow.FlowCollector\nimport kotlinx.coroutines.flow.consumeAsFlow\nimport kotlinx.coroutines.flow.onEach\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.suspendCancellableCoroutine\nimport kotlinx.parcelize.Parcelize\nimport me.bmax.apatch.util.ui.APDialogBlurBehindUtils.Companion.setupWindowBlurListener\nimport kotlin.coroutines.resume\n\nprivate const val TAG = \"DialogComponent\"\n\ninterface ConfirmDialogVisuals : Parcelable {\n    val title: String\n    val content: String\n    val isMarkdown: Boolean\n    val confirm: String?\n    val dismiss: String?\n}\n\n@Parcelize\nprivate data class ConfirmDialogVisualsImpl(\n    override val title: String,\n    override val content: String,\n    override val isMarkdown: Boolean,\n    override val confirm: String?,\n    override val dismiss: String?,\n) : ConfirmDialogVisuals {\n    companion object {\n        val Empty: ConfirmDialogVisuals = ConfirmDialogVisualsImpl(\"\", \"\", false, null, null)\n    }\n}\n\ninterface DialogHandle {\n    val isShown: Boolean\n    val dialogType: String\n    fun show()\n    fun hide()\n}\n\ninterface LoadingDialogHandle : DialogHandle {\n    suspend fun <R> withLoading(block: suspend () -> R): R\n    fun showLoading()\n}\n\nsealed interface ConfirmResult {\n    data object Confirmed : ConfirmResult\n    data object Canceled : ConfirmResult\n}\n\ninterface ConfirmDialogHandle : DialogHandle {\n    val visuals: ConfirmDialogVisuals\n\n    fun showConfirm(\n        title: String,\n        content: String,\n        markdown: Boolean = false,\n        confirm: String? = null,\n        dismiss: String? = null\n    )\n\n    suspend fun awaitConfirm(\n        title: String,\n        content: String,\n        markdown: Boolean = false,\n        confirm: String? = null,\n        dismiss: String? = null\n    ): ConfirmResult\n}\n\nprivate abstract class DialogHandleBase(\n    protected val visible: MutableState<Boolean>,\n    protected val coroutineScope: CoroutineScope\n) : DialogHandle {\n    override val isShown: Boolean\n        get() = visible.value\n\n    override fun show() {\n        coroutineScope.launch {\n            visible.value = true\n        }\n    }\n\n    final override fun hide() {\n        coroutineScope.launch {\n            visible.value = false\n        }\n    }\n\n    override fun toString(): String {\n        return dialogType\n    }\n}\n\nprivate class LoadingDialogHandleImpl(\n    visible: MutableState<Boolean>,\n    coroutineScope: CoroutineScope\n) : LoadingDialogHandle, DialogHandleBase(visible, coroutineScope) {\n    override suspend fun <R> withLoading(block: suspend () -> R): R {\n        return coroutineScope.async {\n            try {\n                visible.value = true\n                block()\n            } finally {\n                visible.value = false\n            }\n        }.await()\n    }\n\n    override fun showLoading() {\n        show()\n    }\n\n    override val dialogType: String get() = \"LoadingDialog\"\n}\n\ntypealias NullableCallback = (() -> Unit)?\n\ninterface ConfirmCallback {\n\n    val onConfirm: NullableCallback\n\n    val onDismiss: NullableCallback\n\n    val isEmpty: Boolean get() = onConfirm == null && onDismiss == null\n\n    companion object {\n        operator fun invoke(\n            onConfirmProvider: () -> NullableCallback,\n            onDismissProvider: () -> NullableCallback\n        ): ConfirmCallback {\n            return object : ConfirmCallback {\n                override val onConfirm: NullableCallback\n                    get() = onConfirmProvider()\n                override val onDismiss: NullableCallback\n                    get() = onDismissProvider()\n            }\n        }\n    }\n}\n\nprivate class ConfirmDialogHandleImpl(\n    visible: MutableState<Boolean>,\n    coroutineScope: CoroutineScope,\n    callback: ConfirmCallback,\n    override var visuals: ConfirmDialogVisuals = ConfirmDialogVisualsImpl.Empty,\n    private val resultFlow: ReceiveChannel<ConfirmResult>\n) : ConfirmDialogHandle, DialogHandleBase(visible, coroutineScope) {\n    private class ResultCollector(\n        private val callback: ConfirmCallback\n    ) : FlowCollector<ConfirmResult> {\n        fun handleResult(result: ConfirmResult) {\n            Log.d(TAG, \"handleResult: ${result.javaClass.simpleName}\")\n            when (result) {\n                ConfirmResult.Confirmed -> onConfirm()\n                ConfirmResult.Canceled -> onDismiss()\n            }\n        }\n\n        fun onConfirm() {\n            callback.onConfirm?.invoke()\n        }\n\n        fun onDismiss() {\n            callback.onDismiss?.invoke()\n        }\n\n        override suspend fun emit(value: ConfirmResult) {\n            handleResult(value)\n        }\n    }\n\n    private val resultCollector = ResultCollector(callback)\n\n    private var awaitContinuation: CancellableContinuation<ConfirmResult>? = null\n\n    private val isCallbackEmpty = callback.isEmpty\n\n    init {\n        coroutineScope.launch {\n            resultFlow\n                .consumeAsFlow()\n                .onEach { result ->\n                    awaitContinuation?.let {\n                        awaitContinuation = null\n                        if (it.isActive) {\n                            it.resume(result)\n                        }\n                    }\n                }\n                .onEach { hide() }\n                .collect(resultCollector)\n        }\n    }\n\n    private suspend fun awaitResult(): ConfirmResult {\n        return suspendCancellableCoroutine {\n            awaitContinuation = it.apply {\n                if (isCallbackEmpty) {\n                    invokeOnCancellation {\n                        visible.value = false\n                    }\n                }\n            }\n        }\n    }\n\n    fun updateVisuals(visuals: ConfirmDialogVisuals) {\n        this.visuals = visuals\n    }\n\n    override fun show() {\n        if (visuals !== ConfirmDialogVisualsImpl.Empty) {\n            super.show()\n        } else {\n            throw UnsupportedOperationException(\"can't show confirm dialog with the Empty visuals\")\n        }\n    }\n\n    override fun showConfirm(\n        title: String,\n        content: String,\n        markdown: Boolean,\n        confirm: String?,\n        dismiss: String?\n    ) {\n        coroutineScope.launch {\n            updateVisuals(ConfirmDialogVisualsImpl(title, content, markdown, confirm, dismiss))\n            show()\n        }\n    }\n\n    override suspend fun awaitConfirm(\n        title: String,\n        content: String,\n        markdown: Boolean,\n        confirm: String?,\n        dismiss: String?\n    ): ConfirmResult {\n        coroutineScope.launch {\n            updateVisuals(ConfirmDialogVisualsImpl(title, content, markdown, confirm, dismiss))\n            show()\n        }\n        return awaitResult()\n    }\n\n    override val dialogType: String get() = \"ConfirmDialog\"\n\n    override fun toString(): String {\n        return \"${super.toString()}(visuals: $visuals)\"\n    }\n\n    companion object {\n        fun Saver(\n            visible: MutableState<Boolean>,\n            coroutineScope: CoroutineScope,\n            callback: ConfirmCallback,\n            resultChannel: ReceiveChannel<ConfirmResult>\n        ) = Saver<ConfirmDialogHandle, ConfirmDialogVisuals>(\n            save = {\n                it.visuals\n            },\n            restore = {\n                Log.d(TAG, \"ConfirmDialog restore, visuals: $it\")\n                ConfirmDialogHandleImpl(visible, coroutineScope, callback, it, resultChannel)\n            }\n        )\n    }\n}\n\nprivate class CustomDialogHandleImpl(\n    visible: MutableState<Boolean>,\n    coroutineScope: CoroutineScope\n) : DialogHandleBase(visible, coroutineScope) {\n    override val dialogType: String get() = \"CustomDialog\"\n}\n\n@Composable\nfun rememberLoadingDialog(): LoadingDialogHandle {\n    val visible = remember {\n        mutableStateOf(false)\n    }\n    val coroutineScope = rememberCoroutineScope()\n\n    if (visible.value) {\n        LoadingDialog()\n    }\n\n    return remember {\n        LoadingDialogHandleImpl(visible, coroutineScope)\n    }\n}\n\n@Composable\nprivate fun rememberConfirmDialog(\n    visuals: ConfirmDialogVisuals,\n    callback: ConfirmCallback\n): ConfirmDialogHandle {\n    val visible = rememberSaveable {\n        mutableStateOf(false)\n    }\n    val coroutineScope = rememberCoroutineScope()\n    val resultChannel = remember {\n        Channel<ConfirmResult>()\n    }\n\n    val handle = rememberSaveable(\n        saver = ConfirmDialogHandleImpl.Saver(visible, coroutineScope, callback, resultChannel),\n        init = {\n            ConfirmDialogHandleImpl(visible, coroutineScope, callback, visuals, resultChannel)\n        }\n    )\n\n    if (visible.value) {\n        ConfirmDialog(\n            handle.visuals,\n            confirm = { coroutineScope.launch { resultChannel.send(ConfirmResult.Confirmed) } },\n            dismiss = { coroutineScope.launch { resultChannel.send(ConfirmResult.Canceled) } }\n        )\n    }\n\n    return handle\n}\n\n@Composable\nfun rememberConfirmCallback(\n    onConfirm: NullableCallback,\n    onDismiss: NullableCallback\n): ConfirmCallback {\n    val currentOnConfirm by rememberUpdatedState(newValue = onConfirm)\n    val currentOnDismiss by rememberUpdatedState(newValue = onDismiss)\n    return remember {\n        ConfirmCallback({ currentOnConfirm }, { currentOnDismiss })\n    }\n}\n\n@Composable\nfun rememberConfirmDialog(\n    onConfirm: NullableCallback = null,\n    onDismiss: NullableCallback = null\n): ConfirmDialogHandle {\n    return rememberConfirmDialog(rememberConfirmCallback(onConfirm, onDismiss))\n}\n\n@Composable\nfun rememberConfirmDialog(callback: ConfirmCallback): ConfirmDialogHandle {\n    return rememberConfirmDialog(ConfirmDialogVisualsImpl.Empty, callback)\n}\n\n@Composable\nfun rememberCustomDialog(composable: @Composable (dismiss: () -> Unit) -> Unit): DialogHandle {\n    val visible = rememberSaveable {\n        mutableStateOf(false)\n    }\n    val coroutineScope = rememberCoroutineScope()\n    if (visible.value) {\n        composable { visible.value = false }\n    }\n    return remember {\n        CustomDialogHandleImpl(visible, coroutineScope)\n    }\n}\n\n@Composable\nprivate fun LoadingDialog() {\n    Dialog(\n        onDismissRequest = {},\n        properties = DialogProperties(\n            dismissOnClickOutside = false,\n            dismissOnBackPress = false,\n            usePlatformDefaultWidth = false\n        )\n    ) {\n        Surface(\n            modifier = Modifier.size(100.dp), shape = RoundedCornerShape(8.dp)\n        ) {\n            Box(\n                contentAlignment = Alignment.Center,\n            ) {\n                CircularProgressIndicator()\n            }\n        }\n        val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n        setupWindowBlurListener(dialogWindowProvider.window)\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun ConfirmDialog(visuals: ConfirmDialogVisuals, confirm: () -> Unit, dismiss: () -> Unit) {\n    BasicAlertDialog(\n        onDismissRequest = {\n            dismiss()\n        },\n        properties = DialogProperties(\n            decorFitsSystemWindows = true,\n            usePlatformDefaultWidth = false,\n            securePolicy = SecureFlagPolicy.SecureOff\n        )\n    ) {\n        Surface(\n            modifier = Modifier\n                .width(320.dp)\n                .wrapContentHeight(),\n            shape = RoundedCornerShape(20.dp),\n            tonalElevation = AlertDialogDefaults.TonalElevation,\n            color = AlertDialogDefaults.containerColor,\n        ) {\n            Column(modifier = Modifier.padding(PaddingValues(all = 24.dp))) {\n                Box(\n                    Modifier\n                        .padding(PaddingValues(bottom = 16.dp))\n                        .align(Alignment.Start)\n                ) {\n                    Text(text = visuals.title, style = MaterialTheme.typography.headlineSmall)\n                }\n                Box(\n                    Modifier\n                        .weight(weight = 1f, fill = false)\n                        .padding(PaddingValues(bottom = 24.dp))\n                        .align(Alignment.Start)\n                ) {\n\n                    if (visuals.isMarkdown) {\n                        MarkdownContent(content = visuals.content)\n                    } else {\n                        Text(text = visuals.content, style = MaterialTheme.typography.bodyMedium)\n                    }\n                }\n                Row(\n                    modifier = Modifier.fillMaxWidth(),\n                    horizontalArrangement = Arrangement.End\n                ) {\n                    TextButton(onClick = dismiss) {\n                        Text(text = visuals.dismiss ?: stringResource(id = android.R.string.cancel))\n                    }\n\n                    TextButton(onClick = confirm) {\n                        Text(text = visuals.confirm ?: stringResource(id = android.R.string.ok))\n                    }\n                }\n            }\n            val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n            setupWindowBlurListener(dialogWindowProvider.window)\n        }\n    }\n\n}\n\n@Composable\nprivate fun MarkdownContent(content: String) {\n    val contentColor = LocalContentColor.current\n\n    AndroidView(\n        factory = { context ->\n            TextView(context).apply {\n                movementMethod = LinkMovementMethod.getInstance()\n                setSpannableFactory(NoCopySpannableFactory.getInstance())\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                    breakStrategy = LineBreaker.BREAK_STRATEGY_SIMPLE\n                    hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE\n                }\n\n                layoutParams = ViewGroup.LayoutParams(\n                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT\n                )\n            }\n        },\n        modifier = Modifier\n            .fillMaxWidth()\n            .wrapContentHeight(),\n        update = {\n            Markwon.create(it.context).setMarkdown(it, content)\n            it.setTextColor(contentColor.toArgb())\n        }\n    )\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/component/DropdownMenu.kt",
    "content": "package me.bmax.apatch.ui.component\n\nimport androidx.compose.foundation.shape.CornerBasedShape\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.unit.dp\n\n@Composable\nfun ProvideMenuShape(\n    value: CornerBasedShape = RoundedCornerShape(8.dp), content: @Composable () -> Unit\n) = MaterialTheme(\n    shapes = MaterialTheme.shapes.copy(extraSmall = value), content = content\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/component/KeyEventBlocker.kt",
    "content": "package me.bmax.apatch.ui.component\n\nimport androidx.compose.foundation.focusable\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.remember\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.focus.FocusRequester\nimport androidx.compose.ui.focus.focusRequester\nimport androidx.compose.ui.input.key.KeyEvent\nimport androidx.compose.ui.input.key.onKeyEvent\n\n@Composable\nfun KeyEventBlocker(predicate: (KeyEvent) -> Boolean) {\n    val requester = remember { FocusRequester() }\n    Box(\n        Modifier\n            .onKeyEvent {\n                predicate(it)\n            }\n            .focusRequester(requester)\n            .focusable()\n    )\n    LaunchedEffect(Unit) {\n        requester.requestFocus()\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/component/ModuleCardComponents.kt",
    "content": "package me.bmax.apatch.ui.component\n\nimport androidx.annotation.DrawableRes\nimport androidx.compose.foundation.Image\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.requiredSize\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.material3.FilledTonalButton\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.graphics.ColorFilter\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.style.TextOverflow\nimport androidx.compose.ui.unit.dp\nimport me.bmax.apatch.R\n\n@Composable\nfun ModuleUpdateButton(\n    onClick: () -> Unit\n) = FilledTonalButton(\n    onClick = onClick, enabled = true, contentPadding = PaddingValues(12.dp)\n) {\n    Icon(\n        modifier = Modifier.size(20.dp),\n        painter = painterResource(id = R.drawable.device_mobile_down),\n        contentDescription = stringResource(id = R.string.apm_update)\n    )\n}\n\n@Composable\nfun ModuleRemoveButton(\n    enabled: Boolean, onClick: () -> Unit\n) = FilledTonalButton(\n    onClick = onClick, enabled = enabled, contentPadding = PaddingValues(12.dp)\n) {\n    Icon(\n        modifier = Modifier.size(20.dp),\n        painter = painterResource(id = R.drawable.trash),\n        contentDescription = stringResource(id = R.string.apm_remove)\n    )\n}\n\n@Composable\nfun KPModuleRemoveButton(\n    enabled: Boolean, onClick: () -> Unit\n) = FilledTonalButton(\n    onClick = onClick, enabled = enabled, contentPadding = PaddingValues(12.dp)\n) {\n    Icon(\n        modifier = Modifier.size(20.dp),\n        painter = painterResource(id = R.drawable.trash),\n        contentDescription = stringResource(id = R.string.kpm_unload)\n    )\n}\n\n@Composable\nfun ModuleStateIndicator(\n    @DrawableRes icon: Int, color: Color = MaterialTheme.colorScheme.outline\n) {\n    Image(\n        modifier = Modifier.requiredSize(150.dp),\n        painter = painterResource(id = icon),\n        contentDescription = null,\n        alpha = 0.1f,\n        colorFilter = ColorFilter.tint(color)\n    )\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/component/SearchBar.kt",
    "content": "package me.bmax.apatch.ui.component\n\nimport androidx.activity.compose.BackHandler\nimport androidx.compose.animation.core.AnimationSpec\nimport androidx.compose.animation.core.DecayAnimationSpec\nimport androidx.compose.animation.rememberSplineBasedDecay\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.ExperimentalLayoutApi\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.WindowInsets\nimport androidx.compose.foundation.layout.WindowInsetsSides\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.isImeVisible\nimport androidx.compose.foundation.layout.only\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.safeDrawing\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.layout.windowInsetsPadding\nimport androidx.compose.foundation.shape.CircleShape\nimport androidx.compose.foundation.text.input.rememberTextFieldState\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.automirrored.outlined.ArrowBack\nimport androidx.compose.material.icons.automirrored.twotone.ArrowBack\nimport androidx.compose.material.icons.twotone.Search\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.ExperimentalMaterial3ExpressiveApi\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.MotionScheme\nimport androidx.compose.material3.SearchBar\nimport androidx.compose.material3.SearchBarDefaults\nimport androidx.compose.material3.SearchBarScrollBehavior\nimport androidx.compose.material3.SearchBarValue\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.rememberSearchBarState\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.DisposableEffect\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableFloatStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.saveable.Saver\nimport androidx.compose.runtime.saveable.listSaver\nimport androidx.compose.runtime.saveable.rememberSaveable\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.draw.clip\nimport androidx.compose.ui.focus.FocusRequester\nimport androidx.compose.ui.focus.focusRequester\nimport androidx.compose.ui.geometry.Offset\nimport androidx.compose.ui.input.nestedscroll.NestedScrollConnection\nimport androidx.compose.ui.input.nestedscroll.NestedScrollSource\nimport androidx.compose.ui.layout.onSizeChanged\nimport androidx.compose.ui.platform.LocalFocusManager\nimport androidx.compose.ui.platform.LocalSoftwareKeyboardController\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.semantics.clearAndSetSemantics\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport kotlinx.coroutines.launch\nimport me.bmax.apatch.R\n\n@OptIn(ExperimentalMaterial3ExpressiveApi::class)\n@ExperimentalMaterial3Api\n@Composable\nfun pinnedScrollBehavior(\n    canScroll: () -> Boolean = { true },\n    snapAnimationSpec: AnimationSpec<Float> = MotionScheme.expressive().defaultEffectsSpec(),\n    flingAnimationSpec: DecayAnimationSpec<Float> = rememberSplineBasedDecay(),\n    reverseLayout: Boolean = false,\n): SearchBarScrollBehavior =\n    rememberSaveable(\n        snapAnimationSpec,\n        flingAnimationSpec,\n        canScroll,\n        reverseLayout,\n        saver =\n            PinnedScrollBehavior.Saver(\n                canScroll = canScroll\n            ),\n    ) {\n        PinnedScrollBehavior(\n            canScroll = canScroll\n        )\n    }\n\n@OptIn(ExperimentalMaterial3Api::class)\nprivate class PinnedScrollBehavior(\n    val canScroll: () -> Boolean,\n) : SearchBarScrollBehavior {\n    // Offset remains 0 so the bar never moves vertically\n    override var scrollOffset by mutableFloatStateOf(0f)\n    override var scrollOffsetLimit by mutableFloatStateOf(0f)\n\n    // Track contentOffset to allow for tonal elevation/color changes on scroll\n    override var contentOffset by mutableFloatStateOf(0f)\n\n    override fun Modifier.searchBarScrollBehavior(): Modifier {\n        // We remove the .layout { ... } and .draggable blocks\n        // that were responsible for hiding/moving the bar.\n        return this.onSizeChanged { size ->\n            scrollOffsetLimit = -size.height.toFloat()\n        }\n    }\n\n    override val nestedScrollConnection: NestedScrollConnection =\n        object : NestedScrollConnection {\n            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {\n                if (!canScroll()) return Offset.Zero\n\n                // We don't modify scrollOffset here because we want it pinned.\n                // We only return Offset.Zero to show we aren't consuming any scroll.\n                return Offset.Zero\n            }\n\n            override fun onPostScroll(\n                consumed: Offset,\n                available: Offset,\n                source: NestedScrollSource,\n            ): Offset {\n                if (!canScroll()) return Offset.Zero\n\n                // Update contentOffset so the UI knows how far the user has scrolled\n                // This is used for \"overlapped\" state (changing colors/elevation)\n                contentOffset += consumed.y\n                return Offset.Zero\n            }\n        }\n\n    companion object {\n        fun Saver(\n            canScroll: () -> Boolean\n        ): Saver<PinnedScrollBehavior, *> =\n            listSaver(\n                save = {\n                    listOf(\n                        it.scrollOffset,\n                        it.scrollOffsetLimit,\n                        it.contentOffset,\n                    )\n                },\n                restore = {\n                    PinnedScrollBehavior(\n                        canScroll = canScroll,\n                    )\n                },\n            )\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)\n@Composable\nfun SearchAppBar(\n    searchText: String,\n    onSearchTextChange: (String) -> Unit,\n    onBackClick: (() -> Unit)? = null,\n    dropdownContent: @Composable (() -> Unit)? = null,\n    navigationContent: @Composable (() -> Unit)? = null,\n    searchBarPlaceHolderText: String\n) {\n    val textFieldState = rememberTextFieldState(initialText = searchText)\n    val searchBarState = rememberSearchBarState()\n\n    val scope = rememberCoroutineScope()\n    val keyboardController = LocalSoftwareKeyboardController.current\n    val focusManager = LocalFocusManager.current\n    val focusRequester = remember { FocusRequester() }\n\n    var isExpanded = searchBarState.currentValue == SearchBarValue.Expanded\n    val isKeyboardVisible = WindowInsets.isImeVisible\n\n    LaunchedEffect(isKeyboardVisible) {\n        if (!isKeyboardVisible) {\n            searchBarState.animateToCollapsed()\n        }\n    }\n\n    BackHandler(isExpanded) {\n        scope.launch { searchBarState.animateToCollapsed() }\n        keyboardController?.hide()\n        focusManager.clearFocus()\n        isExpanded = false\n    }\n\n    LaunchedEffect(textFieldState.text) {\n        onSearchTextChange(textFieldState.text.toString())\n    }\n\n    DisposableEffect(Unit) {\n        onDispose { keyboardController?.hide() }\n    }\n\n    val cardColor = MaterialTheme.colorScheme.background\n\n    Row(\n        modifier = Modifier\n            .fillMaxWidth()\n            .windowInsetsPadding(\n                WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top)\n            )\n            .padding(horizontal = 16.dp, vertical = 8.dp),\n        verticalAlignment = Alignment.CenterVertically\n    ) {\n        if (onBackClick != null) {\n            IconButton(onClick = {\n                if (isExpanded) {\n                    if (textFieldState.text.isNotEmpty()) {\n                        textFieldState.edit { replace(0, length, \"\") }\n                    } else {\n                        scope.launch {\n                            searchBarState.animateToCollapsed()\n                            keyboardController?.hide()\n                            focusManager.clearFocus()\n                        }\n                    }\n                    return@IconButton\n                }\n                onBackClick.invoke()\n            }) {\n                Icon(\n                    Icons.AutoMirrored.Outlined.ArrowBack,\n                    contentDescription = stringResource(R.string.back)\n                )\n            }\n        } else {\n            navigationContent?.invoke()\n        }\n\n        SearchBar(\n            state = searchBarState,\n            inputField = {\n                SearchBarDefaults.InputField(\n                    modifier = Modifier\n                        .focusRequester(focusRequester)\n                        .padding(bottom = 5.dp)\n                        .clip(SearchBarDefaults.inputFieldShape),\n                    searchBarState = searchBarState,\n                    textFieldState = textFieldState,\n                    onSearch = { text ->\n                        scope.launch { searchBarState.animateToCollapsed() }\n                        keyboardController?.hide()\n                        focusManager.clearFocus()\n                        onSearchTextChange(text)\n                    },\n                    colors = SearchBarDefaults.inputFieldColors(\n                        unfocusedContainerColor = MaterialTheme.colorScheme.surfaceContainerHigh,\n                        focusedContainerColor = MaterialTheme.colorScheme.surfaceContainerHigh,\n                    ),\n                    placeholder = {\n                        Text(\n                            modifier = Modifier\n                                .fillMaxWidth()\n                                .clearAndSetSemantics {},\n                            text = searchBarPlaceHolderText,\n                            style = MaterialTheme.typography.bodyLarge,\n                            color = MaterialTheme.colorScheme.onSurfaceVariant\n                        )\n                    },\n                    leadingIcon = {\n                        Row {\n                            if (onBackClick == null && isExpanded) {\n                                Icon(\n                                    imageVector = Icons.AutoMirrored.TwoTone.ArrowBack,\n                                    contentDescription = stringResource(R.string.back),\n                                    tint = MaterialTheme.colorScheme.onSurfaceVariant,\n                                    modifier = Modifier\n                                        .padding(start = 8.dp)\n                                        .size(40.dp)\n                                        .clip(CircleShape)\n                                        .clickable {\n                                            if (textFieldState.text.isNotEmpty()) {\n                                                textFieldState.edit { replace(0, length, \"\") }\n                                                return@clickable\n                                            }\n                                            scope.launch {\n                                                searchBarState.animateToCollapsed()\n                                                keyboardController?.hide()\n                                                focusManager.clearFocus()\n                                            }\n                                        }\n                                        .padding(8.dp)\n                                )\n                            } else {\n                                Icon(\n                                    imageVector = Icons.TwoTone.Search,\n                                    contentDescription = stringResource(R.string.search),\n                                    tint = MaterialTheme.colorScheme.onSurfaceVariant,\n                                    modifier = Modifier\n                                        .padding(start = 8.dp)\n                                        .size(40.dp)\n                                        .clip(CircleShape)\n                                        .clickable {\n                                            scope.launch {\n                                                searchBarState.animateToExpanded()\n                                                focusRequester.requestFocus()\n                                                keyboardController?.show()\n                                            }\n                                        }\n                                        .padding(8.dp)\n                                )\n                            }\n                            Spacer(modifier = Modifier.width(3.dp))\n                        }\n                    },\n                    trailingIcon = {\n                        dropdownContent?.invoke()\n                    }\n                )\n            },\n            modifier = Modifier.weight(1f),\n            colors = SearchBarDefaults.colors(\n                containerColor = cardColor.copy(alpha = 0f)\n            ),\n        )\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Preview\n@Composable\nprivate fun SearchAppBarPreview() {\n    SearchAppBar(\n        searchText = \"\",\n        onSearchTextChange = {},\n        searchBarPlaceHolderText = \"\"\n    )\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/component/SettingsItem.kt",
    "content": "package me.bmax.apatch.ui.component\n\nimport androidx.compose.foundation.LocalIndication\nimport androidx.compose.foundation.interaction.MutableInteractionSource\nimport androidx.compose.foundation.selection.toggleable\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.ListItem\nimport androidx.compose.material3.LocalContentColor\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.RadioButton\nimport androidx.compose.material3.Switch\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.remember\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.vector.ImageVector\nimport androidx.compose.ui.semantics.Role\n\n@Composable\nfun SwitchItem(\n    icon: ImageVector? = null,\n    title: String,\n    summary: String? = null,\n    checked: Boolean,\n    enabled: Boolean = true,\n    onCheckedChange: (Boolean) -> Unit\n) {\n    val interactionSource = remember { MutableInteractionSource() }\n\n    ListItem(\n        modifier = Modifier.toggleable(\n            value = checked,\n            interactionSource = interactionSource,\n            role = Role.Switch,\n            enabled = enabled,\n            indication = LocalIndication.current,\n            onValueChange = onCheckedChange\n        ),\n        headlineContent = {\n            Text(\n                title,\n                style = MaterialTheme.typography.bodyLarge,\n                color = LocalContentColor.current\n            )\n        },\n        leadingContent = icon?.let {\n            { Icon(icon, title) }\n        },\n        trailingContent = {\n            Switch(\n                checked = checked,\n                enabled = enabled,\n                onCheckedChange = onCheckedChange,\n                interactionSource = interactionSource\n            )\n        },\n        supportingContent = {\n            if (summary != null) {\n                Text(\n                    summary,\n                    style = MaterialTheme.typography.bodyMedium,\n                    color = MaterialTheme.colorScheme.outline\n                )\n            }\n        }\n    )\n}\n\n@Composable\nfun RadioItem(\n    title: String,\n    selected: Boolean,\n    onClick: () -> Unit,\n) {\n    ListItem(\n        headlineContent = {\n            Text(title)\n        },\n        leadingContent = {\n            RadioButton(selected = selected, onClick = onClick)\n        },\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/component/WarningCard.kt",
    "content": "package me.bmax.apatch.ui.component\n\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.layout.wrapContentHeight\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.filled.Close\nimport androidx.compose.material.icons.filled.Error\nimport androidx.compose.material3.CardDefaults\nimport androidx.compose.material3.ElevatedCard\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\n\n@Composable\nfun WarningCard(\n    message: String,\n    color: Color? = null,\n    onClick: (() -> Unit)? = null,\n    onClose: (() -> Unit)? = null,\n    icon: (@Composable () -> Unit)? = null\n) {\n    val cardColors = CardDefaults.cardColors(\n        containerColor = color ?: MaterialTheme.colorScheme.errorContainer,\n        contentColor = MaterialTheme.colorScheme.onErrorContainer,\n        disabledContainerColor = MaterialTheme.colorScheme.errorContainer,\n        disabledContentColor = MaterialTheme.colorScheme.onErrorContainer\n    )\n\n    ElevatedCard(\n        colors = cardColors,\n    ) {\n        Box(\n            modifier = Modifier\n                .fillMaxWidth()\n                .then(onClick?.let { Modifier.clickable { it() } } ?: Modifier)\n                .padding(20.dp)\n        ) {\n            Row(\n                verticalAlignment = Alignment.CenterVertically,\n                modifier = Modifier.fillMaxWidth().align(Alignment.CenterStart).padding(end = 40.dp)\n            ) {\n                if (icon != null) {\n                    icon()\n                } else {\n                    Icon(\n                        imageVector = Icons.Default.Error,\n                        contentDescription = null,\n                        tint = MaterialTheme.colorScheme.onErrorContainer,\n                        modifier = Modifier.size(18.dp)\n                    )\n                }\n\n                Spacer(modifier = Modifier.width(12.dp))\n\n                Text(\n                    text = message,\n                    style = MaterialTheme.typography.bodyMedium,\n                    modifier = Modifier\n                        .wrapContentHeight(Alignment.CenterVertically)\n                )\n            }\n\n\n            if (onClose != null) {\n                Icon(\n                    imageVector = Icons.Default.Close,\n                    contentDescription = stringResource(android.R.string.cancel),\n                    tint = MaterialTheme.colorScheme.onErrorContainer,\n                    modifier = Modifier.clickable {\n                        onClose()\n                    }.size(18.dp).align(Alignment.TopEnd)\n                )\n            }\n        }\n    }\n}\n\n@Preview\n@Composable\nprivate fun WarningCardPreview() {\n    Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {\n        WarningCard(message = \"Warning message\")\n        WarningCard(message = \"Warning message\", onClose = {})\n        WarningCard(\n            message = \"Warning message \",\n            MaterialTheme.colorScheme.outlineVariant,\n        ) {}\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/APM.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport android.app.Activity.RESULT_OK\nimport android.content.Context\nimport android.content.Intent\nimport android.net.Uri\nimport android.util.Log\nimport android.util.Patterns\nimport android.widget.Toast\nimport androidx.activity.compose.rememberLauncherForActivityResult\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.compose.animation.AnimatedVisibility\nimport androidx.compose.animation.expandVertically\nimport androidx.compose.animation.fadeIn\nimport androidx.compose.animation.fadeOut\nimport androidx.compose.animation.shrinkVertically\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.lazy.LazyColumn\nimport androidx.compose.foundation.lazy.LazyListState\nimport androidx.compose.foundation.lazy.items\nimport androidx.compose.foundation.lazy.rememberLazyListState\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.FilledTonalButton\nimport androidx.compose.material3.FloatingActionButton\nimport androidx.compose.material3.HorizontalDivider\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.SearchBarScrollBehavior\nimport androidx.compose.material3.SnackbarDuration\nimport androidx.compose.material3.SnackbarHost\nimport androidx.compose.material3.SnackbarHostState\nimport androidx.compose.material3.SnackbarResult\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Switch\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.pulltorefresh.PullToRefreshBox\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.livedata.observeAsState\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.produceState\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.saveable.rememberSaveable\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.draw.alpha\nimport androidx.compose.ui.input.nestedscroll.nestedScroll\nimport androidx.compose.ui.layout.SubcomposeLayout\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.TextLayoutResult\nimport androidx.compose.ui.text.font.FontWeight\nimport androidx.compose.ui.text.style.TextAlign\nimport androidx.compose.ui.text.style.TextDecoration\nimport androidx.compose.ui.text.style.TextOverflow\nimport androidx.compose.ui.unit.Constraints\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.unit.sp\nimport androidx.core.net.toUri\nimport androidx.lifecycle.viewmodel.compose.viewModel\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport com.ramcosta.composedestinations.generated.destinations.ExecuteAPMActionScreenDestination\nimport com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination\nimport com.ramcosta.composedestinations.navigation.DestinationsNavigator\nimport com.topjohnwu.superuser.io.SuFile\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.R\nimport me.bmax.apatch.apApp\nimport me.bmax.apatch.ui.WebUIActivity\nimport me.bmax.apatch.ui.component.ConfirmResult\nimport me.bmax.apatch.ui.component.ModuleRemoveButton\nimport me.bmax.apatch.ui.component.ModuleStateIndicator\nimport me.bmax.apatch.ui.component.ModuleUpdateButton\nimport me.bmax.apatch.ui.component.SearchAppBar\nimport me.bmax.apatch.ui.component.WarningCard\nimport me.bmax.apatch.ui.component.pinnedScrollBehavior\nimport me.bmax.apatch.ui.component.rememberConfirmDialog\nimport me.bmax.apatch.ui.component.rememberLoadingDialog\nimport me.bmax.apatch.ui.viewmodel.APModuleViewModel\nimport me.bmax.apatch.util.DownloadListener\nimport me.bmax.apatch.util.download\nimport me.bmax.apatch.util.hasMagisk\nimport me.bmax.apatch.util.reboot\nimport me.bmax.apatch.util.toggleModule\nimport me.bmax.apatch.util.ui.LocalSnackbarHost\nimport me.bmax.apatch.util.uninstallModule\nimport okhttp3.Request\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Destination<RootGraph>\n@Composable\nfun APModuleScreen(navigator: DestinationsNavigator) {\n    val snackBarHost = LocalSnackbarHost.current\n    val context = LocalContext.current\n\n    val state by APApplication.apStateLiveData.observeAsState(APApplication.State.UNKNOWN_STATE)\n    if (state != APApplication.State.ANDROIDPATCH_INSTALLED && state != APApplication.State.ANDROIDPATCH_NEED_UPDATE) {\n        Column(\n            modifier = Modifier\n                .fillMaxSize()\n                .padding(12.dp),\n            verticalArrangement = Arrangement.Center,\n            horizontalAlignment = Alignment.CenterHorizontally\n        ) {\n            Row {\n                Text(\n                    text = stringResource(id = R.string.apm_not_installed),\n                    style = MaterialTheme.typography.titleMedium\n                )\n            }\n        }\n        return\n    }\n\n    val viewModel = viewModel<APModuleViewModel>()\n\n    LaunchedEffect(Unit) {\n        if (viewModel.moduleList.isEmpty() || viewModel.isNeedRefresh) {\n            viewModel.fetchModuleList()\n        }\n    }\n    val webUILauncher = rememberLauncherForActivityResult(\n        contract = ActivityResultContracts.StartActivityForResult()\n    ) { viewModel.fetchModuleList() }\n    val scrollBehavior = pinnedScrollBehavior()\n\n    //TODO: FIXME -> val isSafeMode = Natives.getSafeMode()\n    val isSafeMode = false\n    val hasMagisk = hasMagisk()\n    val hideInstallButton = isSafeMode || hasMagisk\n\n    val moduleListState = rememberLazyListState()\n\n    Scaffold(\n        topBar = {\n            SearchAppBar(\n                searchText = viewModel.search,\n                onSearchTextChange = { viewModel.search = it },\n                searchBarPlaceHolderText = stringResource(R.string.search_modules)\n            )\n        },\n        floatingActionButton = {\n            if (hideInstallButton) return@Scaffold\n            val selectZipLauncher = rememberLauncherForActivityResult(\n                contract = ActivityResultContracts.StartActivityForResult()\n            ) {\n                if (it.resultCode != RESULT_OK) {\n                    return@rememberLauncherForActivityResult\n                }\n                val data = it.data ?: return@rememberLauncherForActivityResult\n                val uri = data.data ?: return@rememberLauncherForActivityResult\n\n                Log.i(\"ModuleScreen\", \"select zip result: $uri\")\n\n                navigator.navigate(InstallScreenDestination(uri, MODULE_TYPE.APM))\n\n                viewModel.markNeedRefresh()\n            }\n\n            FloatingActionButton(\n                contentColor = MaterialTheme.colorScheme.onPrimary,\n                containerColor = MaterialTheme.colorScheme.primary,\n                onClick = {\n                    // select the zip file to install\n                    val intent = Intent(Intent.ACTION_GET_CONTENT)\n                    intent.type = \"application/zip\"\n                    selectZipLauncher.launch(intent)\n                }) {\n                Icon(\n                    painter = painterResource(id = R.drawable.package_import),\n                    contentDescription = null\n                )\n            }\n        },\n        snackbarHost = { SnackbarHost(snackBarHost) }\n    ) { innerPadding ->\n        when {\n            hasMagisk -> {\n                Box(\n                    modifier = Modifier\n                        .fillMaxSize()\n                        .padding(24.dp),\n                    contentAlignment = Alignment.Center\n                ) {\n                    Text(\n                        stringResource(R.string.apm_magisk_conflict),\n                        textAlign = TextAlign.Center,\n                    )\n                }\n            }\n\n            else -> {\n                ModuleList(\n                    navigator = navigator,\n                    viewModel = viewModel,\n                    modules = viewModel.moduleList,\n                    modifier = Modifier\n                        .padding(innerPadding)\n                        .fillMaxSize(),\n                    state = moduleListState,\n                    onInstallModule = {\n                        navigator.navigate(InstallScreenDestination(it, MODULE_TYPE.APM))\n                    },\n                    onClickModule = { id, name, hasWebUi ->\n                        if (hasWebUi) {\n                            webUILauncher.launch(\n                                Intent(\n                                    context, WebUIActivity::class.java\n                                ).setData(\"apatch://webui/$id\".toUri()).putExtra(\"id\", id)\n                                    .putExtra(\"name\", name)\n                            )\n                        }\n                    },\n                    snackBarHost = snackBarHost,\n                    scrollBehavior = scrollBehavior\n                )\n            }\n        }\n    }\n}\n\nprivate fun getMetaModuleWarningText(\n    viewModel: APModuleViewModel,\n    context: Context\n) : String? {\n    val needsMountModule = viewModel.moduleList.any { module ->\n        val moduleDir = \"/data/adb/modules/${module.id}\"\n\n        // Module requires mounting if it has a system dir and no skip_mount file\n        val hasSystem = SuFile.open(\"$moduleDir/system\").isDirectory\n        val isSkipped = SuFile.open(\"$moduleDir/skip_mount\").isFile\n\n        hasSystem && !isSkipped\n    }\n\n    if (!needsMountModule) return null\n\n    val metaDir = \"/data/adb/metamodule\"\n    val metaProp = SuFile.open(\"$metaDir/module.prop\").isFile\n    val metaRemoved = SuFile.open(\"$metaDir/remove\").isFile\n    val metaDisabled = SuFile.open(\"$metaDir/disable\").isFile\n\n    return when {\n        !metaProp -> context.getString(R.string.no_meta_module_installed)\n        metaRemoved -> context.getString(R.string.meta_module_removed)\n        metaDisabled -> context.getString(R.string.meta_module_disabled)\n        else -> null\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun MetaModuleWarningCard(\n    text: String\n) {\n    var show by rememberSaveable { mutableStateOf(true) }\n\n    AnimatedVisibility(\n        visible = show,\n        enter = fadeIn() + expandVertically(),\n        exit = fadeOut() + shrinkVertically()\n    ) {\n        WarningCard(\n            message = text,\n            onClose = {\n                show = false\n            }\n        )\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun ModuleList(\n    navigator: DestinationsNavigator,\n    viewModel: APModuleViewModel,\n    modules: List<APModuleViewModel.ModuleInfo>,\n    modifier: Modifier = Modifier,\n    state: LazyListState,\n    onInstallModule: (Uri) -> Unit,\n    onClickModule: (id: String, name: String, hasWebUi: Boolean) -> Unit,\n    snackBarHost: SnackbarHostState,\n    scrollBehavior: SearchBarScrollBehavior\n) {\n    val failedEnable = stringResource(R.string.apm_failed_to_enable)\n    val failedDisable = stringResource(R.string.apm_failed_to_disable)\n    val failedUninstall = stringResource(R.string.apm_uninstall_failed)\n    val successUninstall = stringResource(R.string.apm_uninstall_success)\n    val reboot = stringResource(id = R.string.reboot)\n    val rebootToApply = stringResource(id = R.string.apm_reboot_to_apply)\n    val moduleStr = stringResource(id = R.string.apm)\n    val uninstall = stringResource(id = R.string.apm_remove)\n    val cancel = stringResource(id = android.R.string.cancel)\n    val moduleUninstallConfirm = stringResource(id = R.string.apm_uninstall_confirm)\n    val metaModuleUninstallConfirm = stringResource(R.string.metamodule_uninstall_confirm)\n    val updateText = stringResource(R.string.apm_update)\n    val changelogText = stringResource(R.string.apm_changelog)\n    val downloadingText = stringResource(R.string.apm_downloading)\n    val startDownloadingText = stringResource(R.string.apm_start_downloading)\n\n    val context = LocalContext.current\n    val loadingDialog = rememberLoadingDialog()\n    val confirmDialog = rememberConfirmDialog()\n\n    suspend fun onModuleUpdate(\n        module: APModuleViewModel.ModuleInfo,\n        changelogUrl: String,\n        downloadUrl: String,\n        fileName: String\n    ) {\n        val changelog = loadingDialog.withLoading {\n            withContext(Dispatchers.IO) {\n                runCatching {\n                    if (Patterns.WEB_URL.matcher(changelogUrl).matches()) {\n                        apApp.okhttpClient.newCall(\n                                Request.Builder().url(changelogUrl).build()\n                            ).execute().use { it.body?.string().orEmpty() }\n                    } else {\n                        changelogUrl\n                    }\n                }.getOrDefault(\"\")\n            }\n        }\n\n\n        if (changelog.isNotEmpty()) {\n            // changelog is not empty, show it and wait for confirm\n            val confirmResult = confirmDialog.awaitConfirm(\n                changelogText,\n                content = changelog,\n                markdown = true,\n                confirm = updateText,\n            )\n\n            if (confirmResult != ConfirmResult.Confirmed) {\n                return\n            }\n        }\n\n        withContext(Dispatchers.Main) {\n            Toast.makeText(\n                context, startDownloadingText.format(module.name), Toast.LENGTH_SHORT\n            ).show()\n        }\n\n        val downloading = downloadingText.format(module.name)\n        withContext(Dispatchers.IO) {\n            download(\n                context,\n                downloadUrl,\n                fileName,\n                downloading,\n                onDownloaded = onInstallModule,\n                onDownloading = {\n                    launch(Dispatchers.Main) {\n                        Toast.makeText(context, downloading, Toast.LENGTH_SHORT).show()\n                    }\n                })\n        }\n    }\n\n    suspend fun onModuleUninstall(module: APModuleViewModel.ModuleInfo) {\n        val formatter = if (module.metamodule) metaModuleUninstallConfirm else moduleUninstallConfirm\n        val confirmResult = confirmDialog.awaitConfirm(\n            moduleStr,\n            content = formatter.format(module.name),\n            confirm = uninstall,\n            dismiss = cancel\n        )\n        if (confirmResult != ConfirmResult.Confirmed) {\n            return\n        }\n\n        val success = loadingDialog.withLoading {\n            withContext(Dispatchers.IO) {\n                uninstallModule(module.id)\n            }\n        }\n\n        if (success) {\n            viewModel.fetchModuleList()\n        }\n        val message = if (success) {\n            successUninstall.format(module.name)\n        } else {\n            failedUninstall.format(module.name)\n        }\n        val actionLabel = if (success) {\n            reboot\n        } else {\n            null\n        }\n        val result = snackBarHost.showSnackbar(\n            message = message, actionLabel = actionLabel, duration = SnackbarDuration.Long\n        )\n        if (result == SnackbarResult.ActionPerformed) {\n            reboot()\n        }\n    }\n\n    PullToRefreshBox(\n        modifier = modifier,\n        onRefresh = { viewModel.fetchModuleList() },\n        isRefreshing = viewModel.isRefreshing\n    ) {\n        val metaModuleWarningText by produceState<String?>(initialValue = null, viewModel.moduleList) {\n            value = withContext(Dispatchers.IO) {\n                getMetaModuleWarningText(viewModel, context)\n            }\n        }\n\n        LazyColumn(\n            modifier = Modifier.fillMaxSize().nestedScroll(scrollBehavior.nestedScrollConnection),\n            state = state,\n            verticalArrangement = Arrangement.spacedBy(16.dp),\n            contentPadding = remember {\n                PaddingValues(\n                    start = 16.dp,\n                    top = 11.dp, // spacedBy - TopBar padding\n                    end = 16.dp,\n                    bottom = 16.dp + 16.dp + 56.dp /*  Scaffold Fab Spacing + Fab container height */\n                )\n            },\n        ) {\n            if (metaModuleWarningText != null) {\n                item {\n                    MetaModuleWarningCard(metaModuleWarningText!!)\n                }\n            }\n\n            when {\n                modules.isEmpty() -> {\n                    item {\n                        Box(\n                            modifier = Modifier.fillParentMaxSize(),\n                            contentAlignment = Alignment.Center\n                        ) {\n                            Text(\n                                stringResource(R.string.apm_empty), textAlign = TextAlign.Center\n                            )\n                        }\n                    }\n                }\n\n                else -> {\n                    items(modules) { module ->\n                        var isChecked by rememberSaveable(module) { mutableStateOf(module.enabled) }\n                        val scope = rememberCoroutineScope()\n                        val updateInfo = module.updateInfo\n\n                        ModuleItem(\n                            navigator,\n                            module,\n                            isChecked,\n                            updateInfo?.zipUrl ?: \"\",\n                            onUninstall = {\n                                scope.launch { onModuleUninstall(module) }\n                            },\n                            onCheckChanged = {\n                                scope.launch {\n                                    val success = loadingDialog.withLoading {\n                                        withContext(Dispatchers.IO) {\n                                            toggleModule(module.id, !isChecked)\n                                        }\n                                    }\n                                    if (success) {\n                                        isChecked = it\n                                        viewModel.fetchModuleList()\n\n                                        val result = snackBarHost.showSnackbar(\n                                            message = rebootToApply,\n                                            actionLabel = reboot,\n                                            duration = SnackbarDuration.Long\n                                        )\n                                        if (result == SnackbarResult.ActionPerformed) {\n                                            reboot()\n                                        }\n                                    } else {\n                                        val message = if (isChecked) failedDisable else failedEnable\n                                        snackBarHost.showSnackbar(message.format(module.name))\n                                    }\n                                }\n                            },\n                            onUpdate = {\n                                scope.launch {\n                                    updateInfo?.let { info ->\n                                        onModuleUpdate(\n                                            module,\n                                            info.changelog,\n                                            info.zipUrl,\n                                            \"${module.name}-${info.version}.zip\"\n                                        )\n                                    }\n                                }\n                            },\n                            onClick = {\n                                onClickModule(it.id, it.name, it.hasWebUi)\n                            })\n                        // fix last item shadow incomplete in LazyColumn\n                        Spacer(Modifier.height(1.dp))\n                    }\n                }\n            }\n        }\n\n        DownloadListener(context, onInstallModule)\n    }\n}\n\n@Composable\nprivate fun ModuleItem(\n    navigator: DestinationsNavigator,\n    module: APModuleViewModel.ModuleInfo,\n    isChecked: Boolean,\n    updateUrl: String,\n    onUninstall: (APModuleViewModel.ModuleInfo) -> Unit,\n    onCheckChanged: (Boolean) -> Unit,\n    onUpdate: (APModuleViewModel.ModuleInfo) -> Unit,\n    onClick: (APModuleViewModel.ModuleInfo) -> Unit,\n    modifier: Modifier = Modifier,\n    alpha: Float = 1f,\n) {\n    val decoration = if (!module.remove) TextDecoration.None else TextDecoration.LineThrough\n    val moduleAuthor = stringResource(id = R.string.apm_author)\n    val viewModel = viewModel<APModuleViewModel>()\n    Surface(\n        modifier = modifier,\n        color = MaterialTheme.colorScheme.surface,\n        tonalElevation = 1.dp,\n        shape = RoundedCornerShape(20.dp)\n    ) {\n\n        Box(\n            modifier = Modifier\n                .fillMaxWidth()\n                .clickable { onClick(module) },\n            contentAlignment = Alignment.Center\n        ) {\n            Column(\n                modifier = Modifier.fillMaxWidth()\n            ) {\n                Row(\n                    modifier = Modifier.padding(all = 16.dp),\n                    verticalAlignment = Alignment.CenterVertically\n                ) {\n                    Column(\n                        modifier = Modifier\n                            .alpha(alpha = alpha)\n                            .weight(1f),\n                        verticalArrangement = Arrangement.spacedBy(2.dp)\n                    ) {\n                        SubcomposeLayout { constraints ->\n                            val spacingPx = 6.dp.roundToPx()\n                            var nameTextLayout: TextLayoutResult? = null\n                            val metaPlaceable = if (module.metamodule) {\n                                subcompose(\"meta\") {\n                                    Surface(\n                                        shape = RoundedCornerShape(4.dp),\n                                        color = MaterialTheme.colorScheme.tertiary\n                                    ) {\n                                        Text(\n                                            text = \"META\",\n                                            style = MaterialTheme.typography.labelSmall.copy(\n                                                fontSize = 10.sp\n                                            ),\n                                            modifier = Modifier.padding(horizontal = 4.dp, vertical = 1.dp),\n                                            color = MaterialTheme.colorScheme.onTertiary,\n                                            maxLines = 1,\n                                            overflow = TextOverflow.Ellipsis\n                                        )\n                                    }\n                                }.first().measure(Constraints(0, constraints.maxWidth, 0, constraints.maxHeight))\n                            } else null\n\n                            val reserved = (metaPlaceable?.width ?: 0) + if (metaPlaceable != null) spacingPx else 0\n                            val nameMax = (constraints.maxWidth - reserved).coerceAtLeast(0)\n                            val namePlaceable = subcompose(\"name\") {\n                                Text(\n                                    text = module.name,\n                                    style = MaterialTheme.typography.titleSmall.copy(fontWeight = FontWeight.Bold),\n                                    maxLines = 2,\n                                    textDecoration = decoration,\n                                    overflow = TextOverflow.Ellipsis,\n                                    onTextLayout = { nameTextLayout = it }\n                                )\n                            }.first().measure(Constraints(constraints.minWidth, nameMax, constraints.minHeight, constraints.maxHeight))\n\n                            val width = (namePlaceable.width + reserved).coerceIn(constraints.minWidth, constraints.maxWidth)\n                            val height = maxOf(namePlaceable.height, metaPlaceable?.height ?: 0)\n\n                            layout(width, height) {\n                                namePlaceable.placeRelative(0, 0)\n                                val endX = nameTextLayout?.let { layoutRes ->\n                                    val last = (layoutRes.lineCount - 1).coerceAtLeast(0)\n                                    layoutRes.getLineRight(last).toInt()\n                                } ?: namePlaceable.width\n                                metaPlaceable?.placeRelative(endX + spacingPx, (height - (metaPlaceable.height)) / 2)\n                            }\n                        }\n\n                        Text(\n                            text = \"${module.version}, $moduleAuthor ${module.author}\",\n                            style = MaterialTheme.typography.bodySmall,\n                            textDecoration = decoration,\n                            color = MaterialTheme.colorScheme.onSurfaceVariant\n                        )\n                    }\n\n                    Switch(\n                        enabled = !module.update,\n                        checked = isChecked,\n                        onCheckedChange = onCheckChanged\n                    )\n                }\n\n                Text(\n                    modifier = Modifier\n                        .alpha(alpha = alpha)\n                        .padding(horizontal = 16.dp),\n                    text = module.description,\n                    style = MaterialTheme.typography.bodySmall,\n                    textDecoration = decoration,\n                    color = MaterialTheme.colorScheme.outline\n                )\n\n                HorizontalDivider(\n                    thickness = 1.5.dp,\n                    color = MaterialTheme.colorScheme.surface,\n                    modifier = Modifier.padding(top = 8.dp)\n                )\n\n                Row(\n                    modifier = Modifier\n                        .padding(horizontal = 16.dp, vertical = 8.dp)\n                        .fillMaxWidth(),\n                    verticalAlignment = Alignment.CenterVertically\n                ) {\n                    if (updateUrl.isNotEmpty()) {\n                        ModuleUpdateButton(onClick = { onUpdate(module) })\n\n                        Spacer(modifier = Modifier.width(12.dp))\n                    }\n\n                    if (module.hasWebUi) {\n                        FilledTonalButton(\n                            onClick = { onClick(module) },\n                            enabled = true,\n                            contentPadding = PaddingValues(12.dp)\n                        ) {\n                            Icon(\n                                modifier = Modifier.size(20.dp),\n                                painter = painterResource(id = R.drawable.webui),\n                                contentDescription = stringResource(id = R.string.apm_webui_open)\n                            )\n                        }\n\n                        Spacer(modifier = Modifier.width(12.dp))\n                    }\n\n                    Spacer(modifier = Modifier.weight(1f))\n\n                    if (module.hasActionScript) {\n                        FilledTonalButton(\n                            onClick = {\n                                navigator.navigate(ExecuteAPMActionScreenDestination(module.id))\n                                viewModel.markNeedRefresh()\n                            }, enabled = true, contentPadding = PaddingValues(12.dp)\n                        ) {\n                            Icon(\n                                modifier = Modifier.size(20.dp),\n                                painter = painterResource(id = R.drawable.play_circle),\n                                contentDescription = stringResource(id = R.string.apm_action)\n                            )\n                        }\n\n                        Spacer(modifier = Modifier.width(12.dp))\n                    }\n                    ModuleRemoveButton(enabled = !module.remove, onClick = { onUninstall(module) })\n                }\n            }\n\n            if (module.remove) {\n                ModuleStateIndicator(R.drawable.trash)\n            }\n            if (module.update) {\n                ModuleStateIndicator(R.drawable.device_mobile_down)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/AboutScreen.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport androidx.compose.foundation.Image\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.rememberScrollState\nimport androidx.compose.foundation.shape.CircleShape\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.foundation.verticalScroll\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.automirrored.filled.ArrowBack\nimport androidx.compose.material3.ButtonDefaults\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.FilledTonalButton\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.OutlinedCard\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TopAppBar\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.draw.scale\nimport androidx.compose.ui.platform.LocalUriHandler\nimport androidx.compose.ui.res.colorResource\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.unit.dp\nimport androidx.lifecycle.compose.dropUnlessResumed\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport com.ramcosta.composedestinations.navigation.DestinationsNavigator\nimport me.bmax.apatch.BuildConfig\nimport me.bmax.apatch.R\nimport me.bmax.apatch.util.Version\n\n@Destination<RootGraph>\n@Composable\nfun AboutScreen(navigator: DestinationsNavigator) {\n    val uriHandler = LocalUriHandler.current\n\n    Scaffold(\n        topBar = {\n            TopBar(onBack = dropUnlessResumed { navigator.popBackStack() })\n        }\n    ) { innerPadding ->\n        Column(\n            modifier = Modifier\n                .padding(innerPadding)\n                .fillMaxWidth()\n                .verticalScroll(rememberScrollState()),\n            horizontalAlignment = Alignment.CenterHorizontally\n        ) {\n            Spacer(modifier = Modifier.height(20.dp))\n            Surface(\n                modifier = Modifier.size(95.dp),\n                color = colorResource(id = R.color.ic_launcher_background),\n                shape = CircleShape\n            ) {\n                Image(\n                    painter = painterResource(id = R.drawable.ic_launcher_foreground),\n                    contentDescription = \"icon\",\n                    modifier = Modifier.scale(1.4f)\n                )\n            }\n\n            Spacer(modifier = Modifier.height(20.dp))\n            Text(\n                text = stringResource(id = R.string.app_name),\n                style = MaterialTheme.typography.titleLarge\n            )\n            Text(\n                text = stringResource(\n                    id = R.string.about_app_version,\n                    if (BuildConfig.VERSION_NAME.contains(BuildConfig.VERSION_CODE.toString())) \"${BuildConfig.VERSION_CODE}\" else \"${BuildConfig.VERSION_CODE} (${BuildConfig.VERSION_NAME})\"\n                ),\n                style = MaterialTheme.typography.bodyMedium,\n                color = MaterialTheme.colorScheme.onSurfaceVariant,\n                modifier = Modifier.padding(top = 5.dp)\n            )\n            Text(\n\n                text = stringResource(\n                    id = R.string.about_powered_by,\n                    \"KernelPatch (${Version.buildKPVString()})\"\n                ),\n                style = MaterialTheme.typography.bodyMedium,\n                color = MaterialTheme.colorScheme.onSurfaceVariant,\n                modifier = Modifier.padding(top = 5.dp)\n            )\n\n            Spacer(modifier = Modifier.height(20.dp))\n\n            Row(\n                modifier = Modifier.padding(top = 8.dp),\n                verticalAlignment = Alignment.CenterVertically,\n                horizontalArrangement = Arrangement.spacedBy(8.dp)\n            ) {\n                FilledTonalButton(\n                    onClick = { uriHandler.openUri(\"https://github.com/bmax121/APatch\") }\n                ) {\n                    Icon(\n                        painter = painterResource(id = R.drawable.github),\n                        contentDescription = null\n                    )\n                    Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))\n                    Text(text = stringResource(id = R.string.about_github))\n                }\n\n                FilledTonalButton(\n                    onClick = { uriHandler.openUri(\"https://t.me/APatchChannel\") }\n                ) {\n                    Icon(\n                        painter = painterResource(id = R.drawable.telegram),\n                        contentDescription = null\n                    )\n                    Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))\n                    Text(text = stringResource(id = R.string.about_telegram_channel))\n                }\n            }\n\n            Row(\n                modifier = Modifier.padding(top = 8.dp),\n                verticalAlignment = Alignment.CenterVertically,\n                horizontalArrangement = Arrangement.spacedBy(8.dp)\n            ) {\n                FilledTonalButton(\n                    onClick = { uriHandler.openUri(\"https://hosted.weblate.org/engage/APatch\") }\n                ) {\n                    Icon(\n                        painter = painterResource(id = R.drawable.weblate),\n                        contentDescription = null,\n                        modifier = Modifier.size(ButtonDefaults.IconSize)\n                    )\n                    Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))\n                    Text(text = stringResource(id = R.string.about_weblate))\n                }\n\n                FilledTonalButton(\n                    onClick = { uriHandler.openUri(\"https://t.me/apatch_discuss\") }\n                ) {\n                    Icon(\n                        painter = painterResource(id = R.drawable.telegram),\n                        contentDescription = null\n                    )\n                    Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))\n                    Text(text = stringResource(id = R.string.about_telegram_group))\n                }\n            }\n\n            OutlinedCard(\n                modifier = Modifier.padding(vertical = 30.dp, horizontal = 20.dp),\n                shape = RoundedCornerShape(15.dp)\n            ) {\n                Column(\n                    modifier = Modifier\n                        .fillMaxWidth()\n                        .padding(all = 12.dp)\n                ) {\n                    Text(\n                        text = stringResource(id = R.string.about_app_desc),\n                        style = MaterialTheme.typography.bodyMedium,\n                        color = MaterialTheme.colorScheme.onSurfaceVariant\n                    )\n                }\n            }\n\n        }\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun TopBar(onBack: () -> Unit = {}) {\n    TopAppBar(\n        title = { Text(stringResource(R.string.about)) },\n        navigationIcon = {\n            IconButton(\n                onClick = onBack\n            ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }\n        },\n    )\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/BottomBarDestination.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport androidx.annotation.StringRes\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.filled.Apps\nimport androidx.compose.material.icons.filled.Build\nimport androidx.compose.material.icons.filled.Home\nimport androidx.compose.material.icons.filled.Security\nimport androidx.compose.material.icons.filled.Settings\nimport androidx.compose.material.icons.outlined.Apps\nimport androidx.compose.material.icons.outlined.Build\nimport androidx.compose.material.icons.outlined.Home\nimport androidx.compose.material.icons.outlined.Security\nimport androidx.compose.material.icons.outlined.Settings\nimport androidx.compose.ui.graphics.vector.ImageVector\nimport com.ramcosta.composedestinations.generated.destinations.APModuleScreenDestination\nimport com.ramcosta.composedestinations.generated.destinations.HomeScreenDestination\nimport com.ramcosta.composedestinations.generated.destinations.KPModuleScreenDestination\nimport com.ramcosta.composedestinations.generated.destinations.SettingScreenDestination\nimport com.ramcosta.composedestinations.generated.destinations.SuperUserScreenDestination\nimport com.ramcosta.composedestinations.spec.DirectionDestinationSpec\nimport me.bmax.apatch.R\n\nenum class BottomBarDestination(\n    val direction: DirectionDestinationSpec,\n    @param:StringRes val label: Int,\n    val iconSelected: ImageVector,\n    val iconNotSelected: ImageVector,\n    val kPatchRequired: Boolean,\n    val aPatchRequired: Boolean,\n) {\n    Home(\n        HomeScreenDestination,\n        R.string.home,\n        Icons.Filled.Home,\n        Icons.Outlined.Home,\n        false,\n        false\n    ),\n    KModule(\n        KPModuleScreenDestination,\n        R.string.kpm,\n        Icons.Filled.Build,\n        Icons.Outlined.Build,\n        true,\n        false\n    ),\n    SuperUser(\n        SuperUserScreenDestination,\n        R.string.su_title,\n        Icons.Filled.Security,\n        Icons.Outlined.Security,\n        true,\n        false\n    ),\n    AModule(\n        APModuleScreenDestination,\n        R.string.apm,\n        Icons.Filled.Apps,\n        Icons.Outlined.Apps,\n        false,\n        true\n    ),\n    Settings(\n        SettingScreenDestination,\n        R.string.settings,\n        Icons.Filled.Settings,\n        Icons.Outlined.Settings,\n        false,\n        false\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/ExecuteAPMAction.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport android.os.Environment\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.rememberScrollState\nimport androidx.compose.foundation.verticalScroll\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.automirrored.filled.ArrowBack\nimport androidx.compose.material.icons.filled.Save\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.SnackbarHost\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TopAppBar\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.saveable.rememberSaveable\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.input.key.Key\nimport androidx.compose.ui.input.key.key\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.font.FontFamily\nimport androidx.compose.ui.unit.dp\nimport androidx.lifecycle.compose.dropUnlessResumed\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport com.ramcosta.composedestinations.navigation.DestinationsNavigator\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport me.bmax.apatch.R\nimport me.bmax.apatch.ui.component.KeyEventBlocker\nimport me.bmax.apatch.util.runAPModuleAction\nimport me.bmax.apatch.util.ui.LocalSnackbarHost\nimport java.io.File\nimport java.text.SimpleDateFormat\nimport java.util.Date\nimport java.util.Locale\n\n@Composable\n@Destination<RootGraph>\nfun ExecuteAPMActionScreen(navigator: DestinationsNavigator, moduleId: String) {\n    var text by rememberSaveable { mutableStateOf(\"\") }\n    var tempText: String\n    val logContent = rememberSaveable { StringBuilder() }\n    val snackBarHost = LocalSnackbarHost.current\n    val scope = rememberCoroutineScope()\n    val scrollState = rememberScrollState()\n    var actionResult: Boolean\n\n    LaunchedEffect(Unit) {\n        if (text.isNotEmpty()) {\n            return@LaunchedEffect\n        }\n        withContext(Dispatchers.IO) {\n            runAPModuleAction(\n                moduleId,\n                onStdout = {\n                    tempText = \"$it\\n\"\n                    if (tempText.startsWith(\"\u001b[H\u001b[J\")) { // clear command\n                        text = tempText.substring(6)\n                    } else {\n                        text += tempText\n                    }\n                    logContent.append(it).append(\"\\n\")\n                },\n                onStderr = {\n                    logContent.append(it).append(\"\\n\")\n                }\n            ).let {\n                actionResult = it\n            }\n        }\n        if (actionResult) {\n            navigator.popBackStack()\n        }\n    }\n\n    Scaffold(\n        topBar = {\n            TopBar(\n                onBack = dropUnlessResumed {\n                    navigator.popBackStack()\n                },\n                onSave = {\n                    scope.launch {\n                        val format = SimpleDateFormat(\"yyyy-MM-dd-HH-mm-ss\", Locale.getDefault())\n                        val date = format.format(Date())\n                        val file = File(\n                            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),\n                            \"APatch_apm_action_log_${date}.log\"\n                        )\n                        file.writeText(logContent.toString())\n                        snackBarHost.showSnackbar(\"Log saved to ${file.absolutePath}\")\n                    }\n                }\n            )\n        },\n        snackbarHost = { SnackbarHost(snackBarHost) }\n    ) { innerPadding ->\n        KeyEventBlocker {\n            it.key == Key.VolumeDown || it.key == Key.VolumeUp\n        }\n        Column(\n            modifier = Modifier\n                .fillMaxSize(1f)\n                .padding(innerPadding)\n                .verticalScroll(scrollState),\n        ) {\n            LaunchedEffect(text) {\n                scrollState.animateScrollTo(scrollState.maxValue)\n            }\n            Text(\n                modifier = Modifier.padding(8.dp),\n                text = text,\n                fontSize = MaterialTheme.typography.bodySmall.fontSize,\n                fontFamily = FontFamily.Monospace,\n                lineHeight = MaterialTheme.typography.bodySmall.lineHeight,\n            )\n        }\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {\n    TopAppBar(\n        title = { Text(stringResource(R.string.apm_action)) },\n        navigationIcon = {\n            IconButton(\n                onClick = onBack\n            ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }\n        },\n        actions = {\n            IconButton(onClick = onSave) {\n                Icon(\n                    imageVector = Icons.Filled.Save,\n                    contentDescription = \"Save log\"\n                )\n            }\n        }\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/Home.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport android.os.Build\nimport android.system.Os\nimport androidx.annotation.StringRes\nimport androidx.compose.animation.AnimatedVisibility\nimport androidx.compose.animation.expandVertically\nimport androidx.compose.animation.fadeIn\nimport androidx.compose.animation.fadeOut\nimport androidx.compose.animation.shrinkVertically\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.layout.wrapContentHeight\nimport androidx.compose.foundation.rememberScrollState\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.foundation.text.KeyboardOptions\nimport androidx.compose.foundation.verticalScroll\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.automirrored.outlined.HelpOutline\nimport androidx.compose.material.icons.filled.CheckCircle\nimport androidx.compose.material.icons.filled.InstallMobile\nimport androidx.compose.material.icons.filled.MoreVert\nimport androidx.compose.material.icons.filled.Refresh\nimport androidx.compose.material.icons.filled.Visibility\nimport androidx.compose.material.icons.filled.VisibilityOff\nimport androidx.compose.material.icons.filled.Warning\nimport androidx.compose.material.icons.outlined.Block\nimport androidx.compose.material.icons.outlined.Cached\nimport androidx.compose.material.icons.outlined.CheckCircle\nimport androidx.compose.material.icons.outlined.Clear\nimport androidx.compose.material.icons.outlined.InstallMobile\nimport androidx.compose.material.icons.outlined.SystemUpdate\nimport androidx.compose.material3.AlertDialogDefaults\nimport androidx.compose.material3.BasicAlertDialog\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.CardDefaults\nimport androidx.compose.material3.DropdownMenu\nimport androidx.compose.material3.DropdownMenuItem\nimport androidx.compose.material3.ElevatedCard\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.OutlinedTextField\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TextButton\nimport androidx.compose.material3.TopAppBar\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.MutableState\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.livedata.observeAsState\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.produceState\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.saveable.rememberSaveable\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.platform.LocalUriHandler\nimport androidx.compose.ui.platform.LocalView\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.input.KeyboardType\nimport androidx.compose.ui.text.input.PasswordVisualTransformation\nimport androidx.compose.ui.text.input.VisualTransformation\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.window.DialogProperties\nimport androidx.compose.ui.window.DialogWindowProvider\nimport androidx.compose.ui.window.SecureFlagPolicy\nimport androidx.lifecycle.compose.dropUnlessResumed\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport com.ramcosta.composedestinations.generated.destinations.AboutScreenDestination\nimport com.ramcosta.composedestinations.generated.destinations.InstallModeSelectScreenDestination\nimport com.ramcosta.composedestinations.generated.destinations.PatchesDestination\nimport com.ramcosta.composedestinations.navigation.DestinationsNavigator\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.Natives\nimport me.bmax.apatch.R\nimport me.bmax.apatch.apApp\nimport me.bmax.apatch.ui.component.ProvideMenuShape\nimport me.bmax.apatch.ui.component.WarningCard\nimport me.bmax.apatch.ui.component.rememberConfirmDialog\nimport me.bmax.apatch.ui.viewmodel.PatchesViewModel\nimport me.bmax.apatch.util.LatestVersionInfo\nimport me.bmax.apatch.util.Version\nimport me.bmax.apatch.util.Version.getManagerVersion\nimport me.bmax.apatch.util.checkNewVersion\nimport me.bmax.apatch.util.getSELinuxStatus\nimport me.bmax.apatch.util.reboot\nimport me.bmax.apatch.util.ui.APDialogBlurBehindUtils\n\nprivate val managerVersion = getManagerVersion()\n\n@Destination<RootGraph>(start = true)\n@Composable\nfun HomeScreen(navigator: DestinationsNavigator) {\n    var showPatchFloatAction by remember { mutableStateOf(true) }\n\n    val kpState by APApplication.kpStateLiveData.observeAsState(APApplication.State.UNKNOWN_STATE)\n    val apState by APApplication.apStateLiveData.observeAsState(APApplication.State.UNKNOWN_STATE)\n\n    if (kpState != APApplication.State.UNKNOWN_STATE) {\n        showPatchFloatAction = false\n    }\n\n    Scaffold(topBar = {\n        TopBar(onInstallClick = dropUnlessResumed {\n            navigator.navigate(InstallModeSelectScreenDestination)\n        }, navigator, kpState)\n    }) { innerPadding ->\n        Column(\n            modifier = Modifier\n                .padding(innerPadding)\n                .padding(horizontal = 16.dp)\n                .verticalScroll(rememberScrollState()),\n            verticalArrangement = Arrangement.spacedBy(16.dp)\n        ) {\n            Spacer(Modifier.height(0.dp))\n            WarningCard()\n            KStatusCard(kpState, apState, navigator)\n            if (kpState != APApplication.State.UNKNOWN_STATE && apState != APApplication.State.ANDROIDPATCH_INSTALLED) {\n                AStatusCard(apState)\n            }\n            val checkUpdate = APApplication.sharedPreferences.getBoolean(\"check_update\", true)\n            if (checkUpdate) {\n                UpdateCard()\n            }\n            InfoCard(kpState, apState)\n            LearnMoreCard()\n            Spacer(Modifier)\n        }\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun UninstallDialog(showDialog: MutableState<Boolean>, navigator: DestinationsNavigator) {\n    BasicAlertDialog(\n        onDismissRequest = { showDialog.value = false }, properties = DialogProperties(\n            decorFitsSystemWindows = true,\n            usePlatformDefaultWidth = false,\n        )\n    ) {\n        Surface(\n            modifier = Modifier\n                .width(320.dp)\n                .wrapContentHeight(),\n            shape = RoundedCornerShape(20.dp),\n            tonalElevation = AlertDialogDefaults.TonalElevation,\n            color = AlertDialogDefaults.containerColor,\n        ) {\n            Column(modifier = Modifier.padding(PaddingValues(all = 24.dp))) {\n                Box(\n                    Modifier\n                        .padding(PaddingValues(bottom = 16.dp))\n                        .align(Alignment.CenterHorizontally)\n                ) {\n                    Text(\n                        text = stringResource(id = R.string.home_dialog_uninstall_title),\n                        style = MaterialTheme.typography.headlineSmall\n                    )\n                }\n                Row(\n                    modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center\n                ) {\n                    TextButton(onClick = {\n                        showDialog.value = false\n                        APApplication.uninstallApatch()\n                    }) {\n                        Text(text = stringResource(id = R.string.home_dialog_uninstall_ap_only))\n                    }\n\n                    TextButton(onClick = {\n                        showDialog.value = false\n                        APApplication.uninstallApatch()\n                        navigator.navigate(PatchesDestination(PatchesViewModel.PatchMode.UNPATCH))\n                    }) {\n                        Text(text = stringResource(id = R.string.home_dialog_uninstall_all))\n                    }\n                }\n            }\n            val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n            APDialogBlurBehindUtils.setupWindowBlurListener(dialogWindowProvider.window)\n        }\n    }\n\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun AuthFailedTipDialog(showDialog: MutableState<Boolean>) {\n    BasicAlertDialog(\n        onDismissRequest = { showDialog.value = false }, properties = DialogProperties(\n            decorFitsSystemWindows = true,\n            usePlatformDefaultWidth = false,\n            securePolicy = SecureFlagPolicy.SecureOff\n        )\n    ) {\n        Surface(\n            modifier = Modifier\n                .width(320.dp)\n                .wrapContentHeight(),\n            shape = RoundedCornerShape(20.dp),\n            tonalElevation = AlertDialogDefaults.TonalElevation,\n            color = AlertDialogDefaults.containerColor,\n        ) {\n            Column(modifier = Modifier.padding(PaddingValues(all = 24.dp))) {\n                // Title\n                Box(\n                    Modifier\n                        .padding(PaddingValues(bottom = 16.dp))\n                        .align(Alignment.Start)\n                ) {\n                    Text(\n                        text = stringResource(id = R.string.home_dialog_auth_fail_title),\n                        style = MaterialTheme.typography.headlineSmall\n                    )\n                }\n\n                // Content\n                Box(\n                    Modifier\n                        .weight(weight = 1f, fill = false)\n                        .padding(PaddingValues(bottom = 24.dp))\n                        .align(Alignment.Start)\n                ) {\n                    Text(\n                        text = stringResource(id = R.string.home_dialog_auth_fail_content),\n                        style = MaterialTheme.typography.bodyMedium\n                    )\n                }\n\n                // Buttons\n                Row(\n                    modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End\n                ) {\n                    TextButton(onClick = { showDialog.value = false }) {\n                        Text(text = stringResource(id = android.R.string.ok))\n                    }\n                }\n            }\n            val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n            APDialogBlurBehindUtils.setupWindowBlurListener(dialogWindowProvider.window)\n        }\n    }\n\n}\n\nval checkSuperKeyValidation: (superKey: String) -> Boolean = { superKey ->\n    superKey.length in 8..63 && superKey.any { it.isDigit() } && superKey.any { it.isLetter() }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun AuthSuperKey(showDialog: MutableState<Boolean>, showFailedDialog: MutableState<Boolean>) {\n    var key by remember { mutableStateOf(\"\") }\n    var keyVisible by remember { mutableStateOf(false) }\n    var enable by remember { mutableStateOf(false) }\n\n    BasicAlertDialog(\n        onDismissRequest = { showDialog.value = false }, properties = DialogProperties(\n            decorFitsSystemWindows = true,\n            usePlatformDefaultWidth = false,\n            securePolicy = SecureFlagPolicy.SecureOff\n        )\n    ) {\n        Surface(\n            modifier = Modifier\n                .width(310.dp)\n                .wrapContentHeight(),\n            shape = RoundedCornerShape(30.dp),\n            tonalElevation = AlertDialogDefaults.TonalElevation,\n            color = AlertDialogDefaults.containerColor,\n        ) {\n            Column(modifier = Modifier.padding(PaddingValues(all = 24.dp))) {\n                // Title\n                Box(\n                    Modifier\n                        .padding(PaddingValues(bottom = 16.dp))\n                        .align(Alignment.Start)\n                ) {\n                    Text(\n                        text = stringResource(id = R.string.home_auth_key_title),\n                        style = MaterialTheme.typography.headlineSmall\n                    )\n                }\n\n                // Content\n                Box(\n                    Modifier\n                        .weight(weight = 1f, fill = false)\n                        .align(Alignment.Start)\n                ) {\n                    Text(\n                        text = stringResource(id = R.string.home_auth_key_desc),\n                        style = MaterialTheme.typography.bodyMedium\n                    )\n                }\n\n                // Content2\n                Box(\n                    contentAlignment = Alignment.CenterEnd,\n                ) {\n                    OutlinedTextField(\n                        value = key,\n                        modifier = Modifier\n                            .fillMaxWidth()\n                            .padding(top = 6.dp),\n                        onValueChange = {\n                            key = it\n                            enable = checkSuperKeyValidation(key)\n                        },\n                        shape = RoundedCornerShape(50.0f),\n                        label = { Text(stringResource(id = R.string.super_key)) },\n                        visualTransformation = if (keyVisible) VisualTransformation.None else PasswordVisualTransformation(),\n                        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)\n                    )\n                    IconButton(\n                        modifier = Modifier\n                            .size(40.dp)\n                            .padding(top = 15.dp, end = 5.dp),\n                        onClick = { keyVisible = !keyVisible }) {\n                        Icon(\n                            imageVector = if (keyVisible) Icons.Default.Visibility else Icons.Default.VisibilityOff,\n                            contentDescription = null,\n                            tint = Color.Gray\n                        )\n                    }\n                }\n\n                Spacer(modifier = Modifier.height(12.dp))\n                // Buttons\n                Row(\n                    modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End\n                ) {\n                    TextButton(onClick = { showDialog.value = false }) {\n                        Text(stringResource(id = android.R.string.cancel))\n                    }\n\n                    Button(onClick = {\n                        showDialog.value = false\n\n                        val preVerifyKey = Natives.nativeReady(key)\n                        if (preVerifyKey) {\n                            APApplication.superKey = key\n                        } else {\n                            showFailedDialog.value = true\n                        }\n\n                    }, enabled = enable) {\n                        Text(stringResource(id = android.R.string.ok))\n                    }\n                }\n            }\n        }\n        val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n        APDialogBlurBehindUtils.setupWindowBlurListener(dialogWindowProvider.window)\n    }\n}\n\n@Composable\nfun RebootDropdownItem(@StringRes id: Int, reason: String = \"\") {\n    DropdownMenuItem(text = {\n        Text(stringResource(id))\n    }, onClick = {\n        reboot(reason)\n    })\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun TopBar(\n    onInstallClick: () -> Unit, navigator: DestinationsNavigator, kpState: APApplication.State\n) {\n    val uriHandler = LocalUriHandler.current\n    var showDropdownMoreOptions by remember { mutableStateOf(false) }\n    var showDropdownReboot by remember { mutableStateOf(false) }\n\n    TopAppBar(title = {\n        Text(stringResource(R.string.app_name))\n    }, actions = {\n        IconButton(onClick = onInstallClick) {\n            Icon(\n                imageVector = Icons.Filled.InstallMobile,\n                contentDescription = stringResource(id = R.string.mode_select_page_title)\n            )\n        }\n\n        if (kpState != APApplication.State.UNKNOWN_STATE) {\n            IconButton(onClick = {\n                showDropdownReboot = true\n            }) {\n                Icon(\n                    imageVector = Icons.Filled.Refresh,\n                    contentDescription = stringResource(id = R.string.reboot)\n                )\n\n                ProvideMenuShape(RoundedCornerShape(10.dp)) {\n                    DropdownMenu(expanded = showDropdownReboot, onDismissRequest = {\n                        showDropdownReboot = false\n                    }) {\n                        RebootDropdownItem(id = R.string.reboot)\n                        RebootDropdownItem(id = R.string.reboot_recovery, reason = \"recovery\")\n                        RebootDropdownItem(id = R.string.reboot_bootloader, reason = \"bootloader\")\n                        RebootDropdownItem(id = R.string.reboot_download, reason = \"download\")\n                        RebootDropdownItem(id = R.string.reboot_edl, reason = \"edl\")\n                    }\n                }\n            }\n        }\n\n        Box {\n            IconButton(onClick = { showDropdownMoreOptions = true }) {\n                Icon(\n                    imageVector = Icons.Filled.MoreVert,\n                    contentDescription = stringResource(id = R.string.settings)\n                )\n                ProvideMenuShape(RoundedCornerShape(10.dp)) {\n                    DropdownMenu(expanded = showDropdownMoreOptions, onDismissRequest = {\n                        showDropdownMoreOptions = false\n                    }) {\n                        DropdownMenuItem(text = {\n                            Text(stringResource(R.string.home_more_menu_feedback_or_suggestion))\n                        }, onClick = {\n                            showDropdownMoreOptions = false\n                            uriHandler.openUri(\"https://github.com/bmax121/APatch/issues/new/choose\")\n                        })\n                        DropdownMenuItem(text = {\n                            Text(stringResource(R.string.home_more_menu_about))\n                        }, onClick = {\n                            navigator.navigate(AboutScreenDestination)\n                            showDropdownMoreOptions = false\n                        })\n                    }\n                }\n            }\n        }\n    })\n}\n\n@Composable\nprivate fun KStatusCard(\n    kpState: APApplication.State, apState: APApplication.State, navigator: DestinationsNavigator\n) {\n\n    val showAuthFailedTipDialog = remember { mutableStateOf(false) }\n    if (showAuthFailedTipDialog.value) {\n        AuthFailedTipDialog(showDialog = showAuthFailedTipDialog)\n    }\n\n    val showAuthKeyDialog = remember { mutableStateOf(false) }\n    if (showAuthKeyDialog.value) {\n        AuthSuperKey(showDialog = showAuthKeyDialog, showFailedDialog = showAuthFailedTipDialog)\n    }\n\n    val showUninstallDialog = remember { mutableStateOf(false) }\n    if (showUninstallDialog.value) {\n        UninstallDialog(showDialog = showUninstallDialog, navigator)\n    }\n\n    val cardBackgroundColor = when (kpState) {\n        APApplication.State.KERNELPATCH_INSTALLED -> {\n            MaterialTheme.colorScheme.primary\n        }\n\n        APApplication.State.KERNELPATCH_NEED_UPDATE, APApplication.State.KERNELPATCH_NEED_REBOOT -> {\n            MaterialTheme.colorScheme.secondary\n        }\n\n        else -> {\n            MaterialTheme.colorScheme.secondaryContainer\n        }\n    }\n\n    ElevatedCard(\n        onClick = {\n            if (kpState != APApplication.State.KERNELPATCH_INSTALLED) {\n                navigator.navigate(InstallModeSelectScreenDestination)\n            }\n        },\n        colors = CardDefaults.elevatedCardColors(containerColor = cardBackgroundColor),\n        elevation = CardDefaults.cardElevation(\n            defaultElevation = if (kpState == APApplication.State.UNKNOWN_STATE) 0.dp else 6.dp\n        )\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(12.dp),\n            horizontalAlignment = Alignment.CenterHorizontally\n        ) {\n            if (kpState == APApplication.State.KERNELPATCH_NEED_UPDATE) {\n                Row {\n                    Text(\n                        text = stringResource(R.string.kernel_patch),\n                        style = MaterialTheme.typography.titleMedium\n                    )\n                }\n            }\n            Row(\n                modifier = Modifier\n                    .fillMaxWidth()\n                    .padding(10.dp),\n                verticalAlignment = Alignment.CenterVertically\n            ) {\n                when (kpState) {\n                    APApplication.State.KERNELPATCH_INSTALLED -> {\n                        Icon(Icons.Filled.CheckCircle, stringResource(R.string.home_working))\n                    }\n\n                    APApplication.State.KERNELPATCH_NEED_UPDATE, APApplication.State.KERNELPATCH_NEED_REBOOT -> {\n                        Icon(Icons.Outlined.SystemUpdate, stringResource(R.string.home_need_update))\n                    }\n\n                    else -> {\n                        Icon(Icons.AutoMirrored.Outlined.HelpOutline, \"Unknown\")\n                    }\n                }\n                Column(\n                    Modifier\n                        .weight(2f)\n                        .padding(start = 16.dp)\n                ) {\n                    when (kpState) {\n                        APApplication.State.KERNELPATCH_INSTALLED -> {\n                            Text(\n                                text = stringResource(R.string.home_working),\n                                style = MaterialTheme.typography.titleMedium\n                            )\n                        }\n\n                        APApplication.State.KERNELPATCH_NEED_UPDATE, APApplication.State.KERNELPATCH_NEED_REBOOT -> {\n                            Text(\n                                text = stringResource(R.string.home_need_update),\n                                style = MaterialTheme.typography.titleMedium\n                            )\n                            Spacer(Modifier.height(6.dp))\n                            Text(\n                                text = stringResource(\n                                    R.string.kpatch_version_update,\n                                    Version.installedKPVString(),\n                                    Version.buildKPVString()\n                                ), style = MaterialTheme.typography.bodyMedium\n                            )\n                        }\n\n                        else -> {\n                            Text(\n                                text = stringResource(R.string.home_install_unknown),\n                                style = MaterialTheme.typography.titleMedium\n                            )\n                            Text(\n                                text = stringResource(R.string.home_install_unknown_summary),\n                                style = MaterialTheme.typography.bodyMedium\n                            )\n                        }\n                    }\n                    if (kpState != APApplication.State.UNKNOWN_STATE && kpState != APApplication.State.KERNELPATCH_NEED_UPDATE && kpState != APApplication.State.KERNELPATCH_NEED_REBOOT) {\n                        Spacer(Modifier.height(4.dp))\n                        Text(\n                            text = \"${Version.installedKPVString()} (${managerVersion.second}) - \" + if (apState != APApplication.State.ANDROIDPATCH_NOT_INSTALLED) \"Full\" else \"KernelPatch\",\n                            style = MaterialTheme.typography.bodyMedium\n                        )\n                    }\n                }\n\n                Column(\n                    modifier = Modifier.align(Alignment.CenterVertically)\n                ) {\n                    Button(onClick = {\n                        when (kpState) {\n                            APApplication.State.UNKNOWN_STATE -> {\n                                showAuthKeyDialog.value = true\n                            }\n\n                            APApplication.State.KERNELPATCH_NEED_UPDATE -> {\n                                // todo: remove legacy compact for kp < 0.9.0\n                                if (Version.installedKPVUInt() < 0x900u) {\n                                    navigator.navigate(PatchesDestination(PatchesViewModel.PatchMode.PATCH_ONLY))\n                                } else {\n                                    navigator.navigate(InstallModeSelectScreenDestination)\n                                }\n                            }\n\n                            APApplication.State.KERNELPATCH_NEED_REBOOT -> {\n                                reboot()\n                            }\n\n                            APApplication.State.KERNELPATCH_UNINSTALLING -> {\n                                // Do nothing\n                            }\n\n                            else -> {\n                                if (apState == APApplication.State.ANDROIDPATCH_INSTALLED || apState == APApplication.State.ANDROIDPATCH_NEED_UPDATE) {\n                                    showUninstallDialog.value = true\n                                } else {\n                                    navigator.navigate(PatchesDestination(PatchesViewModel.PatchMode.UNPATCH))\n                                }\n                            }\n                        }\n                    }, content = {\n                        when (kpState) {\n                            APApplication.State.UNKNOWN_STATE -> {\n                                Text(text = stringResource(id = R.string.super_key))\n                            }\n\n                            APApplication.State.KERNELPATCH_NEED_UPDATE -> {\n                                Text(text = stringResource(id = R.string.home_ap_cando_update))\n                            }\n\n                            APApplication.State.KERNELPATCH_NEED_REBOOT -> {\n                                Text(text = stringResource(id = R.string.home_ap_cando_reboot))\n                            }\n\n                            APApplication.State.KERNELPATCH_UNINSTALLING -> {\n                                Icon(Icons.Outlined.Cached, contentDescription = \"busy\")\n                            }\n\n                            else -> {\n                                Text(text = stringResource(id = R.string.home_ap_cando_uninstall))\n                            }\n                        }\n                    })\n                }\n            }\n        }\n    }\n}\n\n@Composable\nprivate fun AStatusCard(apState: APApplication.State) {\n    ElevatedCard(\n        colors = CardDefaults.elevatedCardColors(containerColor = run {\n            MaterialTheme.colorScheme.secondaryContainer\n        })\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(12.dp),\n            horizontalAlignment = Alignment.CenterHorizontally\n        ) {\n            Row {\n                Text(\n                    text = stringResource(R.string.android_patch),\n                    style = MaterialTheme.typography.titleMedium\n                )\n            }\n            Row(\n                modifier = Modifier\n                    .fillMaxWidth()\n                    .padding(10.dp),\n                verticalAlignment = Alignment.CenterVertically\n            ) {\n                when (apState) {\n                    APApplication.State.ANDROIDPATCH_NOT_INSTALLED -> {\n                        Icon(Icons.Outlined.Block, stringResource(R.string.home_not_installed))\n                    }\n\n                    APApplication.State.ANDROIDPATCH_INSTALLING -> {\n                        Icon(Icons.Outlined.InstallMobile, stringResource(R.string.home_installing))\n                    }\n\n                    APApplication.State.ANDROIDPATCH_INSTALLED -> {\n                        Icon(Icons.Outlined.CheckCircle, stringResource(R.string.home_working))\n                    }\n\n                    APApplication.State.ANDROIDPATCH_NEED_UPDATE -> {\n                        Icon(Icons.Outlined.SystemUpdate, stringResource(R.string.home_need_update))\n                    }\n\n                    else -> {\n                        Icon(\n                            Icons.AutoMirrored.Outlined.HelpOutline,\n                            stringResource(R.string.home_install_unknown)\n                        )\n                    }\n                }\n                Column(\n                    Modifier\n                        .weight(2f)\n                        .padding(start = 16.dp)\n                ) {\n\n                    when (apState) {\n                        APApplication.State.ANDROIDPATCH_NOT_INSTALLED -> {\n                            Text(\n                                text = stringResource(R.string.home_not_installed),\n                                style = MaterialTheme.typography.titleMedium\n                            )\n                        }\n\n                        APApplication.State.ANDROIDPATCH_INSTALLING -> {\n                            Text(\n                                text = stringResource(R.string.home_installing),\n                                style = MaterialTheme.typography.titleMedium\n                            )\n                        }\n\n                        APApplication.State.ANDROIDPATCH_INSTALLED -> {\n                            Text(\n                                text = stringResource(R.string.home_working),\n                                style = MaterialTheme.typography.titleMedium\n                            )\n                        }\n\n                        APApplication.State.ANDROIDPATCH_NEED_UPDATE -> {\n                            Text(\n                                text = stringResource(R.string.home_need_update),\n                                style = MaterialTheme.typography.titleMedium\n                            )\n                            Spacer(Modifier.height(6.dp))\n                            Text(\n                                text = stringResource(\n                                    R.string.apatch_version_update,\n                                    Version.installedApdVString,\n                                    managerVersion.second\n                                ), style = MaterialTheme.typography.bodyMedium\n                            )\n                        }\n\n                        else -> {\n                            Text(\n                                text = stringResource(R.string.home_install_unknown),\n                                style = MaterialTheme.typography.titleMedium\n                            )\n                        }\n                    }\n                }\n                if (apState != APApplication.State.UNKNOWN_STATE) {\n                    Column(\n                        modifier = Modifier.align(Alignment.CenterVertically)\n                    ) {\n                        Button(onClick = {\n                            when (apState) {\n                                APApplication.State.ANDROIDPATCH_NOT_INSTALLED, APApplication.State.ANDROIDPATCH_NEED_UPDATE -> {\n                                    APApplication.installApatch()\n                                }\n\n                                APApplication.State.ANDROIDPATCH_UNINSTALLING -> {\n                                    // Do nothing\n                                }\n\n                                else -> {\n                                    APApplication.uninstallApatch()\n                                }\n                            }\n                        }, content = {\n                            when (apState) {\n                                APApplication.State.ANDROIDPATCH_NOT_INSTALLED -> {\n                                    Text(text = stringResource(id = R.string.home_ap_cando_install))\n                                }\n\n                                APApplication.State.ANDROIDPATCH_NEED_UPDATE -> {\n                                    Text(text = stringResource(id = R.string.home_ap_cando_update))\n                                }\n\n                                APApplication.State.ANDROIDPATCH_UNINSTALLING -> {\n                                    Icon(Icons.Outlined.Cached, contentDescription = \"busy\")\n                                }\n\n                                else -> {\n                                    Text(text = stringResource(id = R.string.home_ap_cando_uninstall))\n                                }\n                            }\n                        })\n                    }\n                }\n            }\n        }\n    }\n}\n\n\n@Composable\nfun WarningCard() {\n    var show by rememberSaveable { mutableStateOf(apApp.getBackupWarningState()) }\n    if (show) {\n        ElevatedCard(\n            elevation = CardDefaults.cardElevation(\n                defaultElevation = 6.dp\n            ), colors = CardDefaults.elevatedCardColors(containerColor = run {\n                MaterialTheme.colorScheme.error\n            })\n        ) {\n            Row(\n                modifier = Modifier\n                    .fillMaxWidth()\n                    .padding(12.dp)\n            ) {\n                Column(\n                    modifier = Modifier.padding(12.dp),\n                    verticalArrangement = Arrangement.Center,\n                    horizontalAlignment = Alignment.CenterHorizontally\n                ) {\n                    Icon(Icons.Filled.Warning, contentDescription = \"warning\")\n                }\n                Column(\n                    modifier = Modifier.padding(12.dp),\n                    horizontalAlignment = Alignment.CenterHorizontally\n                ) {\n                    Row(\n                        modifier = Modifier\n                            .fillMaxWidth()\n                            .align(Alignment.CenterHorizontally),\n                        horizontalArrangement = Arrangement.SpaceBetween\n                    ) {\n                        Text(\n                            modifier = Modifier.weight(1f),\n                            text = stringResource(id = R.string.patch_warnning),\n                        )\n\n                        Spacer(Modifier.width(12.dp))\n\n                        Icon(\n                            Icons.Outlined.Clear,\n                            contentDescription = \"\",\n                            modifier = Modifier.clickable {\n                                show = false\n                                apApp.updateBackupWarningState(false)\n                            },\n                        )\n                    }\n                }\n            }\n        }\n    }\n}\n\nprivate fun getSystemVersion(): String {\n    return \"${Build.VERSION.RELEASE} ${if (Build.VERSION.PREVIEW_SDK_INT != 0) \"Preview\" else \"\"} (API ${Build.VERSION.SDK_INT})\"\n}\n\nprivate fun getDeviceInfo(): String {\n    var manufacturer =\n        Build.MANUFACTURER[0].uppercaseChar().toString() + Build.MANUFACTURER.substring(1)\n    if (!Build.BRAND.equals(Build.MANUFACTURER, ignoreCase = true)) {\n        manufacturer += \" \" + Build.BRAND[0].uppercaseChar() + Build.BRAND.substring(1)\n    }\n    manufacturer += \" \" + Build.MODEL + \" \"\n    return manufacturer\n}\n\n@Composable\nprivate fun InfoCard(kpState: APApplication.State, apState: APApplication.State) {\n    ElevatedCard {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(start = 24.dp, top = 24.dp, end = 24.dp, bottom = 16.dp)\n        ) {\n            val contents = StringBuilder()\n            val uname = Os.uname()\n\n            @Composable\n            fun InfoCardItem(label: String, content: String) {\n                contents.appendLine(label).appendLine(content).appendLine()\n                Text(text = label, style = MaterialTheme.typography.bodyLarge)\n                Text(text = content, style = MaterialTheme.typography.bodyMedium)\n            }\n\n            if (kpState != APApplication.State.UNKNOWN_STATE) {\n                InfoCardItem(\n                    stringResource(R.string.home_kpatch_version), Version.installedKPVString()\n                )\n\n                Spacer(Modifier.height(16.dp))\n                InfoCardItem(stringResource(R.string.home_su_path), Natives.suPath())\n\n                Spacer(Modifier.height(16.dp))\n            }\n\n            if (apState != APApplication.State.UNKNOWN_STATE && apState != APApplication.State.ANDROIDPATCH_NOT_INSTALLED) {\n                InfoCardItem(\n                    stringResource(R.string.home_apatch_version), managerVersion.second.toString()\n                )\n                Spacer(Modifier.height(16.dp))\n            }\n\n            InfoCardItem(stringResource(R.string.home_device_info), getDeviceInfo())\n\n            Spacer(Modifier.height(16.dp))\n            InfoCardItem(stringResource(R.string.home_kernel), uname.release)\n\n            Spacer(Modifier.height(16.dp))\n            InfoCardItem(stringResource(R.string.home_system_version), getSystemVersion())\n\n            Spacer(Modifier.height(16.dp))\n            InfoCardItem(stringResource(R.string.home_fingerprint), Build.FINGERPRINT)\n\n            Spacer(Modifier.height(16.dp))\n            InfoCardItem(stringResource(R.string.home_selinux_status), getSELinuxStatus())\n\n        }\n    }\n}\n\n@Composable\nfun UpdateCard() {\n    val latestVersionInfo = LatestVersionInfo()\n    val newVersion by produceState(initialValue = latestVersionInfo) {\n        value = withContext(Dispatchers.IO) {\n            checkNewVersion()\n        }\n    }\n    val currentVersionCode = managerVersion.second\n    val newVersionCode = newVersion.versionCode\n    val newVersionUrl = newVersion.downloadUrl\n    val changelog = newVersion.changelog\n\n    val uriHandler = LocalUriHandler.current\n    val title = stringResource(id = R.string.apm_changelog)\n    val updateText = stringResource(id = R.string.apm_update)\n\n    AnimatedVisibility(\n        visible = newVersionCode > currentVersionCode,\n        enter = fadeIn() + expandVertically(),\n        exit = shrinkVertically() + fadeOut()\n    ) {\n        val updateDialog = rememberConfirmDialog(onConfirm = { uriHandler.openUri(newVersionUrl) })\n        WarningCard(\n            message = stringResource(id = R.string.home_new_apatch_found).format(newVersionCode),\n            MaterialTheme.colorScheme.outlineVariant\n        ) {\n            if (changelog.isEmpty()) {\n                uriHandler.openUri(newVersionUrl)\n            } else {\n                updateDialog.showConfirm(\n                    title = title, content = changelog, markdown = true, confirm = updateText\n                )\n            }\n        }\n    }\n}\n\n@Composable\nfun LearnMoreCard() {\n    val uriHandler = LocalUriHandler.current\n\n    ElevatedCard {\n        Row(\n            modifier = Modifier\n                .fillMaxWidth()\n                .clickable {\n                    uriHandler.openUri(\"https://apatch.dev\")\n                }\n                .padding(24.dp), verticalAlignment = Alignment.CenterVertically) {\n            Column {\n                Text(\n                    text = stringResource(R.string.home_learn_apatch),\n                    style = MaterialTheme.typography.titleSmall\n                )\n                Spacer(Modifier.height(4.dp))\n                Text(\n                    text = stringResource(R.string.home_click_to_learn_apatch),\n                    style = MaterialTheme.typography.bodyMedium\n                )\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/Install.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport android.content.Context\nimport android.net.Uri\nimport android.os.Environment\nimport android.util.Log\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.rememberScrollState\nimport androidx.compose.foundation.verticalScroll\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.automirrored.filled.ArrowBack\nimport androidx.compose.material.icons.filled.Refresh\nimport androidx.compose.material.icons.filled.Save\nimport androidx.compose.material.icons.outlined.Info\nimport androidx.compose.material3.AlertDialog\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.ExtendedFloatingActionButton\nimport androidx.compose.material3.FilledTonalButton\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.OutlinedButton\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.SnackbarHost\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TopAppBar\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.saveable.rememberSaveable\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.input.key.Key\nimport androidx.compose.ui.input.key.key\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.platform.LocalUriHandler\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.font.FontFamily\nimport androidx.compose.ui.tooling.preview.Preview\nimport androidx.compose.ui.unit.dp\nimport androidx.lifecycle.compose.dropUnlessResumed\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport com.ramcosta.composedestinations.navigation.DestinationsNavigator\nimport com.topjohnwu.superuser.io.SuFile\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport me.bmax.apatch.R\nimport me.bmax.apatch.ui.component.KeyEventBlocker\nimport me.bmax.apatch.ui.component.rememberCustomDialog\nimport me.bmax.apatch.util.hasMetaModule\nimport me.bmax.apatch.util.installModule\nimport me.bmax.apatch.util.reboot\nimport me.bmax.apatch.util.ui.LocalSnackbarHost\nimport java.io.File\nimport java.text.SimpleDateFormat\nimport java.util.Date\nimport java.util.Locale\nimport java.util.Properties\nimport java.util.zip.ZipEntry\nimport java.util.zip.ZipInputStream\n\nenum class MODULE_TYPE {\n    KPM, APM\n}\n\n@Composable\n@Destination<RootGraph>\nfun InstallScreen(navigator: DestinationsNavigator, uri: Uri, type: MODULE_TYPE) {\n    var text by remember { mutableStateOf(\"\") }\n    var tempText: String\n    val logContent = remember { StringBuilder() }\n    var showFloatAction by rememberSaveable { mutableStateOf(false) }\n    val metaModuleAlertDialog = rememberCustomDialog { dismiss: () -> Unit ->\n        val uriHandler = LocalUriHandler.current\n        AlertDialog(\n            onDismissRequest = { dismiss() },\n            icon = {\n                Icon(Icons.Outlined.Info, contentDescription = null)\n            },\n            title = {\n                Row(modifier = Modifier\n                    .fillMaxWidth(),\n                    horizontalArrangement = Arrangement.Center\n                ) {\n                    Text(text = stringResource(R.string.warning_of_meta_module_title))\n                }\n            },\n            text = {\n                Text(text = stringResource(R.string.warning_of_meta_module_summary))\n            },\n            confirmButton = {\n                FilledTonalButton(onClick = { dismiss() }) {\n                    Text(text = stringResource(id = android.R.string.ok))\n                }\n            },\n            dismissButton = {\n                OutlinedButton(onClick = {\n                    uriHandler.openUri(\"https://apatch.dev/meta-module.html\")\n                }) {\n                    Text(text = stringResource(id = R.string.learn_more))\n                }\n            },\n        )\n    }\n\n    val context = LocalContext.current\n    val snackBarHost = LocalSnackbarHost.current\n    val scope = rememberCoroutineScope()\n    val scrollState = rememberScrollState()\n\n    LaunchedEffect(Unit) {\n        if (text.isNotEmpty()) {\n            return@LaunchedEffect\n        }\n        withContext(Dispatchers.IO) {\n            installModule(uri, type, onFinish = { success ->\n                if (!success) return@installModule\n\n                scope.launch {\n                    showFloatAction = true\n\n                    // check metamodule\n                    if (hasMetaModule()) return@launch\n                    val mountOldDirectory =\n                        SuFile.open(\"/data/adb/modules/${getModuleIdFromUri(context, uri)}/system\")\n                    val mountNewDirectory =\n                        SuFile.open(\"/data/adb/modules_update/${getModuleIdFromUri(context, uri)}/system\")\n                    if (!mountNewDirectory.isDirectory && !mountOldDirectory.isDirectory) return@launch\n\n                    metaModuleAlertDialog.show()\n                }\n\n            }, onStdout = {\n                tempText = \"$it\\n\"\n                if (tempText.startsWith(\"\u001b[H\u001b[J\")) { // clear command\n                    text = tempText.substring(6)\n                } else {\n                    text += tempText\n                }\n                logContent.append(it).append(\"\\n\")\n            }, onStderr = {\n                tempText = \"$it\\n\"\n                if (tempText.startsWith(\"\u001b[H\u001b[J\")) { // clear command\n                    text = tempText.substring(6)\n                } else {\n                    text += tempText\n                }\n                logContent.append(it).append(\"\\n\")\n            })\n        }\n    }\n\n    Scaffold(topBar = {\n        TopBar(onBack = dropUnlessResumed {\n            navigator.popBackStack()\n        }, onSave = {\n            scope.launch {\n                val format = SimpleDateFormat(\"yyyy-MM-dd-HH-mm-ss\", Locale.getDefault())\n                val date = format.format(Date())\n                val file = File(\n                    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),\n                    \"APatch_install_${type}_log_${date}.log\"\n                )\n                file.writeText(logContent.toString())\n                snackBarHost.showSnackbar(\"Log saved to ${file.absolutePath}\")\n            }\n        })\n    }, floatingActionButton = {\n        if (showFloatAction) {\n            val reboot = stringResource(id = R.string.reboot)\n            ExtendedFloatingActionButton(\n                onClick = {\n                    scope.launch {\n                        withContext(Dispatchers.IO) {\n                            reboot()\n                        }\n                    }\n                },\n                icon = { Icon(Icons.Filled.Refresh, reboot) },\n                text = { Text(text = reboot) },\n            )\n        }\n\n    }, snackbarHost = { SnackbarHost(snackBarHost) }) { innerPadding ->\n        KeyEventBlocker {\n            it.key == Key.VolumeDown || it.key == Key.VolumeUp\n        }\n        Column(\n            modifier = Modifier\n                .fillMaxSize(1f)\n                .padding(innerPadding)\n                .verticalScroll(scrollState),\n        ) {\n            LaunchedEffect(text) {\n                scrollState.animateScrollTo(scrollState.maxValue)\n            }\n            Text(\n                modifier = Modifier.padding(8.dp),\n                text = text,\n                fontSize = MaterialTheme.typography.bodySmall.fontSize,\n                fontFamily = FontFamily.Monospace,\n                lineHeight = MaterialTheme.typography.bodySmall.lineHeight,\n            )\n        }\n    }\n}\n\nfun isUriAccessible(context: Context, uri: Uri): Boolean {\n    if (uri == Uri.EMPTY) return false\n\n    return try {\n        context.contentResolver.openInputStream(uri)?.use {} != null\n    } catch (e: Exception) {\n        Log.e(\"ModuleInstall\", \"URI is inaccessible: $uri\", e)\n        false\n    }\n}\n\n\nfun extractModuleId(context: Context, uri: Uri): String? {\n    if (uri == Uri.EMPTY) return null\n\n    context.contentResolver.openInputStream(uri)?.use { inputStream ->\n        ZipInputStream(inputStream).use { zip ->\n            var entry: ZipEntry?\n\n            while (zip.nextEntry.also { entry = it } != null) {\n                if (entry?.name == \"module.prop\") {\n                    val prop = Properties()\n                    prop.load(zip)\n                    return prop.getProperty(\"id\")\n                }\n            }\n        }\n    }\n\n    return null\n}\n\nsuspend fun getModuleIdFromUri(context: Context, uri: Uri): String? {\n    return withContext(Dispatchers.IO) {\n        try {\n            if (uri == Uri.EMPTY) {\n                return@withContext null\n            }\n            if (!isUriAccessible(context, uri)) {\n                return@withContext null\n            }\n            extractModuleId(context, uri)\n        } catch (_: Exception) {\n            null\n        }\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun TopBar(onBack: () -> Unit = {}, onSave: () -> Unit = {}) {\n    TopAppBar(title = { Text(stringResource(R.string.apm_install)) }, navigationIcon = {\n        IconButton(\n            onClick = onBack\n        ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }\n    }, actions = {\n        IconButton(onClick = onSave) {\n            Icon(\n                imageVector = Icons.Filled.Save, contentDescription = \"Localized description\"\n            )\n        }\n    })\n}\n\n@Preview\n@Composable\nfun InstallPreview() {\n//    InstallScreen(DestinationsNavigator(), uri = Uri.EMPTY)\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/InstallModeSelect.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.net.Uri\nimport androidx.activity.compose.rememberLauncherForActivityResult\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.annotation.StringRes\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.automirrored.filled.ArrowBack\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.RadioButton\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TopAppBar\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.res.stringResource\nimport androidx.lifecycle.compose.dropUnlessResumed\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport com.ramcosta.composedestinations.generated.destinations.PatchesDestination\nimport com.ramcosta.composedestinations.navigation.DestinationsNavigator\nimport me.bmax.apatch.R\nimport me.bmax.apatch.ui.component.rememberConfirmDialog\nimport me.bmax.apatch.ui.viewmodel.PatchesViewModel\nimport me.bmax.apatch.util.isABDevice\nimport me.bmax.apatch.util.rootAvailable\n\nvar selectedBootImage: Uri? = null\n\n@Destination<RootGraph>\n@Composable\nfun InstallModeSelectScreen(navigator: DestinationsNavigator) {\n    var installMethod by remember {\n        mutableStateOf<InstallMethod?>(null)\n    }\n\n    Scaffold(topBar = {\n        TopBar(\n            onBack = dropUnlessResumed { navigator.popBackStack() },\n        )\n    }) {\n        Column(modifier = Modifier.padding(it)) {\n            SelectInstallMethod(\n                onSelected = { method ->\n                    installMethod = method\n                },\n                navigator = navigator\n            )\n\n        }\n    }\n}\n\nsealed class InstallMethod {\n    data class SelectFile(\n        val uri: Uri? = null,\n        @param:StringRes override val label: Int = R.string.mode_select_page_select_file,\n    ) : InstallMethod()\n\n    data object DirectInstall : InstallMethod() {\n        override val label: Int\n            get() = R.string.mode_select_page_patch_and_install\n    }\n\n    data object DirectInstallToInactiveSlot : InstallMethod() {\n        override val label: Int\n            get() = R.string.mode_select_page_install_inactive_slot\n    }\n\n    abstract val label: Int\n    open val summary: String? = null\n}\n\n@Composable\nprivate fun SelectInstallMethod(\n    onSelected: (InstallMethod) -> Unit = {},\n    navigator: DestinationsNavigator\n) {\n    val rootAvailable = rootAvailable()\n    val isAbDevice = isABDevice()\n\n    val radioOptions =\n        mutableListOf<InstallMethod>(InstallMethod.SelectFile())\n    if (rootAvailable) {\n        radioOptions.add(InstallMethod.DirectInstall)\n        if (isAbDevice) {\n            radioOptions.add(InstallMethod.DirectInstallToInactiveSlot)\n        }\n    }\n\n    var selectedOption by remember { mutableStateOf<InstallMethod?>(null) }\n    val selectImageLauncher = rememberLauncherForActivityResult(\n        contract = ActivityResultContracts.StartActivityForResult()\n    ) {\n        if (it.resultCode == Activity.RESULT_OK) {\n            it.data?.data?.let { uri ->\n                val option = InstallMethod.SelectFile(uri)\n                selectedOption = option\n                onSelected(option)\n                selectedBootImage = option.uri\n                navigator.navigate(PatchesDestination(PatchesViewModel.PatchMode.PATCH_ONLY))\n            }\n        }\n    }\n\n    val confirmDialog = rememberConfirmDialog(onConfirm = {\n        selectedOption = InstallMethod.DirectInstallToInactiveSlot\n        onSelected(InstallMethod.DirectInstallToInactiveSlot)\n        navigator.navigate(PatchesDestination(PatchesViewModel.PatchMode.INSTALL_TO_NEXT_SLOT))\n    }, onDismiss = null)\n    val dialogTitle = stringResource(id = android.R.string.dialog_alert_title)\n    val dialogContent = stringResource(id = R.string.mode_select_page_install_inactive_slot_warning)\n\n    val onClick = { option: InstallMethod ->\n        when (option) {\n            is InstallMethod.SelectFile -> {\n                // Reset before selecting\n                selectedBootImage = null\n                selectImageLauncher.launch(\n                    Intent(Intent.ACTION_GET_CONTENT).apply {\n                        type = \"application/octet-stream\"\n                    }\n                )\n            }\n\n            is InstallMethod.DirectInstall -> {\n                selectedOption = option\n                onSelected(option)\n                navigator.navigate(PatchesDestination(PatchesViewModel.PatchMode.PATCH_AND_INSTALL))\n            }\n\n            is InstallMethod.DirectInstallToInactiveSlot -> {\n                confirmDialog.showConfirm(dialogTitle, dialogContent)\n            }\n        }\n    }\n\n    Column {\n        radioOptions.forEach { option ->\n            Row(\n                verticalAlignment = Alignment.CenterVertically,\n                modifier = Modifier\n                    .fillMaxWidth()\n                    .clickable {\n                        onClick(option)\n                    }) {\n                RadioButton(selected = option.javaClass == selectedOption?.javaClass, onClick = {\n                    onClick(option)\n                })\n                Column {\n                    Text(\n                        text = stringResource(id = option.label),\n                        fontSize = MaterialTheme.typography.titleMedium.fontSize,\n                        fontFamily = MaterialTheme.typography.titleMedium.fontFamily,\n                        fontStyle = MaterialTheme.typography.titleMedium.fontStyle\n                    )\n                    option.summary?.let {\n                        Text(\n                            text = it,\n                            fontSize = MaterialTheme.typography.bodySmall.fontSize,\n                            fontFamily = MaterialTheme.typography.bodySmall.fontFamily,\n                            fontStyle = MaterialTheme.typography.bodySmall.fontStyle\n                        )\n                    }\n                }\n            }\n        }\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun TopBar(onBack: () -> Unit = {}) {\n    TopAppBar(\n        title = { Text(stringResource(R.string.mode_select_page_title)) },\n        navigationIcon = {\n            IconButton(\n                onClick = onBack\n            ) { Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) }\n        },\n    )\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/KPM.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport android.app.Activity.RESULT_OK\nimport android.content.Intent\nimport android.net.Uri\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.activity.compose.rememberLauncherForActivityResult\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.layout.wrapContentHeight\nimport androidx.compose.foundation.lazy.LazyColumn\nimport androidx.compose.foundation.lazy.LazyListState\nimport androidx.compose.foundation.lazy.items\nimport androidx.compose.foundation.lazy.rememberLazyListState\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.material3.AlertDialogDefaults\nimport androidx.compose.material3.BasicAlertDialog\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.DropdownMenu\nimport androidx.compose.material3.DropdownMenuItem\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.FilledTonalButton\nimport androidx.compose.material3.FloatingActionButton\nimport androidx.compose.material3.HorizontalDivider\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.OutlinedTextField\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.SearchBarScrollBehavior\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TextButton\nimport androidx.compose.material3.pulltorefresh.PullToRefreshBox\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.MutableState\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.livedata.observeAsState\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.draw.alpha\nimport androidx.compose.ui.input.nestedscroll.nestedScroll\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.platform.LocalView\nimport androidx.compose.ui.res.painterResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.font.FontWeight\nimport androidx.compose.ui.text.input.VisualTransformation\nimport androidx.compose.ui.text.style.TextAlign\nimport androidx.compose.ui.text.style.TextDecoration\nimport androidx.compose.ui.text.style.TextOverflow\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.window.DialogProperties\nimport androidx.compose.ui.window.DialogWindowProvider\nimport androidx.compose.ui.window.PopupProperties\nimport androidx.lifecycle.viewmodel.compose.viewModel\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport com.ramcosta.composedestinations.generated.destinations.InstallScreenDestination\nimport com.ramcosta.composedestinations.generated.destinations.PatchesDestination\nimport com.ramcosta.composedestinations.navigation.DestinationsNavigator\nimport com.topjohnwu.superuser.nio.ExtendedFile\nimport com.topjohnwu.superuser.nio.FileSystemManager\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.Natives\nimport me.bmax.apatch.R\nimport me.bmax.apatch.apApp\nimport me.bmax.apatch.ui.component.ConfirmResult\nimport me.bmax.apatch.ui.component.KPModuleRemoveButton\nimport me.bmax.apatch.ui.component.LoadingDialogHandle\nimport me.bmax.apatch.ui.component.ProvideMenuShape\nimport me.bmax.apatch.ui.component.SearchAppBar\nimport me.bmax.apatch.ui.component.pinnedScrollBehavior\nimport me.bmax.apatch.ui.component.rememberConfirmDialog\nimport me.bmax.apatch.ui.component.rememberLoadingDialog\nimport me.bmax.apatch.ui.viewmodel.KPModel\nimport me.bmax.apatch.ui.viewmodel.KPModuleViewModel\nimport me.bmax.apatch.ui.viewmodel.PatchesViewModel\nimport me.bmax.apatch.util.inputStream\nimport me.bmax.apatch.util.ui.APDialogBlurBehindUtils\nimport me.bmax.apatch.util.writeTo\nimport java.io.IOException\n\nprivate const val TAG = \"KernelPatchModule\"\nprivate lateinit var targetKPMToControl: KPModel.KPMInfo\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Destination<RootGraph>\n@Composable\nfun KPModuleScreen(navigator: DestinationsNavigator) {\n    val state by APApplication.apStateLiveData.observeAsState(APApplication.State.UNKNOWN_STATE)\n    if (state == APApplication.State.UNKNOWN_STATE) {\n        Column(\n            modifier = Modifier\n                .fillMaxSize()\n                .padding(12.dp),\n            verticalArrangement = Arrangement.Center,\n            horizontalAlignment = Alignment.CenterHorizontally\n        ) {\n            Row {\n                Text(\n                    text = stringResource(id = R.string.kpm_kp_not_installed),\n                    style = MaterialTheme.typography.titleMedium\n                )\n            }\n        }\n        return\n    }\n\n    val viewModel = viewModel<KPModuleViewModel>()\n    val scrollBehavior = pinnedScrollBehavior()\n    val kpModuleListState = rememberLazyListState()\n\n    LaunchedEffect(Unit) {\n        if (viewModel.moduleList.isEmpty() || viewModel.isNeedRefresh) {\n            viewModel.fetchModuleList()\n        }\n    }\n\n    Scaffold(topBar = {\n        SearchAppBar(\n            searchText = viewModel.search,\n            onSearchTextChange = { viewModel.search = it },\n            searchBarPlaceHolderText = stringResource(R.string.search_modules)\n        )\n    }, floatingActionButton = run {\n        {\n            val scope = rememberCoroutineScope()\n            val context = LocalContext.current\n\n            val moduleLoad = stringResource(id = R.string.kpm_load)\n            val moduleInstall = stringResource(id = R.string.kpm_install)\n            val moduleEmbed = stringResource(id = R.string.kpm_embed)\n            val successToastText = stringResource(id = R.string.kpm_load_toast_succ)\n            val failToastText = stringResource(id = R.string.kpm_load_toast_failed)\n            val loadingDialog = rememberLoadingDialog()\n\n            val selectZipLauncher = rememberLauncherForActivityResult(\n                contract = ActivityResultContracts.StartActivityForResult()\n            ) {\n                if (it.resultCode != RESULT_OK) {\n                    return@rememberLauncherForActivityResult\n                }\n                val data = it.data ?: return@rememberLauncherForActivityResult\n                val uri = data.data ?: return@rememberLauncherForActivityResult\n\n                Log.i(TAG, \"select zip result: $uri\")\n\n                navigator.navigate(InstallScreenDestination(uri, MODULE_TYPE.KPM))\n            }\n\n            val selectKpmLauncher = rememberLauncherForActivityResult(\n                contract = ActivityResultContracts.StartActivityForResult()\n            ) {\n                if (it.resultCode != RESULT_OK) {\n                    return@rememberLauncherForActivityResult\n                }\n                val data = it.data ?: return@rememberLauncherForActivityResult\n                val uri = data.data ?: return@rememberLauncherForActivityResult\n\n                // todo: args\n                scope.launch {\n                    val rc = loadModule(loadingDialog, uri, \"\")\n                    val toastText = if (rc == 0) successToastText else \"$failToastText: $rc\"\n                    withContext(Dispatchers.Main) {\n                        Toast.makeText(\n                            context, toastText, Toast.LENGTH_SHORT\n                        ).show()\n                    }\n                    viewModel.markNeedRefresh()\n                    viewModel.fetchModuleList()\n                }\n            }\n\n            var expanded by remember { mutableStateOf(false) }\n            val options = listOf(moduleEmbed, moduleInstall, moduleLoad)\n\n            Column {\n                FloatingActionButton(\n                    onClick = {\n                        expanded = !expanded\n                    },\n                    contentColor = MaterialTheme.colorScheme.onPrimary,\n                    containerColor = MaterialTheme.colorScheme.primary,\n                ) {\n                    Icon(\n                        painter = painterResource(id = R.drawable.package_import),\n                        contentDescription = null\n                    )\n                }\n\n                ProvideMenuShape(RoundedCornerShape(10.dp)) {\n                    DropdownMenu(\n                        expanded = expanded,\n                        onDismissRequest = { expanded = false },\n                        properties = PopupProperties(focusable = true)\n                    ) {\n                        options.forEach { label ->\n                            DropdownMenuItem(text = { Text(label) }, onClick = {\n                                expanded = false\n                                when (label) {\n                                    moduleEmbed -> {\n                                        navigator.navigate(PatchesDestination(PatchesViewModel.PatchMode.PATCH_AND_INSTALL))\n                                    }\n\n                                    moduleInstall -> {\n//                                        val intent = Intent(Intent.ACTION_GET_CONTENT)\n//                                        intent.type = \"application/zip\"\n//                                        selectZipLauncher.launch(intent)\n                                        Toast.makeText(\n                                            context,\n                                            \"Under development\",\n                                            Toast.LENGTH_SHORT\n                                        ).show()\n                                    }\n\n                                    moduleLoad -> {\n                                        val intent = Intent(Intent.ACTION_GET_CONTENT)\n                                        intent.type = \"*/*\"\n                                        selectKpmLauncher.launch(intent)\n                                    }\n                                }\n                            })\n                        }\n                    }\n                }\n            }\n        }\n    }) { innerPadding ->\n        KPModuleList(\n            viewModel = viewModel,\n            modules = viewModel.moduleList,\n            modifier = Modifier\n                .padding(innerPadding)\n                .fillMaxSize(),\n            state = kpModuleListState,\n            scrollBehavior = scrollBehavior\n        )\n    }\n}\n\nsuspend fun loadModule(loadingDialog: LoadingDialogHandle, uri: Uri, args: String): Int {\n    val rc = loadingDialog.withLoading {\n        withContext(Dispatchers.IO) {\n            run {\n                val kpmDir: ExtendedFile =\n                    FileSystemManager.getLocal().getFile(apApp.filesDir.parent, \"kpm\")\n                kpmDir.deleteRecursively()\n                kpmDir.mkdirs()\n                val rand = (1..4).map { ('a'..'z').random() }.joinToString(\"\")\n                val kpm = kpmDir.getChildFile(\"${rand}.kpm\")\n                Log.d(TAG, \"save tmp kpm: ${kpm.path}\")\n                var rc = -1\n                try {\n                    uri.inputStream().buffered().writeTo(kpm)\n                    rc = Natives.loadKernelPatchModule(kpm.path, args).toInt()\n                } catch (e: IOException) {\n                    Log.e(TAG, \"Copy kpm error: $e\")\n                }\n                Log.d(TAG, \"load ${kpm.path} rc: $rc\")\n                rc\n            }\n        }\n    }\n    return rc\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun KPMControlDialog(showDialog: MutableState<Boolean>) {\n    var controlParam by remember { mutableStateOf(\"\") }\n    var enable by remember { mutableStateOf(false) }\n    val scope = rememberCoroutineScope()\n    val loadingDialog = rememberLoadingDialog()\n    val context = LocalContext.current\n    val outMsgStringRes = stringResource(id = R.string.kpm_control_outMsg)\n    val okStringRes = stringResource(id = R.string.kpm_control_ok)\n    val failedStringRes = stringResource(id = R.string.kpm_control_failed)\n\n    lateinit var controlResult: Natives.KPMCtlRes\n\n    suspend fun onModuleControl(module: KPModel.KPMInfo) {\n        loadingDialog.withLoading {\n            withContext(Dispatchers.IO) {\n                controlResult = Natives.kernelPatchModuleControl(module.name, controlParam)\n            }\n        }\n\n        if (controlResult.rc >= 0) {\n            Toast.makeText(\n                context,\n                \"$okStringRes\\n${outMsgStringRes}: ${controlResult.outMsg}\",\n                Toast.LENGTH_SHORT\n            ).show()\n        } else {\n            Toast.makeText(\n                context,\n                \"$failedStringRes\\n${outMsgStringRes}: ${controlResult.outMsg}\",\n                Toast.LENGTH_SHORT\n            ).show()\n        }\n    }\n\n    BasicAlertDialog(\n        onDismissRequest = { showDialog.value = false }, properties = DialogProperties(\n            decorFitsSystemWindows = true,\n            usePlatformDefaultWidth = false,\n        )\n    ) {\n        Surface(\n            modifier = Modifier\n                .width(310.dp)\n                .wrapContentHeight(),\n            shape = RoundedCornerShape(30.dp),\n            tonalElevation = AlertDialogDefaults.TonalElevation,\n            color = AlertDialogDefaults.containerColor,\n        ) {\n            Column(modifier = Modifier.padding(PaddingValues(all = 24.dp))) {\n                Box(\n                    Modifier\n                        .padding(PaddingValues(bottom = 16.dp))\n                        .align(Alignment.Start)\n                ) {\n                    Text(\n                        text = stringResource(id = R.string.kpm_control_dialog_title),\n                        style = MaterialTheme.typography.headlineSmall\n                    )\n                }\n\n                Box(\n                    Modifier\n                        .weight(weight = 1f, fill = false)\n                        .align(Alignment.Start)\n                ) {\n                    Text(\n                        text = stringResource(id = R.string.kpm_control_dialog_content),\n                        style = MaterialTheme.typography.bodyMedium\n                    )\n                }\n\n                Box(\n                    contentAlignment = Alignment.CenterEnd,\n                ) {\n                    OutlinedTextField(\n                        value = controlParam,\n                        modifier = Modifier\n                            .fillMaxWidth()\n                            .padding(top = 6.dp),\n                        onValueChange = {\n                            controlParam = it\n                            enable = controlParam.isNotBlank()\n                        },\n                        shape = RoundedCornerShape(50.0f),\n                        label = { Text(stringResource(id = R.string.kpm_control_paramters)) },\n                        visualTransformation = VisualTransformation.None,\n                    )\n                }\n\n                Spacer(modifier = Modifier.height(12.dp))\n                Row(\n                    modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End\n                ) {\n                    TextButton(onClick = { showDialog.value = false }) {\n                        Text(stringResource(id = android.R.string.cancel))\n                    }\n\n                    Button(onClick = {\n                        showDialog.value = false\n\n                        scope.launch { onModuleControl(targetKPMToControl) }\n\n                    }, enabled = enable) {\n                        Text(stringResource(id = android.R.string.ok))\n                    }\n                }\n            }\n        }\n        val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n        APDialogBlurBehindUtils.setupWindowBlurListener(dialogWindowProvider.window)\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun KPModuleList(\n    viewModel: KPModuleViewModel,\n    modules: List<KPModel.KPMInfo>,\n    modifier: Modifier = Modifier,\n    state: LazyListState,\n    scrollBehavior: SearchBarScrollBehavior\n) {\n    val moduleStr = stringResource(id = R.string.kpm)\n    val moduleUninstallConfirm = stringResource(id = R.string.kpm_unload_confirm)\n    val uninstall = stringResource(id = R.string.kpm_unload)\n    val cancel = stringResource(id = android.R.string.cancel)\n\n    val confirmDialog = rememberConfirmDialog()\n    val loadingDialog = rememberLoadingDialog()\n\n    val showKPMControlDialog = remember { mutableStateOf(false) }\n    if (showKPMControlDialog.value) {\n        KPMControlDialog(showDialog = showKPMControlDialog)\n    }\n\n    suspend fun onModuleUninstall(module: KPModel.KPMInfo) {\n        val confirmResult = confirmDialog.awaitConfirm(\n            moduleStr,\n            content = moduleUninstallConfirm.format(module.name),\n            confirm = uninstall,\n            dismiss = cancel\n        )\n        if (confirmResult != ConfirmResult.Confirmed) {\n            return\n        }\n\n        val success = loadingDialog.withLoading {\n            withContext(Dispatchers.IO) {\n                Natives.unloadKernelPatchModule(module.name) == 0L\n            }\n        }\n\n        if (success) {\n            viewModel.fetchModuleList()\n        }\n    }\n\n    PullToRefreshBox(\n        modifier = modifier,\n        onRefresh = { viewModel.fetchModuleList() },\n        isRefreshing = viewModel.isRefreshing\n    ) {\n        LazyColumn(\n            modifier = Modifier.fillMaxSize().nestedScroll(scrollBehavior.nestedScrollConnection),\n            state = state,\n            verticalArrangement = Arrangement.spacedBy(16.dp),\n            contentPadding = remember {\n                PaddingValues(\n                    start = 16.dp,\n                    top = 11.dp, // spacedBy - TopBar padding\n                    end = 16.dp,\n                    bottom = 16.dp + 16.dp + 56.dp /*  Scaffold Fab Spacing + Fab container height */\n                )\n            },\n        ) {\n            when {\n                modules.isEmpty() -> {\n                    item {\n                        Box(\n                            modifier = Modifier.fillParentMaxSize(),\n                            contentAlignment = Alignment.Center\n                        ) {\n                            Text(\n                                stringResource(R.string.kpm_apm_empty), textAlign = TextAlign.Center\n                            )\n                        }\n                    }\n                }\n\n                else -> {\n                    items(modules) { module ->\n                        val scope = rememberCoroutineScope()\n                        KPModuleItem(\n                            module,\n                            onUninstall = {\n                                scope.launch { onModuleUninstall(module) }\n                            },\n                            onControl = {\n                                targetKPMToControl = module\n                                showKPMControlDialog.value = true\n                            },\n                        )\n\n                        // fix last item shadow incomplete in LazyColumn\n                        Spacer(Modifier.height(1.dp))\n                    }\n                }\n            }\n        }\n    }\n}\n\n@Composable\nprivate fun KPModuleItem(\n    module: KPModel.KPMInfo,\n    onUninstall: (KPModel.KPMInfo) -> Unit,\n    onControl: (KPModel.KPMInfo) -> Unit,\n    modifier: Modifier = Modifier,\n    alpha: Float = 1f,\n) {\n    val moduleAuthor = stringResource(id = R.string.kpm_author)\n    val moduleArgs = stringResource(id = R.string.kpm_args)\n    val decoration = TextDecoration.None\n\n    Surface(\n        modifier = modifier,\n        color = MaterialTheme.colorScheme.surface,\n        tonalElevation = 1.dp,\n        shape = RoundedCornerShape(20.dp)\n    ) {\n\n        Box(\n            modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center\n        ) {\n            Column(\n                modifier = Modifier.fillMaxWidth()\n            ) {\n                Row(\n                    modifier = Modifier.padding(all = 16.dp),\n                    verticalAlignment = Alignment.CenterVertically\n                ) {\n                    Column(\n                        modifier = Modifier\n                            .alpha(alpha = alpha)\n                            .weight(1f),\n                        verticalArrangement = Arrangement.spacedBy(2.dp)\n                    ) {\n                        Text(\n                            text = module.name,\n                            style = MaterialTheme.typography.titleSmall.copy(fontWeight = FontWeight.Bold),\n                            maxLines = 2,\n                            textDecoration = decoration,\n                            overflow = TextOverflow.Ellipsis\n                        )\n\n                        Text(\n                            text = \"${module.version}, $moduleAuthor ${module.author}\",\n                            style = MaterialTheme.typography.bodySmall,\n                            textDecoration = decoration,\n                            color = MaterialTheme.colorScheme.onSurfaceVariant\n                        )\n\n                        Text(\n                            text = \"$moduleArgs: ${module.args}\",\n                            style = MaterialTheme.typography.bodySmall,\n                            textDecoration = decoration,\n                            color = MaterialTheme.colorScheme.onSurfaceVariant\n                        )\n                    }\n\n                }\n\n                Text(\n                    modifier = Modifier\n                        .alpha(alpha = alpha)\n                        .padding(horizontal = 16.dp),\n                    text = module.description,\n                    style = MaterialTheme.typography.bodySmall,\n                    textDecoration = decoration,\n                    color = MaterialTheme.colorScheme.outline\n                )\n\n                HorizontalDivider(\n                    thickness = 1.5.dp,\n                    color = MaterialTheme.colorScheme.surface,\n                    modifier = Modifier.padding(top = 8.dp)\n                )\n\n                Row(\n                    modifier = Modifier\n                        .padding(horizontal = 16.dp, vertical = 8.dp)\n                        .fillMaxWidth(),\n                    verticalAlignment = Alignment.CenterVertically\n                ) {\n                    Spacer(modifier = Modifier.weight(1f))\n\n                    FilledTonalButton(\n                        onClick = { onControl(module) },\n                        enabled = true,\n                        contentPadding = PaddingValues(12.dp)\n                    ) {\n                        Icon(\n                            modifier = Modifier.size(20.dp),\n                            painter = painterResource(id = R.drawable.settings),\n                            contentDescription = stringResource(id = R.string.kpm_control)\n                        )\n                    }\n\n                    Spacer(modifier = Modifier.width(12.dp))\n\n                    KPModuleRemoveButton(enabled = true, onClick = { onUninstall(module) })\n                }\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/Patches.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport android.Manifest\nimport android.app.Activity\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.net.Uri\nimport android.util.Log\nimport androidx.activity.compose.rememberLauncherForActivityResult\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.size\nimport androidx.compose.foundation.layout.wrapContentWidth\nimport androidx.compose.foundation.rememberScrollState\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.foundation.text.BasicTextField\nimport androidx.compose.foundation.text.KeyboardOptions\nimport androidx.compose.foundation.text.selection.SelectionContainer\nimport androidx.compose.foundation.verticalScroll\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.filled.Delete\nimport androidx.compose.material.icons.filled.Refresh\nimport androidx.compose.material.icons.filled.Visibility\nimport androidx.compose.material.icons.filled.VisibilityOff\nimport androidx.compose.material.icons.filled.Settings\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.layout.wrapContentHeight\nimport androidx.compose.material3.AlertDialogDefaults\nimport androidx.compose.material3.BasicAlertDialog\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.TextButton\nimport androidx.compose.ui.platform.LocalView\nimport androidx.compose.ui.window.DialogProperties\nimport androidx.compose.ui.window.DialogWindowProvider\nimport me.bmax.apatch.util.ui.APDialogBlurBehindUtils\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.CardDefaults\nimport androidx.compose.material3.CircularProgressIndicator\nimport androidx.compose.material3.ElevatedCard\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.ExtendedFloatingActionButton\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.OutlinedTextField\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TopAppBar\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.SideEffect\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.input.KeyboardType\nimport androidx.compose.ui.text.input.PasswordVisualTransformation\nimport androidx.compose.ui.text.input.VisualTransformation\nimport androidx.compose.ui.unit.dp\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport androidx.lifecycle.viewmodel.compose.viewModel\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport me.bmax.apatch.R\nimport me.bmax.apatch.ui.viewmodel.KPModel\nimport me.bmax.apatch.ui.viewmodel.PatchesViewModel\nimport me.bmax.apatch.util.Version\nimport me.bmax.apatch.util.reboot\n\nprivate const val TAG = \"Patches\"\n\n@Destination<RootGraph>\n@Composable\nfun Patches(mode: PatchesViewModel.PatchMode) {\n    val scrollState = rememberScrollState()\n    val scope = rememberCoroutineScope()\n\n    val viewModel = viewModel<PatchesViewModel>()\n    SideEffect {\n        viewModel.prepare(mode)\n    }\n\n    Scaffold(topBar = {\n        TopBar()\n    }, floatingActionButton = {\n        if (viewModel.needReboot) {\n            val reboot = stringResource(id = R.string.reboot)\n            ExtendedFloatingActionButton(\n                onClick = {\n                    scope.launch {\n                        withContext(Dispatchers.IO) {\n                            reboot()\n                        }\n                    }\n                },\n                icon = { Icon(Icons.Filled.Refresh, reboot) },\n                text = { Text(text = reboot) },\n            )\n        }\n    }) { innerPadding ->\n        Column(\n            modifier = Modifier\n                .padding(innerPadding)\n                .padding(horizontal = 16.dp)\n                .verticalScroll(scrollState),\n            verticalArrangement = Arrangement.spacedBy(16.dp)\n        ) {\n            val context = LocalContext.current\n\n            // request permissions\n            val permissions = arrayOf(\n                Manifest.permission.WRITE_EXTERNAL_STORAGE,\n                Manifest.permission.READ_EXTERNAL_STORAGE\n            )\n            val permissionsToRequest = permissions.filter {\n                ContextCompat.checkSelfPermission(context, it) != PackageManager.PERMISSION_GRANTED\n            }\n            if (permissionsToRequest.isNotEmpty()) {\n                ActivityCompat.requestPermissions(\n                    context as Activity,\n                    permissionsToRequest.toTypedArray(),\n                    1001\n                )\n            }\n\n            PatchMode(mode)\n            ErrorView(viewModel.error)\n            KernelPatchImageView(viewModel.kpimgInfo)\n\n            if (mode == PatchesViewModel.PatchMode.PATCH_ONLY && selectedBootImage != null && viewModel.kimgInfo.banner.isEmpty()) {\n                viewModel.copyAndParseBootimg(selectedBootImage!!)\n                // Fix endless loop. It's not normal if (parse done && working thread is not working) but banner still null\n                // Leave user re-choose\n                if (!viewModel.running && viewModel.kimgInfo.banner.isEmpty()) {\n                    selectedBootImage = null\n                }\n            }\n\n            // select boot.img\n            if (mode == PatchesViewModel.PatchMode.PATCH_ONLY && viewModel.kimgInfo.banner.isEmpty()) {\n                SelectFileButton(\n                    text = stringResource(id = R.string.patch_select_bootimg_btn),\n                    onSelected = { data, uri ->\n                        Log.d(TAG, \"select boot.img, data: $data, uri: $uri\")\n                        viewModel.copyAndParseBootimg(uri)\n                    }\n                )\n            }\n\n            if (viewModel.bootSlot.isNotEmpty() || viewModel.bootDev.isNotEmpty()) {\n                BootimgView(slot = viewModel.bootSlot, boot = viewModel.bootDev)\n            }\n\n            if (viewModel.kimgInfo.banner.isNotEmpty()) {\n                KernelImageView(viewModel.kimgInfo)\n            }\n\n            if (mode != PatchesViewModel.PatchMode.UNPATCH && viewModel.kimgInfo.banner.isNotEmpty()) {\n                SetSuperKeyView(viewModel)\n            }\n\n            // existed extras\n            if (mode == PatchesViewModel.PatchMode.PATCH_AND_INSTALL || mode == PatchesViewModel.PatchMode.INSTALL_TO_NEXT_SLOT) {\n                viewModel.existedExtras.forEach(action = {\n                    ExtraItem(extra = it, true, onDelete = {\n                        viewModel.existedExtras.remove(it)\n                    })\n                })\n            }\n\n            // add new extras\n            if (mode != PatchesViewModel.PatchMode.UNPATCH) {\n                viewModel.newExtras.forEach(action = {\n                    ExtraItem(extra = it, false, onDelete = {\n                        val idx = viewModel.newExtras.indexOf(it)\n                        viewModel.newExtras.remove(it)\n                        viewModel.newExtrasFileName.removeAt(idx)\n                    })\n                })\n            }\n\n            // add new KPM\n            if (viewModel.superkey.isNotEmpty() && !viewModel.patching && !viewModel.patchdone && mode != PatchesViewModel.PatchMode.UNPATCH) {\n                SelectFileButton(\n                    text = stringResource(id = R.string.patch_embed_kpm_btn),\n                    onSelected = { data, uri ->\n                        Log.d(TAG, \"select kpm, data: $data, uri: $uri\")\n                        viewModel.embedKPM(uri)\n                    }\n                )\n            }\n\n            // do patch, update, unpatch\n            if (!viewModel.patching && !viewModel.patchdone) {\n                // patch start\n                if (mode != PatchesViewModel.PatchMode.UNPATCH && viewModel.superkey.isNotEmpty()) {\n                    StartButton(stringResource(id = R.string.patch_start_patch_btn)) {\n                        viewModel.doPatch(\n                            mode\n                        )\n                    }\n                }\n                // unpatch\n                if (mode == PatchesViewModel.PatchMode.UNPATCH && viewModel.kimgInfo.banner.isNotEmpty()) {\n                    StartButton(stringResource(id = R.string.patch_start_unpatch_btn)) { viewModel.doUnpatch() }\n                }\n            }\n\n            // patch log\n            if (viewModel.patching || viewModel.patchdone) {\n                SelectionContainer {\n                    Text(\n                        modifier = Modifier.padding(8.dp),\n                        text = viewModel.patchLog,\n                        fontSize = MaterialTheme.typography.bodySmall.fontSize,\n                        fontFamily = MaterialTheme.typography.bodySmall.fontFamily,\n                        lineHeight = MaterialTheme.typography.bodySmall.lineHeight,\n                    )\n                }\n                LaunchedEffect(viewModel.patchLog) {\n                    scrollState.animateScrollTo(scrollState.maxValue)\n                }\n            }\n\n            Spacer(modifier = Modifier.height(12.dp))\n\n            // loading progress\n            if (viewModel.running) {\n                Box(\n                    modifier = Modifier\n                        .padding(innerPadding)\n                        .align(Alignment.CenterHorizontally)\n                ) {\n                    CircularProgressIndicator(\n                        modifier = Modifier\n                            .size(50.dp)\n                            .padding(16.dp)\n                            .align(Alignment.BottomCenter)\n                    )\n                }\n            }\n        }\n    }\n}\n\n\n@Composable\nprivate fun StartButton(text: String, onClick: () -> Unit) {\n    Column(\n        modifier = Modifier\n            .fillMaxWidth(),\n        horizontalAlignment = Alignment.End\n    ) {\n        Button(\n            onClick = onClick,\n            content = {\n                Text(text = text)\n            }\n        )\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun ExtraConfigDialog(kpmInfo: KPModel.KPMInfo, onDismiss: () -> Unit) {\n    var event by remember { mutableStateOf(kpmInfo.event) }\n    var args by remember { mutableStateOf(kpmInfo.args) }\n\n    BasicAlertDialog(\n        onDismissRequest = onDismiss,\n        properties = DialogProperties(\n            decorFitsSystemWindows = true,\n            usePlatformDefaultWidth = false,\n        )\n    ) {\n        Surface(\n            modifier = Modifier\n                .width(310.dp)\n                .wrapContentHeight(),\n            shape = RoundedCornerShape(30.dp),\n            tonalElevation = AlertDialogDefaults.TonalElevation,\n            color = AlertDialogDefaults.containerColor,\n        ) {\n            Column(modifier = Modifier.padding(PaddingValues(all = 24.dp))) {\n                Text(\n                    text = stringResource(id = R.string.kpm_control_dialog_title),\n                    style = MaterialTheme.typography.headlineSmall,\n                    modifier = Modifier.padding(bottom = 16.dp)\n                )\n\n                OutlinedTextField(\n                    value = event,\n                    onValueChange = {\n                        event = it\n                        kpmInfo.event = it\n                    },\n                    label = { Text(stringResource(id = R.string.patch_item_extra_event)) },\n                    modifier = Modifier.fillMaxWidth()\n                )\n\n                Spacer(modifier = Modifier.height(16.dp))\n\n                OutlinedTextField(\n                    value = args,\n                    onValueChange = {\n                        args = it\n                        kpmInfo.args = it\n                    },\n                    label = { Text(stringResource(id = R.string.patch_item_extra_args)) },\n                    modifier = Modifier.fillMaxWidth()\n                )\n\n                Spacer(modifier = Modifier.height(24.dp))\n\n                Row(\n                    modifier = Modifier.fillMaxWidth(),\n                    horizontalArrangement = Arrangement.End\n                ) {\n                    TextButton(onClick = onDismiss) {\n                        Text(stringResource(id = android.R.string.ok))\n                    }\n                }\n            }\n        }\n        val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n        APDialogBlurBehindUtils.setupWindowBlurListener(dialogWindowProvider.window)\n    }\n}\n\n@Composable\nprivate fun ExtraItem(extra: KPModel.IExtraInfo, existed: Boolean, onDelete: () -> Unit) {\n    var showConfigDialog by remember { mutableStateOf(false) }\n\n    if (showConfigDialog && extra is KPModel.KPMInfo) {\n        ExtraConfigDialog(extra, onDismiss = { showConfigDialog = false })\n    }\n\n    ElevatedCard(\n        colors = CardDefaults.elevatedCardColors(containerColor = run {\n            MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 1f)\n        }),\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(12.dp),\n        ) {\n            Row(modifier = Modifier.align(Alignment.CenterHorizontally)) {\n                Text(\n                    text = stringResource(\n                        id =\n                            if (existed) R.string.patch_item_existed_extra_kpm else R.string.patch_item_new_extra_kpm\n                    ) +\n                            \" \" + extra.type.toString().uppercase(),\n                    style = MaterialTheme.typography.bodyLarge,\n                    modifier = Modifier\n                        .weight(1f)\n                        .wrapContentWidth(Alignment.CenterHorizontally)\n                )\n                if (extra.type == KPModel.ExtraType.KPM) {\n                    Icon(\n                        imageVector = Icons.Default.Settings,\n                        contentDescription = \"Config\",\n                        modifier = Modifier\n                            .padding(end = 8.dp)\n                            .clickable { showConfigDialog = true }\n                    )\n                }\n                Icon(\n                    imageVector = Icons.Default.Delete,\n                    contentDescription = \"Delete\",\n                    modifier = Modifier\n                        .padding(end = 8.dp)\n                        .clickable { onDelete() })\n            }\n            if (extra.type == KPModel.ExtraType.KPM) {\n                val kpmInfo: KPModel.KPMInfo = extra as KPModel.KPMInfo\n                Text(\n                    text = \"${stringResource(id = R.string.patch_item_extra_name) + \" \"} ${kpmInfo.name}\",\n                    style = MaterialTheme.typography.bodyMedium\n                )\n                Text(\n                    text = \"${stringResource(id = R.string.patch_item_extra_version) + \" \"} ${kpmInfo.version}\",\n                    style = MaterialTheme.typography.bodyMedium\n                )\n                Text(\n                    text = \"${stringResource(id = R.string.patch_item_extra_kpm_license) + \" \"} ${kpmInfo.license}\",\n                    style = MaterialTheme.typography.bodyMedium\n                )\n                Text(\n                    text = \"${stringResource(id = R.string.patch_item_extra_author) + \" \"} ${kpmInfo.author}\",\n                    style = MaterialTheme.typography.bodyMedium\n                )\n                Text(\n                    text = \"${stringResource(id = R.string.patch_item_extra_kpm_desciption) + \" \"} ${kpmInfo.description}\",\n                    style = MaterialTheme.typography.bodyMedium\n                )\n            }\n        }\n    }\n}\n\n\n@Composable\nprivate fun SetSuperKeyView(viewModel: PatchesViewModel) {\n    var skey by remember { mutableStateOf(viewModel.superkey) }\n    var showWarn by remember { mutableStateOf(!viewModel.checkSuperKeyValidation(skey)) }\n    var keyVisible by remember { mutableStateOf(false) }\n    ElevatedCard(\n        colors = CardDefaults.elevatedCardColors(containerColor = run {\n            MaterialTheme.colorScheme.secondaryContainer\n        })\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(12.dp),\n        ) {\n            Column(\n                modifier = Modifier\n                    .fillMaxWidth(),\n                horizontalAlignment = Alignment.CenterHorizontally\n            ) {\n                Text(\n                    text = stringResource(id = R.string.patch_item_skey),\n                    style = MaterialTheme.typography.bodyLarge\n                )\n            }\n            if (showWarn) {\n                Spacer(modifier = Modifier.height(3.dp))\n                Text(\n                    color = Color.Red,\n                    text = stringResource(id = R.string.patch_item_set_skey_label),\n                    style = MaterialTheme.typography.bodyMedium\n                )\n            }\n            Column {\n                //Spacer(modifier = Modifier.height(8.dp))\n                Box(\n                    contentAlignment = Alignment.CenterEnd,\n                ) {\n                    OutlinedTextField(\n                        modifier = Modifier\n                            .fillMaxWidth()\n                            .padding(top = 6.dp),\n                        value = skey,\n                        label = { Text(stringResource(id = R.string.patch_set_superkey)) },\n                        visualTransformation = if (keyVisible) VisualTransformation.None else PasswordVisualTransformation(),\n                        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),\n                        shape = RoundedCornerShape(50.0f),\n                        onValueChange = {\n                            skey = it\n                            if (viewModel.checkSuperKeyValidation(it)) {\n                                viewModel.superkey = it\n                                showWarn = false\n                            } else {\n                                viewModel.superkey = \"\"\n                                showWarn = true\n                            }\n                        },\n                    )\n                    IconButton(\n                        modifier = Modifier\n                            .size(40.dp)\n                            .padding(top = 15.dp, end = 5.dp),\n                        onClick = { keyVisible = !keyVisible }\n                    ) {\n                        Icon(\n                            imageVector = if (keyVisible) Icons.Default.Visibility else Icons.Default.VisibilityOff,\n                            contentDescription = null,\n                            tint = Color.Gray\n                        )\n                    }\n                }\n            }\n        }\n    }\n}\n\n@Composable\nprivate fun KernelPatchImageView(kpImgInfo: KPModel.KPImgInfo) {\n    if (kpImgInfo.version.isEmpty()) return\n    ElevatedCard(\n        colors = CardDefaults.elevatedCardColors(containerColor = run {\n            MaterialTheme.colorScheme.secondaryContainer\n        })\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(start = 12.dp, top = 12.dp, end = 12.dp, bottom = 12.dp),\n        ) {\n            Column(\n                modifier = Modifier\n                    .fillMaxWidth(),\n                horizontalAlignment = Alignment.CenterHorizontally\n            ) {\n                Text(\n                    text = stringResource(id = R.string.patch_item_kpimg),\n                    style = MaterialTheme.typography.bodyLarge\n                )\n            }\n            Text(\n                text = stringResource(id = R.string.patch_item_kpimg_version) + \" \" + Version.uInt2String(\n                    kpImgInfo.version.substring(2).toUInt(16)\n                ), style = MaterialTheme.typography.bodyMedium\n            )\n            Text(\n                text = stringResource(id = R.string.patch_item_kpimg_comile_time) + \" \" + kpImgInfo.compileTime,\n                style = MaterialTheme.typography.bodyMedium\n            )\n            Text(\n                text = stringResource(id = R.string.patch_item_kpimg_config) + \" \" + kpImgInfo.config,\n                style = MaterialTheme.typography.bodyMedium\n            )\n        }\n    }\n}\n\n@Composable\nprivate fun BootimgView(slot: String, boot: String) {\n    ElevatedCard(\n        colors = CardDefaults.elevatedCardColors(containerColor = run {\n            MaterialTheme.colorScheme.secondaryContainer\n        })\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(12.dp),\n        ) {\n            Column(\n                modifier = Modifier\n                    .fillMaxWidth(),\n                horizontalAlignment = Alignment.CenterHorizontally\n            ) {\n                Text(\n                    text = stringResource(id = R.string.patch_item_bootimg),\n                    style = MaterialTheme.typography.bodyLarge\n                )\n            }\n            if (slot.isNotEmpty()) {\n                Text(\n                    text = stringResource(id = R.string.patch_item_bootimg_slot) + \" \" + slot,\n                    style = MaterialTheme.typography.bodyMedium\n                )\n            }\n            Text(\n                text = stringResource(id = R.string.patch_item_bootimg_dev) + \" \" + boot,\n                style = MaterialTheme.typography.bodyMedium\n            )\n        }\n    }\n}\n\n@Composable\nprivate fun KernelImageView(kImgInfo: KPModel.KImgInfo) {\n    ElevatedCard(\n        colors = CardDefaults.elevatedCardColors(containerColor = run {\n            MaterialTheme.colorScheme.secondaryContainer\n        })\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(12.dp),\n        ) {\n            Column(\n                modifier = Modifier\n                    .fillMaxWidth(),\n                horizontalAlignment = Alignment.CenterHorizontally\n            ) {\n                Text(\n                    text = stringResource(id = R.string.patch_item_kernel),\n                    style = MaterialTheme.typography.bodyLarge\n                )\n            }\n            Text(text = kImgInfo.banner, style = MaterialTheme.typography.bodyMedium)\n        }\n    }\n}\n\n\n@Composable\nprivate fun SelectFileButton(text: String, onSelected: (data: Intent, uri: Uri) -> Unit) {\n    val selectFileLauncher = rememberLauncherForActivityResult(\n        contract = ActivityResultContracts.StartActivityForResult()\n    ) {\n        if (it.resultCode != Activity.RESULT_OK) {\n            return@rememberLauncherForActivityResult\n        }\n        val data = it.data ?: return@rememberLauncherForActivityResult\n        val uri = data.data ?: return@rememberLauncherForActivityResult\n        onSelected(data, uri)\n    }\n\n    Column(\n        modifier = Modifier\n            .fillMaxWidth(),\n        horizontalAlignment = Alignment.End\n    ) {\n        Button(\n            onClick = {\n                val intent = Intent(Intent.ACTION_GET_CONTENT)\n                intent.type = \"*/*\"\n                selectFileLauncher.launch(intent)\n            },\n            content = { Text(text = text) }\n        )\n    }\n}\n\n@Composable\nprivate fun ErrorView(error: String) {\n    if (error.isEmpty()) return\n    ElevatedCard(\n        colors = CardDefaults.elevatedCardColors(containerColor = run {\n            MaterialTheme.colorScheme.error\n        })\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(start = 12.dp, top = 12.dp, end = 12.dp, bottom = 12.dp),\n            horizontalAlignment = Alignment.CenterHorizontally\n        ) {\n            Text(\n                text = stringResource(id = R.string.patch_item_error),\n                style = MaterialTheme.typography.bodyLarge\n            )\n            Text(text = error, style = MaterialTheme.typography.bodyMedium)\n        }\n    }\n}\n\n@Composable\nprivate fun PatchMode(mode: PatchesViewModel.PatchMode) {\n    ElevatedCard(\n        colors = CardDefaults.elevatedCardColors(containerColor = run {\n            MaterialTheme.colorScheme.secondaryContainer\n        })\n    ) {\n        Column(\n            modifier = Modifier\n                .fillMaxWidth()\n                .padding(12.dp),\n            horizontalAlignment = Alignment.CenterHorizontally\n        ) {\n            Text(text = stringResource(id = mode.sId), style = MaterialTheme.typography.bodyLarge)\n        }\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nprivate fun TopBar() {\n    TopAppBar(title = { Text(stringResource(R.string.patch_config_title)) })\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/Settings.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Build\nimport android.widget.Toast\nimport androidx.activity.compose.rememberLauncherForActivityResult\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.annotation.StringRes\nimport androidx.appcompat.app.AppCompatDelegate\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Arrangement\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.PaddingValues\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose.foundation.layout.WindowInsets\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.layout.wrapContentHeight\nimport androidx.compose.foundation.lazy.LazyColumn\nimport androidx.compose.foundation.lazy.items\nimport androidx.compose.foundation.lazy.itemsIndexed\nimport androidx.compose.foundation.rememberScrollState\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.foundation.verticalScroll\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.filled.BugReport\nimport androidx.compose.material.icons.filled.ColorLens\nimport androidx.compose.material.icons.filled.Commit\nimport androidx.compose.material.icons.filled.DarkMode\nimport androidx.compose.material.icons.filled.DeveloperMode\nimport androidx.compose.material.icons.filled.Engineering\nimport androidx.compose.material.icons.filled.FormatColorFill\nimport androidx.compose.material.icons.filled.InvertColors\nimport androidx.compose.material.icons.filled.Key\nimport androidx.compose.material.icons.filled.Save\nimport androidx.compose.material.icons.filled.Share\nimport androidx.compose.material.icons.filled.Translate\nimport androidx.compose.material.icons.filled.Update\nimport androidx.compose.material3.AlertDialogDefaults\nimport androidx.compose.material3.BasicAlertDialog\nimport androidx.compose.material3.Button\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.ListItem\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.ModalBottomSheet\nimport androidx.compose.material3.OutlinedTextField\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.SnackbarHost\nimport androidx.compose.material3.Surface\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.TextButton\nimport androidx.compose.material3.TopAppBar\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.MutableState\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.livedata.observeAsState\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.saveable.rememberSaveable\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Alignment\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.platform.LocalView\nimport androidx.compose.ui.res.stringArrayResource\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.input.VisualTransformation\nimport androidx.compose.ui.text.style.LineHeightStyle\nimport androidx.compose.ui.text.style.TextAlign\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.window.DialogProperties\nimport androidx.compose.ui.window.DialogWindowProvider\nimport androidx.core.content.FileProvider\nimport androidx.core.content.edit\nimport androidx.core.os.LocaleListCompat\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.BuildConfig\nimport me.bmax.apatch.Natives\nimport me.bmax.apatch.R\nimport me.bmax.apatch.ui.component.SwitchItem\nimport me.bmax.apatch.ui.component.rememberConfirmDialog\nimport me.bmax.apatch.ui.component.rememberLoadingDialog\nimport me.bmax.apatch.ui.theme.refreshTheme\nimport me.bmax.apatch.util.APatchKeyHelper\nimport me.bmax.apatch.util.getBugreportFile\nimport me.bmax.apatch.util.isGlobalNamespaceEnabled\nimport me.bmax.apatch.util.outputStream\nimport me.bmax.apatch.util.rootShellForResult\nimport me.bmax.apatch.util.setGlobalNamespaceEnabled\nimport me.bmax.apatch.util.ui.APDialogBlurBehindUtils\nimport me.bmax.apatch.util.ui.LocalSnackbarHost\nimport me.bmax.apatch.util.ui.NavigationBarsSpacer\nimport java.time.LocalDateTime\nimport java.time.format.DateTimeFormatter\nimport java.util.Locale\n\n@Destination<RootGraph>\n@Composable\n@OptIn(ExperimentalMaterial3Api::class)\nfun SettingScreen() {\n    val state by APApplication.apStateLiveData.observeAsState(APApplication.State.UNKNOWN_STATE)\n    val kPatchReady = state != APApplication.State.UNKNOWN_STATE\n    val aPatchReady =\n        (state == APApplication.State.ANDROIDPATCH_INSTALLING || state == APApplication.State.ANDROIDPATCH_INSTALLED || state == APApplication.State.ANDROIDPATCH_NEED_UPDATE)\n    var isGlobalNamespaceEnabled by rememberSaveable {\n        mutableStateOf(false)\n    }\n    var bSkipStoreSuperKey by rememberSaveable {\n        mutableStateOf(APatchKeyHelper.shouldSkipStoreSuperKey())\n    }\n    if (kPatchReady && aPatchReady) {\n        isGlobalNamespaceEnabled = isGlobalNamespaceEnabled()\n    }\n\n    val snackBarHost = LocalSnackbarHost.current\n\n    Scaffold(\n        topBar = {\n            TopAppBar(\n                title = { Text(stringResource(R.string.settings)) },\n            )\n        },\n        snackbarHost = { SnackbarHost(snackBarHost) }\n    ) { paddingValues ->\n\n        val loadingDialog = rememberLoadingDialog()\n        val clearKeyDialog = rememberConfirmDialog(\n            onConfirm = {\n                APatchKeyHelper.clearConfigKey()\n                APApplication.superKey = \"\"\n            }\n        )\n\n        val showLanguageDialog = rememberSaveable { mutableStateOf(false) }\n        LanguageDialog(showLanguageDialog)\n\n        val showResetSuPathDialog = remember { mutableStateOf(false) }\n        if (showResetSuPathDialog.value) {\n            ResetSUPathDialog(showResetSuPathDialog)\n        }\n\n        val showThemeChooseDialog = remember { mutableStateOf(false) }\n        if (showThemeChooseDialog.value) {\n            ThemeChooseDialog(showThemeChooseDialog)\n        }\n\n        var showLogBottomSheet by remember { mutableStateOf(false) }\n\n        val scope = rememberCoroutineScope()\n        val context = LocalContext.current\n        val logSavedMessage = stringResource(R.string.log_saved)\n        val exportBugreportLauncher = rememberLauncherForActivityResult(\n            ActivityResultContracts.CreateDocument(\"application/gzip\")\n        ) { uri: Uri? ->\n            if (uri != null) {\n                scope.launch(Dispatchers.IO) {\n                    loadingDialog.show()\n                    uri.outputStream().use { output ->\n                        getBugreportFile(context).inputStream().use {\n                            it.copyTo(output)\n                        }\n                    }\n                    loadingDialog.hide()\n                    snackBarHost.showSnackbar(message = logSavedMessage)\n                }\n            }\n        }\n\n        Column(\n            modifier = Modifier\n                .padding(paddingValues)\n                .fillMaxWidth()\n                .verticalScroll(rememberScrollState()),\n        ) {\n\n            val context = LocalContext.current\n            val scope = rememberCoroutineScope()\n            val prefs = APApplication.sharedPreferences\n\n            // clear key\n            if (kPatchReady) {\n                val clearKeyDialogTitle = stringResource(id = R.string.clear_super_key)\n                val clearKeyDialogContent =\n                    stringResource(id = R.string.settings_clear_super_key_dialog)\n                ListItem(\n                    leadingContent = {\n                        Icon(\n                            Icons.Filled.Key, stringResource(id = R.string.super_key)\n                        )\n                    },\n                    headlineContent = { Text(stringResource(id = R.string.clear_super_key)) },\n                    modifier = Modifier.clickable {\n                        clearKeyDialog.showConfirm(\n                            title = clearKeyDialogTitle,\n                            content = clearKeyDialogContent,\n                            markdown = false,\n                        )\n\n                    })\n            }\n\n            // store key local?\n            SwitchItem(\n                icon = Icons.Filled.Key,\n                title = stringResource(id = R.string.settings_donot_store_superkey),\n                summary = stringResource(id = R.string.settings_donot_store_superkey_summary),\n                checked = bSkipStoreSuperKey,\n                onCheckedChange = {\n                    bSkipStoreSuperKey = it\n                    APatchKeyHelper.setShouldSkipStoreSuperKey(bSkipStoreSuperKey)\n                })\n\n            // Global mount\n            if (kPatchReady && aPatchReady) {\n                SwitchItem(\n                    icon = Icons.Filled.Engineering,\n                    title = stringResource(id = R.string.settings_global_namespace_mode),\n                    summary = stringResource(id = R.string.settings_global_namespace_mode_summary),\n                    checked = isGlobalNamespaceEnabled,\n                    onCheckedChange = {\n                        setGlobalNamespaceEnabled(\n                            if (isGlobalNamespaceEnabled) {\n                                \"0\"\n                            } else {\n                                \"1\"\n                            }\n                        )\n                        isGlobalNamespaceEnabled = it\n                    })\n            }\n\n            // WebView Debug\n            if (aPatchReady) {\n                var enableWebDebugging by rememberSaveable {\n                    mutableStateOf(\n                        prefs.getBoolean(\"enable_web_debugging\", false)\n                    )\n                }\n                SwitchItem(\n                    icon = Icons.Filled.DeveloperMode,\n                    title = stringResource(id = R.string.enable_web_debugging),\n                    summary = stringResource(id = R.string.enable_web_debugging_summary),\n                    checked = enableWebDebugging\n                ) {\n                    APApplication.sharedPreferences.edit {\n                        putBoolean(\"enable_web_debugging\", it)\n                    }\n                    enableWebDebugging = it\n                }\n            }\n\n            // Check Update\n            var checkUpdate by rememberSaveable {\n                mutableStateOf(\n                    prefs.getBoolean(\"check_update\", true)\n                )\n            }\n\n            SwitchItem(\n                icon = Icons.Filled.Update,\n                title = stringResource(id = R.string.settings_check_update),\n                summary = stringResource(id = R.string.settings_check_update_summary),\n                checked = checkUpdate\n            ) {\n                prefs.edit { putBoolean(\"check_update\", it) }\n                checkUpdate = it\n            }\n\n            // Night Mode Follow System\n            var nightFollowSystem by rememberSaveable {\n                mutableStateOf(\n                    prefs.getBoolean(\"night_mode_follow_sys\", true)\n                )\n            }\n            SwitchItem(\n                icon = Icons.Filled.InvertColors,\n                title = stringResource(id = R.string.settings_night_mode_follow_sys),\n                summary = stringResource(id = R.string.settings_night_mode_follow_sys_summary),\n                checked = nightFollowSystem\n            ) {\n                prefs.edit { putBoolean(\"night_mode_follow_sys\", it) }\n                nightFollowSystem = it\n                refreshTheme.value = true\n            }\n\n            // Custom Night Theme Switch\n            if (!nightFollowSystem) {\n                var nightThemeEnabled by rememberSaveable {\n                    mutableStateOf(\n                        prefs.getBoolean(\"night_mode_enabled\", false)\n                    )\n                }\n                SwitchItem(\n                    icon = Icons.Filled.DarkMode,\n                    title = stringResource(id = R.string.settings_night_theme_enabled),\n                    checked = nightThemeEnabled\n                ) {\n                    prefs.edit { putBoolean(\"night_mode_enabled\", it) }\n                    nightThemeEnabled = it\n                    refreshTheme.value = true\n                }\n            }\n\n            // System dynamic color theme\n            val isDynamicColorSupport = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S\n            if (isDynamicColorSupport) {\n                var useSystemDynamicColor by rememberSaveable {\n                    mutableStateOf(\n                        prefs.getBoolean(\"use_system_color_theme\", true)\n                    )\n                }\n                SwitchItem(\n                    icon = Icons.Filled.ColorLens,\n                    title = stringResource(id = R.string.settings_use_system_color_theme),\n                    summary = stringResource(id = R.string.settings_use_system_color_theme_summary),\n                    checked = useSystemDynamicColor\n                ) {\n                    prefs.edit { putBoolean(\"use_system_color_theme\", it) }\n                    useSystemDynamicColor = it\n                    refreshTheme.value = true\n                }\n\n                if (!useSystemDynamicColor) {\n                    ListItem(headlineContent = {\n                        Text(text = stringResource(id = R.string.settings_custom_color_theme))\n                    }, modifier = Modifier.clickable {\n                        showThemeChooseDialog.value = true\n                    }, supportingContent = {\n                        val colorMode = prefs.getString(\"custom_color\", \"blue\")\n                        Text(\n                            text = stringResource(colorNameToString(colorMode.toString())),\n                            style = MaterialTheme.typography.bodyMedium,\n                            color = MaterialTheme.colorScheme.outline\n                        )\n                    }, leadingContent = { Icon(Icons.Filled.FormatColorFill, null) })\n\n                }\n            } else {\n                ListItem(headlineContent = {\n                    Text(text = stringResource(id = R.string.settings_custom_color_theme))\n                }, modifier = Modifier.clickable {\n                    showThemeChooseDialog.value = true\n                }, supportingContent = {\n                    val colorMode = prefs.getString(\"custom_color\", \"blue\")\n                    Text(\n                        text = stringResource(colorNameToString(colorMode.toString())),\n                        style = MaterialTheme.typography.bodyMedium,\n                        color = MaterialTheme.colorScheme.outline\n                    )\n                }, leadingContent = { Icon(Icons.Filled.FormatColorFill, null) })\n            }\n\n            // su path\n            if (kPatchReady) {\n                ListItem(\n                    leadingContent = {\n                        Icon(\n                            Icons.Filled.Commit, stringResource(id = R.string.setting_reset_su_path)\n                        )\n                    },\n                    supportingContent = {},\n                    headlineContent = { Text(stringResource(id = R.string.setting_reset_su_path)) },\n                    modifier = Modifier.clickable {\n                        showResetSuPathDialog.value = true\n                    })\n            }\n\n            // language\n            ListItem(headlineContent = {\n                Text(text = stringResource(id = R.string.settings_app_language))\n            }, modifier = Modifier.clickable {\n                showLanguageDialog.value = true\n            }, supportingContent = {\n                Text(text = AppCompatDelegate.getApplicationLocales()[0]?.displayLanguage?.replaceFirstChar {\n                    if (it.isLowerCase()) it.titlecase(\n                        Locale.getDefault()\n                    ) else it.toString()\n                } ?: stringResource(id = R.string.system_default),\n                    style = MaterialTheme.typography.bodyMedium,\n                    color = MaterialTheme.colorScheme.outline)\n            }, leadingContent = { Icon(Icons.Filled.Translate, null) })\n\n            // log\n            ListItem(\n                leadingContent = {\n                    Icon(\n                        Icons.Filled.BugReport, stringResource(id = R.string.send_log)\n                    )\n                },\n                headlineContent = { Text(stringResource(id = R.string.send_log)) },\n                modifier = Modifier.clickable {\n                    showLogBottomSheet = true\n                })\n            if (showLogBottomSheet) {\n                ModalBottomSheet(\n                    onDismissRequest = { showLogBottomSheet = false },\n                    contentWindowInsets = { WindowInsets(0, 0, 0, 0) },\n                    content = {\n                        Row(\n                            modifier = Modifier\n                                .padding(10.dp)\n                                .align(Alignment.CenterHorizontally)\n\n                        ) {\n                            Box {\n                                Column(\n                                    modifier = Modifier\n                                        .padding(16.dp)\n                                        .clickable {\n                                            scope.launch {\n                                                val formatter =\n                                                    DateTimeFormatter.ofPattern(\"yyyy-MM-dd_HH_mm\")\n                                                val current = LocalDateTime.now().format(formatter)\n                                                exportBugreportLauncher.launch(\"APatch_bugreport_${current}.tar.gz\")\n                                                showLogBottomSheet = false\n                                            }\n                                        }\n                                ) {\n                                    Icon(\n                                        Icons.Filled.Save,\n                                        contentDescription = null,\n                                        modifier = Modifier.align(Alignment.CenterHorizontally)\n                                    )\n                                    Text(\n                                        text = stringResource(id = R.string.save_log),\n                                        modifier = Modifier.padding(top = 16.dp),\n                                        textAlign = TextAlign.Center.also {\n                                            LineHeightStyle(\n                                                alignment = LineHeightStyle.Alignment.Center,\n                                                trim = LineHeightStyle.Trim.None\n                                            )\n                                        }\n\n                                    )\n                                }\n\n                            }\n                            Box {\n                                Column(\n                                    modifier = Modifier\n                                        .padding(16.dp)\n                                        .clickable {\n                                            scope.launch {\n                                                val bugreport = loadingDialog.withLoading {\n                                                    withContext(Dispatchers.IO) {\n                                                        getBugreportFile(context)\n                                                    }\n                                                }\n\n                                                val uri: Uri = FileProvider.getUriForFile(\n                                                    context,\n                                                    \"${BuildConfig.APPLICATION_ID}.fileprovider\",\n                                                    bugreport\n                                                )\n\n                                                val shareIntent = Intent(Intent.ACTION_SEND).apply {\n                                                    putExtra(Intent.EXTRA_STREAM, uri)\n                                                    setDataAndType(uri, \"application/gzip\")\n                                                    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)\n                                                }\n\n                                                context.startActivity(\n                                                    Intent.createChooser(\n                                                        shareIntent,\n                                                        context.getString(R.string.send_log)\n                                                    )\n                                                )\n                                                showLogBottomSheet = false\n                                            }\n                                        }) {\n                                    Icon(\n                                        Icons.Filled.Share,\n                                        contentDescription = null,\n                                        modifier = Modifier.align(Alignment.CenterHorizontally)\n                                    )\n                                    Text(\n                                        text = stringResource(id = R.string.send_log),\n                                        modifier = Modifier.padding(top = 16.dp),\n                                        textAlign = TextAlign.Center.also {\n                                            LineHeightStyle(\n                                                alignment = LineHeightStyle.Alignment.Center,\n                                                trim = LineHeightStyle.Trim.None\n                                            )\n                                        }\n\n                                    )\n                                }\n\n                            }\n                        }\n                        NavigationBarsSpacer()\n                    })\n            }\n\n\n        }\n\n    }\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun ThemeChooseDialog(showDialog: MutableState<Boolean>) {\n    val prefs = APApplication.sharedPreferences\n\n    BasicAlertDialog(\n        onDismissRequest = { showDialog.value = false }, properties = DialogProperties(\n            decorFitsSystemWindows = true,\n            usePlatformDefaultWidth = false,\n        )\n    ) {\n        Surface(\n            modifier = Modifier\n                .width(310.dp)\n                .wrapContentHeight(),\n            shape = RoundedCornerShape(30.dp),\n            tonalElevation = AlertDialogDefaults.TonalElevation,\n            color = AlertDialogDefaults.containerColor,\n        ) {\n            LazyColumn {\n                items(colorsList()) {\n                    ListItem(\n                        headlineContent = { Text(text = stringResource(it.nameId)) },\n                        modifier = Modifier.clickable {\n                            showDialog.value = false\n                            prefs.edit { putString(\"custom_color\", it.name) }\n                            refreshTheme.value = true\n                        })\n                }\n\n            }\n\n            val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n            APDialogBlurBehindUtils.setupWindowBlurListener(dialogWindowProvider.window)\n        }\n    }\n\n}\n\nprivate data class APColor(\n    val name: String, @param:StringRes val nameId: Int\n)\n\nprivate fun colorsList(): List<APColor> {\n    return listOf(\n        APColor(\"amber\", R.string.amber_theme),\n        APColor(\"blue_grey\", R.string.blue_grey_theme),\n        APColor(\"blue\", R.string.blue_theme),\n        APColor(\"brown\", R.string.brown_theme),\n        APColor(\"cyan\", R.string.cyan_theme),\n        APColor(\"deep_orange\", R.string.deep_orange_theme),\n        APColor(\"deep_purple\", R.string.deep_purple_theme),\n        APColor(\"green\", R.string.green_theme),\n        APColor(\"indigo\", R.string.indigo_theme),\n        APColor(\"light_blue\", R.string.light_blue_theme),\n        APColor(\"light_green\", R.string.light_green_theme),\n        APColor(\"lime\", R.string.lime_theme),\n        APColor(\"orange\", R.string.orange_theme),\n        APColor(\"pink\", R.string.pink_theme),\n        APColor(\"purple\", R.string.purple_theme),\n        APColor(\"red\", R.string.red_theme),\n        APColor(\"sakura\", R.string.sakura_theme),\n        APColor(\"teal\", R.string.teal_theme),\n        APColor(\"yellow\", R.string.yellow_theme),\n    )\n}\n\n@Composable\nprivate fun colorNameToString(colorName: String): Int {\n    return colorsList().find { it.name == colorName }?.nameId ?: R.string.blue_theme\n}\n\nval suPathChecked: (path: String) -> Boolean = {\n    it.startsWith(\"/\") && it.trim().length > 1\n}\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun ResetSUPathDialog(showDialog: MutableState<Boolean>) {\n    val context = LocalContext.current\n    var suPath by remember { mutableStateOf(Natives.suPath()) }\n    BasicAlertDialog(\n        onDismissRequest = { showDialog.value = false }, properties = DialogProperties(\n            decorFitsSystemWindows = true,\n            usePlatformDefaultWidth = false,\n        )\n    ) {\n        Surface(\n            modifier = Modifier\n                .width(310.dp)\n                .wrapContentHeight(),\n            shape = RoundedCornerShape(30.dp),\n            tonalElevation = AlertDialogDefaults.TonalElevation,\n            color = AlertDialogDefaults.containerColor,\n        ) {\n            Column(modifier = Modifier.padding(PaddingValues(all = 24.dp))) {\n                Box(\n                    Modifier\n                        .padding(PaddingValues(bottom = 16.dp))\n                        .align(Alignment.Start)\n                ) {\n                    Text(\n                        text = stringResource(id = R.string.setting_reset_su_path),\n                        style = MaterialTheme.typography.headlineSmall\n                    )\n                }\n                Box(\n                    Modifier\n                        .weight(weight = 1f, fill = false)\n                        .padding(PaddingValues(bottom = 12.dp))\n                        .align(Alignment.Start)\n                ) {\n                    OutlinedTextField(\n                        value = suPath,\n                        onValueChange = {\n                            suPath = it\n                        },\n                        label = { Text(stringResource(id = R.string.setting_reset_su_new_path)) },\n                        visualTransformation = VisualTransformation.None,\n                    )\n                }\n\n                Row(\n                    modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End\n                ) {\n                    TextButton(onClick = { showDialog.value = false }) {\n\n                        Text(stringResource(id = android.R.string.cancel))\n                    }\n\n                    Button(enabled = suPathChecked(suPath), onClick = {\n                        showDialog.value = false\n                        val success = Natives.resetSuPath(suPath)\n                        Toast.makeText(\n                            context,\n                            if (success) R.string.success else R.string.failure,\n                            Toast.LENGTH_SHORT\n                        ).show()\n                        rootShellForResult(\"echo $suPath > ${APApplication.SU_PATH_FILE}\")\n                    }) {\n                        Text(stringResource(id = android.R.string.ok))\n                    }\n                }\n            }\n            val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n            APDialogBlurBehindUtils.setupWindowBlurListener(dialogWindowProvider.window)\n        }\n    }\n}\n\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Composable\nfun LanguageDialog(showLanguageDialog: MutableState<Boolean>) {\n\n    val languages = stringArrayResource(id = R.array.languages)\n    val languagesValues = stringArrayResource(id = R.array.languages_values)\n\n    if (showLanguageDialog.value) {\n        BasicAlertDialog(\n            onDismissRequest = { showLanguageDialog.value = false }\n        ) {\n            Surface(\n                modifier = Modifier\n                    .width(150.dp)\n                    .wrapContentHeight(),\n                shape = RoundedCornerShape(28.dp),\n                tonalElevation = AlertDialogDefaults.TonalElevation,\n                color = AlertDialogDefaults.containerColor,\n            ) {\n                LazyColumn {\n                    itemsIndexed(languages) { index, item ->\n                        ListItem(\n                            headlineContent = { Text(item) },\n                            modifier = Modifier.clickable {\n                                showLanguageDialog.value = false\n                                if (index == 0) {\n                                    AppCompatDelegate.setApplicationLocales(\n                                        LocaleListCompat.getEmptyLocaleList()\n                                    )\n                                } else {\n                                    AppCompatDelegate.setApplicationLocales(\n                                        LocaleListCompat.forLanguageTags(\n                                            languagesValues[index]\n                                        )\n                                    )\n                                }\n                            }\n                        )\n                    }\n                }\n            }\n            val dialogWindowProvider = LocalView.current.parent as DialogWindowProvider\n            APDialogBlurBehindUtils.setupWindowBlurListener(dialogWindowProvider.window)\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/screen/SuperUser.kt",
    "content": "package me.bmax.apatch.ui.screen\n\nimport androidx.compose.animation.AnimatedVisibility\nimport androidx.compose.foundation.background\nimport androidx.compose.foundation.clickable\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Column\nimport androidx.compose.foundation.layout.ExperimentalLayoutApi\nimport androidx.compose.foundation.layout.FlowRow\nimport androidx.compose.foundation.layout.fillMaxSize\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.compose.foundation.layout.height\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.foundation.layout.width\nimport androidx.compose.foundation.lazy.LazyColumn\nimport androidx.compose.foundation.lazy.items\nimport androidx.compose.foundation.shape.RoundedCornerShape\nimport androidx.compose.material.icons.Icons\nimport androidx.compose.material.icons.filled.MoreVert\nimport androidx.compose.material.icons.filled.Security\nimport androidx.compose.material3.DropdownMenu\nimport androidx.compose.material3.DropdownMenuItem\nimport androidx.compose.material3.ExperimentalMaterial3Api\nimport androidx.compose.material3.Icon\nimport androidx.compose.material3.IconButton\nimport androidx.compose.material3.ListItem\nimport androidx.compose.material3.Scaffold\nimport androidx.compose.material3.Switch\nimport androidx.compose.material3.Text\nimport androidx.compose.material3.pulltorefresh.PullToRefreshBox\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableIntStateOf\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.rememberCoroutineScope\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.compose.ui.res.stringResource\nimport androidx.compose.ui.text.TextStyle\nimport androidx.compose.ui.unit.dp\nimport androidx.compose.ui.unit.sp\nimport androidx.lifecycle.viewmodel.compose.viewModel\nimport coil.compose.AsyncImage\nimport coil.request.ImageRequest\nimport com.ramcosta.composedestinations.annotation.Destination\nimport com.ramcosta.composedestinations.annotation.RootGraph\nimport kotlinx.coroutines.launch\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.Natives\nimport me.bmax.apatch.R\nimport me.bmax.apatch.apApp\nimport me.bmax.apatch.ui.component.ProvideMenuShape\nimport me.bmax.apatch.ui.component.SearchAppBar\nimport me.bmax.apatch.ui.component.SwitchItem\nimport me.bmax.apatch.ui.component.pinnedScrollBehavior\nimport me.bmax.apatch.ui.viewmodel.SuperUserViewModel\nimport me.bmax.apatch.util.PkgConfig\n\n\n@OptIn(ExperimentalMaterial3Api::class)\n@Destination<RootGraph>\n@Composable\nfun SuperUserScreen() {\n    val viewModel = viewModel<SuperUserViewModel>()\n    val scrollBehavior = pinnedScrollBehavior()\n    val scope = rememberCoroutineScope()\n\n    LaunchedEffect(Unit) {\n        if (viewModel.appList.isEmpty()) {\n            viewModel.fetchAppList()\n        }\n    }\n\n    Scaffold(\n        topBar = {\n            SearchAppBar(\n                searchText = viewModel.search,\n                onSearchTextChange = { viewModel.search = it },\n                searchBarPlaceHolderText = stringResource(R.string.search_apps),\n                dropdownContent = {\n                    var showDropdown by remember { mutableStateOf(false) }\n\n                    IconButton(\n                        onClick = { showDropdown = true },\n                    ) {\n                        Icon(\n                            imageVector = Icons.Filled.MoreVert,\n                            contentDescription = stringResource(id = R.string.settings)\n                        )\n\n                        ProvideMenuShape(RoundedCornerShape(10.dp)) {\n                            DropdownMenu(expanded = showDropdown, onDismissRequest = {\n                                showDropdown = false\n                            }) {\n                                DropdownMenuItem(text = {\n                                    Text(stringResource(R.string.su_refresh))\n                                }, onClick = {\n                                    scope.launch {\n                                        viewModel.fetchAppList()\n                                    }\n                                    showDropdown = false\n                                })\n\n                                DropdownMenuItem(text = {\n                                    Text(\n                                        if (viewModel.showSystemApps) {\n                                            stringResource(R.string.su_hide_system_apps)\n                                        } else {\n                                            stringResource(R.string.su_show_system_apps)\n                                        }\n                                    )\n                                }, onClick = {\n                                    viewModel.showSystemApps = !viewModel.showSystemApps\n                                    showDropdown = false\n                                })\n                            }\n                        }\n                    }\n                }\n            )\n        },\n    ) { innerPadding ->\n\n        PullToRefreshBox(\n            modifier = Modifier.padding(innerPadding),\n            onRefresh = { scope.launch { viewModel.fetchAppList() } },\n            isRefreshing = viewModel.isRefreshing\n        ) {\n            LazyColumn(Modifier.fillMaxSize()) {\n                items(viewModel.appList.filter { it.packageName != apApp.packageName }, key = { it.packageName + it.uid }) { app ->\n                    AppItem(app)\n                }\n            }\n        }\n    }\n}\n\n@OptIn(ExperimentalLayoutApi::class)\n@Composable\nprivate fun AppItem(\n    app: SuperUserViewModel.AppInfo,\n) {\n    val config = app.config\n    var showEditProfile by remember { mutableStateOf(false) }\n    var rootGranted by remember { mutableStateOf(config.allow != 0) }\n    var excludeApp by remember { mutableIntStateOf(config.exclude) }\n\n    ListItem(\n        modifier = Modifier.clickable(onClick = {\n            if (!rootGranted) {\n                showEditProfile = !showEditProfile\n            } else {\n                rootGranted = false\n                config.allow = 0\n                Natives.revokeSu(app.uid)\n                PkgConfig.changeConfig(config)\n            }\n        }),\n        headlineContent = { Text(app.label) },\n        leadingContent = {\n            AsyncImage(\n                model = ImageRequest.Builder(LocalContext.current).data(app.packageInfo)\n                    .crossfade(true).build(),\n                contentDescription = app.label,\n                modifier = Modifier\n                    .padding(4.dp)\n                    .width(48.dp)\n                    .height(48.dp)\n            )\n        },\n        supportingContent = {\n\n            Column {\n                Text(app.packageName)\n                FlowRow {\n\n                    if (excludeApp == 1) {\n                        LabelText(label = stringResource(id = R.string.su_pkg_excluded_label))\n                    }\n                    if (rootGranted) {\n                        LabelText(label = config.profile.uid.toString())\n                        LabelText(label = config.profile.toUid.toString())\n                        LabelText(\n                            label = when {\n                                // todo: valid scontext ?\n                                config.profile.scontext.isNotEmpty() -> config.profile.scontext\n                                else -> stringResource(id = R.string.su_selinux_via_hook)\n                            }\n                        )\n                    }\n                }\n            }\n        },\n        trailingContent = {\n            Switch(checked = rootGranted, onCheckedChange = {\n                rootGranted = !rootGranted\n                if (rootGranted) {\n                    excludeApp = 0\n                    config.allow = 1\n                    config.exclude = 0\n                    config.profile.scontext = APApplication.MAGISK_SCONTEXT\n                } else {\n                    config.allow = 0\n                }\n                config.profile.uid = app.uid\n                PkgConfig.changeConfig(config)\n                if (config.allow == 1) {\n                    Natives.grantSu(app.uid, 0, config.profile.scontext)\n                    Natives.setUidExclude(app.uid, 0)\n                } else {\n                    Natives.revokeSu(app.uid)\n                }\n            })\n        },\n    )\n\n    AnimatedVisibility(\n        visible = showEditProfile && !rootGranted,\n        modifier = Modifier\n            .fillMaxWidth()\n            .padding(horizontal = 24.dp)\n    ) {\n        SwitchItem(\n            icon = Icons.Filled.Security,\n            title = stringResource(id = R.string.su_pkg_excluded_setting_title),\n            summary = stringResource(id = R.string.su_pkg_excluded_setting_summary),\n            checked = excludeApp == 1,\n            onCheckedChange = {\n                if (it) {\n                    excludeApp = 1\n                    config.allow = 0\n                    config.profile.scontext = APApplication.DEFAULT_SCONTEXT\n                    Natives.revokeSu(app.uid)\n                } else {\n                    excludeApp = 0\n                }\n                config.exclude = excludeApp\n                config.profile.uid = app.uid\n                PkgConfig.changeConfig(config)\n                Natives.setUidExclude(app.uid, excludeApp)\n            },\n        )\n    }\n}\n\n@Composable\nfun LabelText(label: String) {\n    Box(\n        modifier = Modifier\n            .padding(top = 4.dp, end = 4.dp)\n            .background(\n                Color.Black, shape = RoundedCornerShape(4.dp)\n            )\n    ) {\n        Text(\n            text = label,\n            modifier = Modifier.padding(vertical = 2.dp, horizontal = 5.dp),\n            style = TextStyle(\n                fontSize = 8.sp,\n                color = Color.White,\n            )\n        )\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/AmberTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF785900)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFFFDF9E)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF261A00)\nprivate val md_theme_light_secondary = Color(0xFF6B5D3F)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFF5E0BB)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF241A04)\nprivate val md_theme_light_tertiary = Color(0xFF4A6547)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFCCEBC4)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF072109)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF1E1B16)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF1E1B16)\nprivate val md_theme_light_surfaceVariant = Color(0xFFEDE1CF)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF4D4639)\nprivate val md_theme_light_outline = Color(0xFF7F7667)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF7EFE7)\nprivate val md_theme_light_inverseSurface = Color(0xFF33302A)\nprivate val md_theme_light_inversePrimary = Color(0xFFFABD00)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF785900)\nprivate val md_theme_light_outlineVariant = Color(0xFFD0C5B4)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFFABD00)\nprivate val md_theme_dark_onPrimary = Color(0xFF3F2E00)\nprivate val md_theme_dark_primaryContainer = Color(0xFF5B4300)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFFFDF9E)\nprivate val md_theme_dark_secondary = Color(0xFFD8C4A0)\nprivate val md_theme_dark_onSecondary = Color(0xFF3A2F15)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF52452A)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFF5E0BB)\nprivate val md_theme_dark_tertiary = Color(0xFFB0CFAA)\nprivate val md_theme_dark_onTertiary = Color(0xFF1D361C)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF334D31)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFCCEBC4)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF1E1B16)\nprivate val md_theme_dark_onBackground = Color(0xFFE9E1D8)\nprivate val md_theme_dark_surface = Color(0xFF1E1B16)\nprivate val md_theme_dark_onSurface = Color(0xFFE9E1D8)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF4D4639)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFD0C5B4)\nprivate val md_theme_dark_outline = Color(0xFF998F80)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF1E1B16)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE9E1D8)\nprivate val md_theme_dark_inversePrimary = Color(0xFF785900)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFFABD00)\nprivate val md_theme_dark_outlineVariant = Color(0xFF4D4639)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightAmberTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkAmberTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/BlueGreyTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF00668A)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFC4E7FF)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF001E2C)\nprivate val md_theme_light_secondary = Color(0xFF4E616D)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFD1E5F4)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF0A1E28)\nprivate val md_theme_light_tertiary = Color(0xFF605A7D)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFE6DEFF)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF1D1736)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFBFCFF)\nprivate val md_theme_light_onBackground = Color(0xFF191C1E)\nprivate val md_theme_light_surface = Color(0xFFFBFCFF)\nprivate val md_theme_light_onSurface = Color(0xFF191C1E)\nprivate val md_theme_light_surfaceVariant = Color(0xFFDCE3E9)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF41484D)\nprivate val md_theme_light_outline = Color(0xFF71787D)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF0F1F3)\nprivate val md_theme_light_inverseSurface = Color(0xFF2E3133)\nprivate val md_theme_light_inversePrimary = Color(0xFF7BD0FF)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF00668A)\nprivate val md_theme_light_outlineVariant = Color(0xFFC0C7CD)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFF7BD0FF)\nprivate val md_theme_dark_onPrimary = Color(0xFF003549)\nprivate val md_theme_dark_primaryContainer = Color(0xFF004C69)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFC4E7FF)\nprivate val md_theme_dark_secondary = Color(0xFFB5C9D7)\nprivate val md_theme_dark_onSecondary = Color(0xFF20333E)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF374955)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFD1E5F4)\nprivate val md_theme_dark_tertiary = Color(0xFFCAC1E9)\nprivate val md_theme_dark_onTertiary = Color(0xFF322C4C)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF484264)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFE6DEFF)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF191C1E)\nprivate val md_theme_dark_onBackground = Color(0xFFE1E2E5)\nprivate val md_theme_dark_surface = Color(0xFF191C1E)\nprivate val md_theme_dark_onSurface = Color(0xFFE1E2E5)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF41484D)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFC0C7CD)\nprivate val md_theme_dark_outline = Color(0xFF8B9297)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF191C1E)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE1E2E5)\nprivate val md_theme_dark_inversePrimary = Color(0xFF00668A)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFF7BD0FF)\nprivate val md_theme_dark_outlineVariant = Color(0xFF41484D)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightBlueGreyTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkBlueGreyTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/BlueTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF0061A4)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFD1E4FF)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF001D36)\nprivate val md_theme_light_secondary = Color(0xFF535F70)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFD7E3F7)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF101C2B)\nprivate val md_theme_light_tertiary = Color(0xFF6B5778)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFF2DAFF)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF251431)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFDFCFF)\nprivate val md_theme_light_onBackground = Color(0xFF1A1C1E)\nprivate val md_theme_light_surface = Color(0xFFFDFCFF)\nprivate val md_theme_light_onSurface = Color(0xFF1A1C1E)\nprivate val md_theme_light_surfaceVariant = Color(0xFFDFE2EB)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF43474E)\nprivate val md_theme_light_outline = Color(0xFF73777F)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF1F0F4)\nprivate val md_theme_light_inverseSurface = Color(0xFF2F3033)\nprivate val md_theme_light_inversePrimary = Color(0xFF9ECAFF)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF0061A4)\nprivate val md_theme_light_outlineVariant = Color(0xFFC3C7CF)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFF9ECAFF)\nprivate val md_theme_dark_onPrimary = Color(0xFF003258)\nprivate val md_theme_dark_primaryContainer = Color(0xFF00497D)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFD1E4FF)\nprivate val md_theme_dark_secondary = Color(0xFFBBC7DB)\nprivate val md_theme_dark_onSecondary = Color(0xFF253140)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF3B4858)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFD7E3F7)\nprivate val md_theme_dark_tertiary = Color(0xFFD6BEE4)\nprivate val md_theme_dark_onTertiary = Color(0xFF3B2948)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF523F5F)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFF2DAFF)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF1A1C1E)\nprivate val md_theme_dark_onBackground = Color(0xFFE2E2E6)\nprivate val md_theme_dark_surface = Color(0xFF1A1C1E)\nprivate val md_theme_dark_onSurface = Color(0xFFE2E2E6)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF43474E)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFC3C7CF)\nprivate val md_theme_dark_outline = Color(0xFF8D9199)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF1A1C1E)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE2E2E6)\nprivate val md_theme_dark_inversePrimary = Color(0xFF0061A4)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFF9ECAFF)\nprivate val md_theme_dark_outlineVariant = Color(0xFF43474E)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\n\nval LightBlueTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkBlueTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/BrownTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF9A4522)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFFFDBCF)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF380D00)\nprivate val md_theme_light_secondary = Color(0xFF77574C)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFFFDBCF)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF2C160D)\nprivate val md_theme_light_tertiary = Color(0xFF695E2F)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFF2E2A8)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF211B00)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF201A18)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF201A18)\nprivate val md_theme_light_surfaceVariant = Color(0xFFF5DED6)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF53433E)\nprivate val md_theme_light_outline = Color(0xFF85736D)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFFBEEEA)\nprivate val md_theme_light_inverseSurface = Color(0xFF362F2C)\nprivate val md_theme_light_inversePrimary = Color(0xFFFFB59A)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF9A4522)\nprivate val md_theme_light_outlineVariant = Color(0xFFD8C2BB)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFFFB59A)\nprivate val md_theme_dark_onPrimary = Color(0xFF5B1B00)\nprivate val md_theme_dark_primaryContainer = Color(0xFF7B2E0D)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFFFDBCF)\nprivate val md_theme_dark_secondary = Color(0xFFE7BEAF)\nprivate val md_theme_dark_onSecondary = Color(0xFF442A20)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF5D4035)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFFFDBCF)\nprivate val md_theme_dark_tertiary = Color(0xFFD5C68E)\nprivate val md_theme_dark_onTertiary = Color(0xFF393005)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF50471A)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFF2E2A8)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF201A18)\nprivate val md_theme_dark_onBackground = Color(0xFFEDE0DC)\nprivate val md_theme_dark_surface = Color(0xFF201A18)\nprivate val md_theme_dark_onSurface = Color(0xFFEDE0DC)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF53433E)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFD8C2BB)\nprivate val md_theme_dark_outline = Color(0xFFA08D86)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF201A18)\nprivate val md_theme_dark_inverseSurface = Color(0xFFEDE0DC)\nprivate val md_theme_dark_inversePrimary = Color(0xFF9A4522)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFFFB59A)\nprivate val md_theme_dark_outlineVariant = Color(0xFF53433E)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightBrownTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkBrownTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/CyanTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF006876)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFA1EFFF)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF001F25)\nprivate val md_theme_light_secondary = Color(0xFF4A6268)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFCDE7ED)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF051F23)\nprivate val md_theme_light_tertiary = Color(0xFF545D7E)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFDBE1FF)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF101A37)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFBFCFD)\nprivate val md_theme_light_onBackground = Color(0xFF191C1D)\nprivate val md_theme_light_surface = Color(0xFFFBFCFD)\nprivate val md_theme_light_onSurface = Color(0xFF191C1D)\nprivate val md_theme_light_surfaceVariant = Color(0xFFDBE4E6)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF3F484A)\nprivate val md_theme_light_outline = Color(0xFF6F797B)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFEFF1F2)\nprivate val md_theme_light_inverseSurface = Color(0xFF2E3132)\nprivate val md_theme_light_inversePrimary = Color(0xFF44D8F1)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF006876)\nprivate val md_theme_light_outlineVariant = Color(0xFFBFC8CA)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFF44D8F1)\nprivate val md_theme_dark_onPrimary = Color(0xFF00363E)\nprivate val md_theme_dark_primaryContainer = Color(0xFF004E59)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFA1EFFF)\nprivate val md_theme_dark_secondary = Color(0xFFB1CBD1)\nprivate val md_theme_dark_onSecondary = Color(0xFF1C3439)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF334A50)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFCDE7ED)\nprivate val md_theme_dark_tertiary = Color(0xFFBCC5EB)\nprivate val md_theme_dark_onTertiary = Color(0xFF262F4D)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF3C4665)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFDBE1FF)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF191C1D)\nprivate val md_theme_dark_onBackground = Color(0xFFE1E3E3)\nprivate val md_theme_dark_surface = Color(0xFF191C1D)\nprivate val md_theme_dark_onSurface = Color(0xFFE1E3E3)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF3F484A)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFBFC8CA)\nprivate val md_theme_dark_outline = Color(0xFF899295)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF191C1D)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE1E3E3)\nprivate val md_theme_dark_inversePrimary = Color(0xFF006876)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFF44D8F1)\nprivate val md_theme_dark_outlineVariant = Color(0xFF3F484A)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightCyanTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkCyanTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/DeepOrangeTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFFB02F00)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFFFDBD1)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF3B0900)\nprivate val md_theme_light_secondary = Color(0xFF77574E)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFFFDBD1)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF2C150F)\nprivate val md_theme_light_tertiary = Color(0xFF6C5D2F)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFF5E1A7)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF231B00)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF201A18)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF201A18)\nprivate val md_theme_light_surfaceVariant = Color(0xFFF5DED8)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF53433F)\nprivate val md_theme_light_outline = Color(0xFF85736E)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFFBEEEB)\nprivate val md_theme_light_inverseSurface = Color(0xFF362F2D)\nprivate val md_theme_light_inversePrimary = Color(0xFFFFB5A0)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFFB02F00)\nprivate val md_theme_light_outlineVariant = Color(0xFFD8C2BC)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFFFB5A0)\nprivate val md_theme_dark_onPrimary = Color(0xFF5F1500)\nprivate val md_theme_dark_primaryContainer = Color(0xFF862200)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFFFDBD1)\nprivate val md_theme_dark_secondary = Color(0xFFE7BDB2)\nprivate val md_theme_dark_onSecondary = Color(0xFF442A22)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF5D4037)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFFFDBD1)\nprivate val md_theme_dark_tertiary = Color(0xFFD8C58D)\nprivate val md_theme_dark_onTertiary = Color(0xFF3B2F05)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF534619)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFF5E1A7)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF201A18)\nprivate val md_theme_dark_onBackground = Color(0xFFEDE0DC)\nprivate val md_theme_dark_surface = Color(0xFF201A18)\nprivate val md_theme_dark_onSurface = Color(0xFFEDE0DC)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF53433F)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFD8C2BC)\nprivate val md_theme_dark_outline = Color(0xFFA08C87)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF201A18)\nprivate val md_theme_dark_inverseSurface = Color(0xFFEDE0DC)\nprivate val md_theme_dark_inversePrimary = Color(0xFFB02F00)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFFFB5A0)\nprivate val md_theme_dark_outlineVariant = Color(0xFF53433F)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\n\nval LightDeepOrangeTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkDeepOrangeTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/DeepPurpleTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF6F43C0)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFEBDDFF)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF250059)\nprivate val md_theme_light_secondary = Color(0xFF635B70)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFE9DEF8)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF1F182B)\nprivate val md_theme_light_tertiary = Color(0xFF7E525D)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFFFD9E1)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF31101B)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF1D1B1E)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF1D1B1E)\nprivate val md_theme_light_surfaceVariant = Color(0xFFE7E0EB)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF49454E)\nprivate val md_theme_light_outline = Color(0xFF7A757F)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF5EFF4)\nprivate val md_theme_light_inverseSurface = Color(0xFF323033)\nprivate val md_theme_light_inversePrimary = Color(0xFFD3BBFF)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF6F43C0)\nprivate val md_theme_light_outlineVariant = Color(0xFFCBC4CF)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFD3BBFF)\nprivate val md_theme_dark_onPrimary = Color(0xFF3F008D)\nprivate val md_theme_dark_primaryContainer = Color(0xFF5727A6)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFEBDDFF)\nprivate val md_theme_dark_secondary = Color(0xFFCDC2DB)\nprivate val md_theme_dark_onSecondary = Color(0xFF342D40)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF4B4358)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFE9DEF8)\nprivate val md_theme_dark_tertiary = Color(0xFFF0B7C5)\nprivate val md_theme_dark_onTertiary = Color(0xFF4A2530)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF643B46)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFFFD9E1)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF1D1B1E)\nprivate val md_theme_dark_onBackground = Color(0xFFE6E1E6)\nprivate val md_theme_dark_surface = Color(0xFF1D1B1E)\nprivate val md_theme_dark_onSurface = Color(0xFFE6E1E6)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF49454E)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFCBC4CF)\nprivate val md_theme_dark_outline = Color(0xFF948F99)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF1D1B1E)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE6E1E6)\nprivate val md_theme_dark_inversePrimary = Color(0xFF6F43C0)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFD3BBFF)\nprivate val md_theme_dark_outlineVariant = Color(0xFF49454E)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightDeepPurpleTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkDeepPurpleTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/GreenTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF006E1A)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFF96F990)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF002203)\nprivate val md_theme_light_secondary = Color(0xFF53634F)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFD6E8CE)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF111F0F)\nprivate val md_theme_light_tertiary = Color(0xFF38656A)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFBCEBF0)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF002023)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFCFDF6)\nprivate val md_theme_light_onBackground = Color(0xFF1A1C19)\nprivate val md_theme_light_surface = Color(0xFFFCFDF6)\nprivate val md_theme_light_onSurface = Color(0xFF1A1C19)\nprivate val md_theme_light_surfaceVariant = Color(0xFFDEE5D8)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF424940)\nprivate val md_theme_light_outline = Color(0xFF72796F)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF1F1EB)\nprivate val md_theme_light_inverseSurface = Color(0xFF2F312D)\nprivate val md_theme_light_inversePrimary = Color(0xFF7ADC77)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF006E1A)\nprivate val md_theme_light_outlineVariant = Color(0xFFC2C8BD)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFF7ADC77)\nprivate val md_theme_dark_onPrimary = Color(0xFF003909)\nprivate val md_theme_dark_primaryContainer = Color(0xFF005311)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFF96F990)\nprivate val md_theme_dark_secondary = Color(0xFFBACCB3)\nprivate val md_theme_dark_onSecondary = Color(0xFF253423)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF3B4B38)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFD6E8CE)\nprivate val md_theme_dark_tertiary = Color(0xFFA0CFD4)\nprivate val md_theme_dark_onTertiary = Color(0xFF00363B)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF1E4D52)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFBCEBF0)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF1A1C19)\nprivate val md_theme_dark_onBackground = Color(0xFFE2E3DD)\nprivate val md_theme_dark_surface = Color(0xFF1A1C19)\nprivate val md_theme_dark_onSurface = Color(0xFFE2E3DD)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF424940)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFC2C8BD)\nprivate val md_theme_dark_outline = Color(0xFF8C9388)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF1A1C19)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE2E3DD)\nprivate val md_theme_dark_inversePrimary = Color(0xFF006E1A)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFF7ADC77)\nprivate val md_theme_dark_outlineVariant = Color(0xFF424940)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightGreenTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkGreenTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/IndigoTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF4355B9)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFDEE0FF)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF00105C)\nprivate val md_theme_light_secondary = Color(0xFF5B5D72)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFE0E1F9)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF181A2C)\nprivate val md_theme_light_tertiary = Color(0xFF77536D)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFFFD7F1)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF2D1228)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFEFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF1B1B1F)\nprivate val md_theme_light_surface = Color(0xFFFEFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF1B1B1F)\nprivate val md_theme_light_surfaceVariant = Color(0xFFE3E1EC)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF46464F)\nprivate val md_theme_light_outline = Color(0xFF767680)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF3F0F4)\nprivate val md_theme_light_inverseSurface = Color(0xFF303034)\nprivate val md_theme_light_inversePrimary = Color(0xFFBAC3FF)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF4355B9)\nprivate val md_theme_light_outlineVariant = Color(0xFFC7C5D0)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFBAC3FF)\nprivate val md_theme_dark_onPrimary = Color(0xFF08218A)\nprivate val md_theme_dark_primaryContainer = Color(0xFF293CA0)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFDEE0FF)\nprivate val md_theme_dark_secondary = Color(0xFFC3C5DD)\nprivate val md_theme_dark_onSecondary = Color(0xFF2D2F42)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF434659)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFE0E1F9)\nprivate val md_theme_dark_tertiary = Color(0xFFE6BAD7)\nprivate val md_theme_dark_onTertiary = Color(0xFF44263D)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF5D3C55)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFFFD7F1)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF1B1B1F)\nprivate val md_theme_dark_onBackground = Color(0xFFE4E1E6)\nprivate val md_theme_dark_surface = Color(0xFF1B1B1F)\nprivate val md_theme_dark_onSurface = Color(0xFFE4E1E6)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF46464F)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFC7C5D0)\nprivate val md_theme_dark_outline = Color(0xFF90909A)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF1B1B1F)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE4E1E6)\nprivate val md_theme_dark_inversePrimary = Color(0xFF4355B9)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFBAC3FF)\nprivate val md_theme_dark_outlineVariant = Color(0xFF46464F)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightIndigoTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkIndigoTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/LightBlueTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF006493)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFCAE6FF)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF001E30)\nprivate val md_theme_light_secondary = Color(0xFF50606E)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFD3E5F5)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF0C1D29)\nprivate val md_theme_light_tertiary = Color(0xFF65587B)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFEBDDFF)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF201634)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFCFCFF)\nprivate val md_theme_light_onBackground = Color(0xFF1A1C1E)\nprivate val md_theme_light_surface = Color(0xFFFCFCFF)\nprivate val md_theme_light_onSurface = Color(0xFF1A1C1E)\nprivate val md_theme_light_surfaceVariant = Color(0xFFDDE3EA)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF41474D)\nprivate val md_theme_light_outline = Color(0xFF72787E)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF0F0F3)\nprivate val md_theme_light_inverseSurface = Color(0xFF2E3133)\nprivate val md_theme_light_inversePrimary = Color(0xFF8DCDFF)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF006493)\nprivate val md_theme_light_outlineVariant = Color(0xFFC1C7CE)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFF8DCDFF)\nprivate val md_theme_dark_onPrimary = Color(0xFF00344F)\nprivate val md_theme_dark_primaryContainer = Color(0xFF004B70)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFCAE6FF)\nprivate val md_theme_dark_secondary = Color(0xFFB7C9D9)\nprivate val md_theme_dark_onSecondary = Color(0xFF22323F)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF384956)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFD3E5F5)\nprivate val md_theme_dark_tertiary = Color(0xFFCFC0E8)\nprivate val md_theme_dark_onTertiary = Color(0xFF362B4B)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF4D4162)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFEBDDFF)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF1A1C1E)\nprivate val md_theme_dark_onBackground = Color(0xFFE2E2E5)\nprivate val md_theme_dark_surface = Color(0xFF1A1C1E)\nprivate val md_theme_dark_onSurface = Color(0xFFE2E2E5)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF41474D)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFC1C7CE)\nprivate val md_theme_dark_outline = Color(0xFF8B9198)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF1A1C1E)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE2E2E5)\nprivate val md_theme_dark_inversePrimary = Color(0xFF006493)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFF8DCDFF)\nprivate val md_theme_dark_outlineVariant = Color(0xFF41474D)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\n\nval LightLightBlueTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkLightBlueTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/LightGreenTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF006C48)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFF8DF7C2)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF002113)\nprivate val md_theme_light_secondary = Color(0xFF4D6356)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFD0E8D8)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF0A1F15)\nprivate val md_theme_light_tertiary = Color(0xFF3C6472)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFC0E9FA)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF001F28)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFBFDF8)\nprivate val md_theme_light_onBackground = Color(0xFF191C1A)\nprivate val md_theme_light_surface = Color(0xFFFBFDF8)\nprivate val md_theme_light_onSurface = Color(0xFF191C1A)\nprivate val md_theme_light_surfaceVariant = Color(0xFFDCE5DD)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF404943)\nprivate val md_theme_light_outline = Color(0xFF707973)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFEFF1ED)\nprivate val md_theme_light_inverseSurface = Color(0xFF2E312F)\nprivate val md_theme_light_inversePrimary = Color(0xFF70DBA7)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF006C48)\nprivate val md_theme_light_outlineVariant = Color(0xFFC0C9C1)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFF70DBA7)\nprivate val md_theme_dark_onPrimary = Color(0xFF003824)\nprivate val md_theme_dark_primaryContainer = Color(0xFF005235)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFF8DF7C2)\nprivate val md_theme_dark_secondary = Color(0xFFB4CCBC)\nprivate val md_theme_dark_onSecondary = Color(0xFF20352A)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF364B3F)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFD0E8D8)\nprivate val md_theme_dark_tertiary = Color(0xFFA4CDDE)\nprivate val md_theme_dark_onTertiary = Color(0xFF063543)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF234C5A)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFC0E9FA)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF191C1A)\nprivate val md_theme_dark_onBackground = Color(0xFFE1E3DF)\nprivate val md_theme_dark_surface = Color(0xFF191C1A)\nprivate val md_theme_dark_onSurface = Color(0xFFE1E3DF)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF404943)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFC0C9C1)\nprivate val md_theme_dark_outline = Color(0xFF8A938C)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF191C1A)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE1E3DF)\nprivate val md_theme_dark_inversePrimary = Color(0xFF006C48)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFF70DBA7)\nprivate val md_theme_dark_outlineVariant = Color(0xFF404943)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightLightGreenTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkLightGreenTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/LimeTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF5B6300)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFDDED49)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF1A1D00)\nprivate val md_theme_light_secondary = Color(0xFF5E6044)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFE4E5C1)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF1B1D07)\nprivate val md_theme_light_tertiary = Color(0xFF3C665A)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFBEECDC)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF002019)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFEFFD8)\nprivate val md_theme_light_onBackground = Color(0xFF1C1C17)\nprivate val md_theme_light_surface = Color(0xFFFEFFD8)\nprivate val md_theme_light_onSurface = Color(0xFF1C1C17)\nprivate val md_theme_light_surfaceVariant = Color(0xFFE5E3D2)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF47483B)\nprivate val md_theme_light_outline = Color(0xFF787869)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF3F1E8)\nprivate val md_theme_light_inverseSurface = Color(0xFF31312B)\nprivate val md_theme_light_inversePrimary = Color(0xFFC1D02C)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF5B6300)\nprivate val md_theme_light_outlineVariant = Color(0xFFC8C7B7)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFC1D02C)\nprivate val md_theme_dark_onPrimary = Color(0xFF2F3300)\nprivate val md_theme_dark_primaryContainer = Color(0xFF444B00)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFDDED49)\nprivate val md_theme_dark_secondary = Color(0xFFC7C9A6)\nprivate val md_theme_dark_onSecondary = Color(0xFF30321A)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF46492E)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFE4E5C1)\nprivate val md_theme_dark_tertiary = Color(0xFFA2D0C1)\nprivate val md_theme_dark_onTertiary = Color(0xFF07372D)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF234E43)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFBEECDC)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF1C1C17)\nprivate val md_theme_dark_onBackground = Color(0xFFE5E2DA)\nprivate val md_theme_dark_surface = Color(0xFF1C1C17)\nprivate val md_theme_dark_onSurface = Color(0xFFE5E2DA)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF47483B)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFC8C7B7)\nprivate val md_theme_dark_outline = Color(0xFF929282)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF1C1C17)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE5E2DA)\nprivate val md_theme_dark_inversePrimary = Color(0xFF5B6300)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFC1D02C)\nprivate val md_theme_dark_outlineVariant = Color(0xFF47483B)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightLimeTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkLimeTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/OrangeTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF8B5000)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFFFDCBE)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF2C1600)\nprivate val md_theme_light_secondary = Color(0xFF725A42)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFFFDCBE)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF291806)\nprivate val md_theme_light_tertiary = Color(0xFF58633A)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFDCE8B4)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF161E01)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF201B16)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF201B16)\nprivate val md_theme_light_surfaceVariant = Color(0xFFF2DFD1)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF51453A)\nprivate val md_theme_light_outline = Color(0xFF837468)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFFAEFE7)\nprivate val md_theme_light_inverseSurface = Color(0xFF352F2B)\nprivate val md_theme_light_inversePrimary = Color(0xFFFFB870)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF8B5000)\nprivate val md_theme_light_outlineVariant = Color(0xFFD5C3B5)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFFFB870)\nprivate val md_theme_dark_onPrimary = Color(0xFF4A2800)\nprivate val md_theme_dark_primaryContainer = Color(0xFF693C00)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFFFDCBE)\nprivate val md_theme_dark_secondary = Color(0xFFE1C1A4)\nprivate val md_theme_dark_onSecondary = Color(0xFF402C18)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF59422C)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFFFDCBE)\nprivate val md_theme_dark_tertiary = Color(0xFFC0CC9A)\nprivate val md_theme_dark_onTertiary = Color(0xFF2B3410)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF414B24)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFDCE8B4)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF201B16)\nprivate val md_theme_dark_onBackground = Color(0xFFEBE0D9)\nprivate val md_theme_dark_surface = Color(0xFF201B16)\nprivate val md_theme_dark_onSurface = Color(0xFFEBE0D9)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF51453A)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFD5C3B5)\nprivate val md_theme_dark_outline = Color(0xFF9D8E81)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF201B16)\nprivate val md_theme_dark_inverseSurface = Color(0xFFEBE0D9)\nprivate val md_theme_dark_inversePrimary = Color(0xFF8B5000)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFFFB870)\nprivate val md_theme_dark_outlineVariant = Color(0xFF51453A)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightOrangeTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkOrangeTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/PinkTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFFBC004B)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFFFD9DE)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF400014)\nprivate val md_theme_light_secondary = Color(0xFF75565B)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFFFD9DE)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF2C1519)\nprivate val md_theme_light_tertiary = Color(0xFF795831)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFFFDDBA)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF2B1700)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF201A1B)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF201A1B)\nprivate val md_theme_light_surfaceVariant = Color(0xFFF3DDDF)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF524345)\nprivate val md_theme_light_outline = Color(0xFF847375)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFFBEEEE)\nprivate val md_theme_light_inverseSurface = Color(0xFF362F2F)\nprivate val md_theme_light_inversePrimary = Color(0xFFFFB2BE)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFFBC004B)\nprivate val md_theme_light_outlineVariant = Color(0xFFD6C2C3)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFFFB2BE)\nprivate val md_theme_dark_onPrimary = Color(0xFF660025)\nprivate val md_theme_dark_primaryContainer = Color(0xFF900038)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFFFD9DE)\nprivate val md_theme_dark_secondary = Color(0xFFE5BDC2)\nprivate val md_theme_dark_onSecondary = Color(0xFF43292D)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF5C3F43)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFFFD9DE)\nprivate val md_theme_dark_tertiary = Color(0xFFEBBF90)\nprivate val md_theme_dark_onTertiary = Color(0xFF452B08)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF5F411C)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFFFDDBA)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF201A1B)\nprivate val md_theme_dark_onBackground = Color(0xFFECE0E0)\nprivate val md_theme_dark_surface = Color(0xFF201A1B)\nprivate val md_theme_dark_onSurface = Color(0xFFECE0E0)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF524345)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFD6C2C3)\nprivate val md_theme_dark_outline = Color(0xFF9F8C8E)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF201A1B)\nprivate val md_theme_dark_inverseSurface = Color(0xFFECE0E0)\nprivate val md_theme_dark_inversePrimary = Color(0xFFBC004B)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFFFB2BE)\nprivate val md_theme_dark_outlineVariant = Color(0xFF524345)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightPinkTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkPinkTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/PurpleTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF9A25AE)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFFFD6FE)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF35003F)\nprivate val md_theme_light_secondary = Color(0xFF6B586B)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFF4DBF1)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF251626)\nprivate val md_theme_light_tertiary = Color(0xFF82524A)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFFFDAD4)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF33110C)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF1E1A1D)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF1E1A1D)\nprivate val md_theme_light_surfaceVariant = Color(0xFFECDFE8)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF4D444C)\nprivate val md_theme_light_outline = Color(0xFF7F747D)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF7EEF3)\nprivate val md_theme_light_inverseSurface = Color(0xFF332F32)\nprivate val md_theme_light_inversePrimary = Color(0xFFF9ABFF)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF9A25AE)\nprivate val md_theme_light_outlineVariant = Color(0xFFD0C3CC)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFF9ABFF)\nprivate val md_theme_dark_onPrimary = Color(0xFF570066)\nprivate val md_theme_dark_primaryContainer = Color(0xFF7B008F)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFFFD6FE)\nprivate val md_theme_dark_secondary = Color(0xFFD7BFD5)\nprivate val md_theme_dark_onSecondary = Color(0xFF3B2B3C)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF534153)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFF4DBF1)\nprivate val md_theme_dark_tertiary = Color(0xFFF6B8AD)\nprivate val md_theme_dark_onTertiary = Color(0xFF4C251F)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF673B34)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFFFDAD4)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF1E1A1D)\nprivate val md_theme_dark_onBackground = Color(0xFFE9E0E4)\nprivate val md_theme_dark_surface = Color(0xFF1E1A1D)\nprivate val md_theme_dark_onSurface = Color(0xFFE9E0E4)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF4D444C)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFD0C3CC)\nprivate val md_theme_dark_outline = Color(0xFF998D96)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF1E1A1D)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE9E0E4)\nprivate val md_theme_dark_inversePrimary = Color(0xFF9A25AE)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFF9ABFF)\nprivate val md_theme_dark_outlineVariant = Color(0xFF4D444C)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightPurpleTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkPurpleTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/RedTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFFBB1614)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFFFDAD5)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF410001)\nprivate val md_theme_light_secondary = Color(0xFF775652)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFFFDAD5)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF2C1512)\nprivate val md_theme_light_tertiary = Color(0xFF705C2E)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFFCDFA6)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF261A00)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF201A19)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF201A19)\nprivate val md_theme_light_surfaceVariant = Color(0xFFF5DDDA)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF534341)\nprivate val md_theme_light_outline = Color(0xFF857370)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFFBEEEC)\nprivate val md_theme_light_inverseSurface = Color(0xFF362F2E)\nprivate val md_theme_light_inversePrimary = Color(0xFFFFB4A9)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFFBB1614)\nprivate val md_theme_light_outlineVariant = Color(0xFFD8C2BE)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFFFB4A9)\nprivate val md_theme_dark_onPrimary = Color(0xFF690002)\nprivate val md_theme_dark_primaryContainer = Color(0xFF930005)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFFFDAD5)\nprivate val md_theme_dark_secondary = Color(0xFFE7BDB7)\nprivate val md_theme_dark_onSecondary = Color(0xFF442926)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF5D3F3B)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFFFDAD5)\nprivate val md_theme_dark_tertiary = Color(0xFFDFC38C)\nprivate val md_theme_dark_onTertiary = Color(0xFF3E2E04)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF574419)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFFCDFA6)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF201A19)\nprivate val md_theme_dark_onBackground = Color(0xFFEDE0DE)\nprivate val md_theme_dark_surface = Color(0xFF201A19)\nprivate val md_theme_dark_onSurface = Color(0xFFEDE0DE)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF534341)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFD8C2BE)\nprivate val md_theme_dark_outline = Color(0xFFA08C89)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF201A19)\nprivate val md_theme_dark_inverseSurface = Color(0xFFEDE0DE)\nprivate val md_theme_dark_inversePrimary = Color(0xFFBB1614)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFFFB4A9)\nprivate val md_theme_dark_outlineVariant = Color(0xFF534341)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightRedTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkRedTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/SakuraTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF9B404F)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFFFD9DC)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF400011)\nprivate val md_theme_light_secondary = Color(0xFF765659)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFFFD9DC)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF2C1518)\nprivate val md_theme_light_tertiary = Color(0xFF785830)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFFFDDB7)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF2A1700)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF201A1A)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF201A1A)\nprivate val md_theme_light_surfaceVariant = Color(0xFFF4DDDE)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF524344)\nprivate val md_theme_light_outline = Color(0xFF847374)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFFBEEEE)\nprivate val md_theme_light_inverseSurface = Color(0xFF362F2F)\nprivate val md_theme_light_inversePrimary = Color(0xFFFFB2BA)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF9B404F)\nprivate val md_theme_light_outlineVariant = Color(0xFFD7C1C3)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFFFB2BA)\nprivate val md_theme_dark_onPrimary = Color(0xFF5F1223)\nprivate val md_theme_dark_primaryContainer = Color(0xFF7D2939)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFFFD9DC)\nprivate val md_theme_dark_secondary = Color(0xFFE5BDC0)\nprivate val md_theme_dark_onSecondary = Color(0xFF43292C)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF5C3F42)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFFFD9DC)\nprivate val md_theme_dark_tertiary = Color(0xFFE9BF8F)\nprivate val md_theme_dark_onTertiary = Color(0xFF442B07)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF5E411B)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFFFDDB7)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF201A1A)\nprivate val md_theme_dark_onBackground = Color(0xFFECE0E0)\nprivate val md_theme_dark_surface = Color(0xFF201A1A)\nprivate val md_theme_dark_onSurface = Color(0xFFECE0E0)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF524344)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFD7C1C3)\nprivate val md_theme_dark_outline = Color(0xFF9F8C8D)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF201A1A)\nprivate val md_theme_dark_inverseSurface = Color(0xFFECE0E0)\nprivate val md_theme_dark_inversePrimary = Color(0xFF9B404F)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFFFB2BA)\nprivate val md_theme_dark_outlineVariant = Color(0xFF524344)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightSakuraTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkSakuraTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/TealTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF006A60)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFF74F8E5)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF00201C)\nprivate val md_theme_light_secondary = Color(0xFF4A635F)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFCCE8E2)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF05201C)\nprivate val md_theme_light_tertiary = Color(0xFF456179)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFCCE5FF)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF001E31)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFAFDFB)\nprivate val md_theme_light_onBackground = Color(0xFF191C1B)\nprivate val md_theme_light_surface = Color(0xFFFAFDFB)\nprivate val md_theme_light_onSurface = Color(0xFF191C1B)\nprivate val md_theme_light_surfaceVariant = Color(0xFFDAE5E1)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF3F4947)\nprivate val md_theme_light_outline = Color(0xFF6F7977)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFEFF1EF)\nprivate val md_theme_light_inverseSurface = Color(0xFF2D3130)\nprivate val md_theme_light_inversePrimary = Color(0xFF53DBC9)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF006A60)\nprivate val md_theme_light_outlineVariant = Color(0xFFBEC9C6)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFF53DBC9)\nprivate val md_theme_dark_onPrimary = Color(0xFF003731)\nprivate val md_theme_dark_primaryContainer = Color(0xFF005048)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFF74F8E5)\nprivate val md_theme_dark_secondary = Color(0xFFB1CCC6)\nprivate val md_theme_dark_onSecondary = Color(0xFF1C3531)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF334B47)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFCCE8E2)\nprivate val md_theme_dark_tertiary = Color(0xFFADCAE6)\nprivate val md_theme_dark_onTertiary = Color(0xFF153349)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF2D4961)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFCCE5FF)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF191C1B)\nprivate val md_theme_dark_onBackground = Color(0xFFE0E3E1)\nprivate val md_theme_dark_surface = Color(0xFF191C1B)\nprivate val md_theme_dark_onSurface = Color(0xFFE0E3E1)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF3F4947)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFBEC9C6)\nprivate val md_theme_dark_outline = Color(0xFF899390)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF191C1B)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE0E3E1)\nprivate val md_theme_dark_inversePrimary = Color(0xFF006A60)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFF53DBC9)\nprivate val md_theme_dark_outlineVariant = Color(0xFF3F4947)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\n\nval LightTealTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkTealTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/Theme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport android.os.Build\nimport androidx.activity.ComponentActivity\nimport androidx.activity.SystemBarStyle\nimport androidx.activity.enableEdgeToEdge\nimport androidx.compose.foundation.isSystemInDarkTheme\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.dynamicDarkColorScheme\nimport androidx.compose.material3.dynamicLightColorScheme\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.SideEffect\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.livedata.observeAsState\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.runtime.setValue\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.graphics.toArgb\nimport androidx.compose.ui.platform.LocalContext\nimport androidx.lifecycle.MutableLiveData\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.ui.webui.MonetColorsProvider\n\n@Composable\nprivate fun SystemBarStyle(\n    darkMode: Boolean,\n    statusBarScrim: Color = Color.Transparent,\n    navigationBarScrim: Color = Color.Transparent\n) {\n    val context = LocalContext.current\n    val activity = context as ComponentActivity\n\n    SideEffect {\n        activity.enableEdgeToEdge(\n            statusBarStyle = SystemBarStyle.auto(\n                statusBarScrim.toArgb(),\n                statusBarScrim.toArgb(),\n            ) { darkMode }, navigationBarStyle = when {\n                darkMode -> SystemBarStyle.dark(\n                    navigationBarScrim.toArgb()\n                )\n\n                else -> SystemBarStyle.light(\n                    navigationBarScrim.toArgb(),\n                    navigationBarScrim.toArgb(),\n                )\n            }\n        )\n    }\n}\n\nval refreshTheme = MutableLiveData(false)\n\n@Composable\nfun APatchTheme(\n    content: @Composable () -> Unit\n) {\n    val context = LocalContext.current\n    val prefs = APApplication.sharedPreferences\n\n    var darkThemeFollowSys by remember {\n        mutableStateOf(\n            prefs.getBoolean(\n                \"night_mode_follow_sys\",\n                true\n            )\n        )\n    }\n    var nightModeEnabled by remember {\n        mutableStateOf(\n            prefs.getBoolean(\n                \"night_mode_enabled\",\n                false\n            )\n        )\n    }\n    // Dynamic color is available on Android 12+, and custom 1t!\n    var dynamicColor by remember {\n        mutableStateOf(\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) prefs.getBoolean(\n                \"use_system_color_theme\",\n                true\n            ) else false\n        )\n    }\n    var customColorScheme by remember { mutableStateOf(prefs.getString(\"custom_color\", \"blue\")) }\n\n    val refreshThemeObserver by refreshTheme.observeAsState(false)\n    if (refreshThemeObserver == true) {\n        darkThemeFollowSys = prefs.getBoolean(\"night_mode_follow_sys\", true)\n        nightModeEnabled = prefs.getBoolean(\"night_mode_enabled\", false)\n        dynamicColor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) prefs.getBoolean(\n            \"use_system_color_theme\",\n            true\n        ) else false\n        customColorScheme = prefs.getString(\"custom_color\", \"blue\")\n        refreshTheme.postValue(false)\n    }\n\n    val darkTheme = if (darkThemeFollowSys) {\n        isSystemInDarkTheme()\n    } else {\n        nightModeEnabled\n    }\n\n    val colorScheme = if (!dynamicColor) {\n        if (darkTheme) {\n            when (customColorScheme) {\n                \"amber\" -> DarkAmberTheme\n                \"blue_grey\" -> DarkBlueGreyTheme\n                \"blue\" -> DarkBlueTheme\n                \"brown\" -> DarkBrownTheme\n                \"cyan\" -> DarkCyanTheme\n                \"deep_orange\" -> DarkDeepOrangeTheme\n                \"deep_purple\" -> DarkDeepPurpleTheme\n                \"green\" -> DarkGreenTheme\n                \"indigo\" -> DarkIndigoTheme\n                \"light_blue\" -> DarkLightBlueTheme\n                \"light_green\" -> DarkLightGreenTheme\n                \"lime\" -> DarkLimeTheme\n                \"orange\" -> DarkOrangeTheme\n                \"pink\" -> DarkPinkTheme\n                \"purple\" -> DarkPurpleTheme\n                \"red\" -> DarkRedTheme\n                \"sakura\" -> DarkSakuraTheme\n                \"teal\" -> DarkTealTheme\n                \"yellow\" -> DarkYellowTheme\n                else -> DarkBlueTheme\n            }\n        } else {\n            when (customColorScheme) {\n                \"amber\" -> LightAmberTheme\n                \"blue_grey\" -> LightBlueGreyTheme\n                \"blue\" -> LightBlueTheme\n                \"brown\" -> LightBrownTheme\n                \"cyan\" -> LightCyanTheme\n                \"deep_orange\" -> LightDeepOrangeTheme\n                \"deep_purple\" -> LightDeepPurpleTheme\n                \"green\" -> LightGreenTheme\n                \"indigo\" -> LightIndigoTheme\n                \"light_blue\" -> LightLightBlueTheme\n                \"light_green\" -> LightLightGreenTheme\n                \"lime\" -> LightLimeTheme\n                \"orange\" -> LightOrangeTheme\n                \"pink\" -> LightPinkTheme\n                \"purple\" -> LightPurpleTheme\n                \"red\" -> LightRedTheme\n                \"sakura\" -> LightSakuraTheme\n                \"teal\" -> LightTealTheme\n                \"yellow\" -> LightYellowTheme\n                else -> LightBlueTheme\n            }\n        }\n    } else {\n        when {\n            Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {\n                if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)\n            }\n\n            darkTheme -> DarkBlueTheme\n            else -> LightBlueTheme\n        }\n    }\n\n    SystemBarStyle(\n        darkMode = darkTheme\n    )\n\n    MaterialTheme(\n        colorScheme = colorScheme,\n        typography = Typography,\n        content = {\n            MonetColorsProvider.UpdateCss()\n            content()\n        }\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/Type.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.ui.text.TextStyle\nimport androidx.compose.ui.text.font.FontFamily\nimport androidx.compose.ui.text.font.FontWeight\nimport androidx.compose.ui.unit.sp\n\n// Set of Material typography styles to start with\nval Typography = androidx.compose.material3.Typography(\n    bodyLarge = TextStyle(\n        fontFamily = FontFamily.Default,\n        fontWeight = FontWeight.Normal,\n        fontSize = 16.sp,\n        lineHeight = 24.sp,\n        letterSpacing = 0.5.sp\n    )\n    /* Other default text styles to override\n    titleLarge = TextStyle(\n        fontFamily = FontFamily.Default,\n        fontWeight = FontWeight.Normal,\n        fontSize = 22.sp,\n        lineHeight = 28.sp,\n        letterSpacing = 0.sp\n    ),\n    labelSmall = TextStyle(\n        fontFamily = FontFamily.Default,\n        fontWeight = FontWeight.Medium,\n        fontSize = 11.sp,\n        lineHeight = 16.sp,\n        letterSpacing = 0.5.sp\n    )\n    */\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/theme/YellowTheme.kt",
    "content": "package me.bmax.apatch.ui.theme\n\nimport androidx.compose.material3.darkColorScheme\nimport androidx.compose.material3.lightColorScheme\nimport androidx.compose.ui.graphics.Color\n\nprivate val md_theme_light_primary = Color(0xFF695F00)\nprivate val md_theme_light_onPrimary = Color(0xFFFFFFFF)\nprivate val md_theme_light_primaryContainer = Color(0xFFF9E534)\nprivate val md_theme_light_onPrimaryContainer = Color(0xFF201C00)\nprivate val md_theme_light_secondary = Color(0xFF645F41)\nprivate val md_theme_light_onSecondary = Color(0xFFFFFFFF)\nprivate val md_theme_light_secondaryContainer = Color(0xFFEBE3BD)\nprivate val md_theme_light_onSecondaryContainer = Color(0xFF1F1C05)\nprivate val md_theme_light_tertiary = Color(0xFF406652)\nprivate val md_theme_light_onTertiary = Color(0xFFFFFFFF)\nprivate val md_theme_light_tertiaryContainer = Color(0xFFC2ECD3)\nprivate val md_theme_light_onTertiaryContainer = Color(0xFF002113)\nprivate val md_theme_light_error = Color(0xFFBA1A1A)\nprivate val md_theme_light_errorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_light_onError = Color(0xFFFFFFFF)\nprivate val md_theme_light_onErrorContainer = Color(0xFF410002)\nprivate val md_theme_light_background = Color(0xFFFFFBFF)\nprivate val md_theme_light_onBackground = Color(0xFF1D1C16)\nprivate val md_theme_light_surface = Color(0xFFFFFBFF)\nprivate val md_theme_light_onSurface = Color(0xFF1D1C16)\nprivate val md_theme_light_surfaceVariant = Color(0xFFE8E2D0)\nprivate val md_theme_light_onSurfaceVariant = Color(0xFF4A473A)\nprivate val md_theme_light_outline = Color(0xFF7B7768)\nprivate val md_theme_light_inverseOnSurface = Color(0xFFF5F0E7)\nprivate val md_theme_light_inverseSurface = Color(0xFF32302A)\nprivate val md_theme_light_inversePrimary = Color(0xFFDBC90A)\nprivate val md_theme_light_shadow = Color(0xFF000000)\nprivate val md_theme_light_surfaceTint = Color(0xFF695F00)\nprivate val md_theme_light_outlineVariant = Color(0xFFCBC6B5)\nprivate val md_theme_light_scrim = Color(0xFF000000)\n\nprivate val md_theme_dark_primary = Color(0xFFDBC90A)\nprivate val md_theme_dark_onPrimary = Color(0xFF363100)\nprivate val md_theme_dark_primaryContainer = Color(0xFF4F4800)\nprivate val md_theme_dark_onPrimaryContainer = Color(0xFFF9E534)\nprivate val md_theme_dark_secondary = Color(0xFFCEC7A3)\nprivate val md_theme_dark_onSecondary = Color(0xFF343117)\nprivate val md_theme_dark_secondaryContainer = Color(0xFF4B472B)\nprivate val md_theme_dark_onSecondaryContainer = Color(0xFFEBE3BD)\nprivate val md_theme_dark_tertiary = Color(0xFFA7D0B7)\nprivate val md_theme_dark_onTertiary = Color(0xFF103726)\nprivate val md_theme_dark_tertiaryContainer = Color(0xFF294E3B)\nprivate val md_theme_dark_onTertiaryContainer = Color(0xFFC2ECD3)\nprivate val md_theme_dark_error = Color(0xFFFFB4AB)\nprivate val md_theme_dark_errorContainer = Color(0xFF93000A)\nprivate val md_theme_dark_onError = Color(0xFF690005)\nprivate val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)\nprivate val md_theme_dark_background = Color(0xFF1D1C16)\nprivate val md_theme_dark_onBackground = Color(0xFFE7E2D9)\nprivate val md_theme_dark_surface = Color(0xFF1D1C16)\nprivate val md_theme_dark_onSurface = Color(0xFFE7E2D9)\nprivate val md_theme_dark_surfaceVariant = Color(0xFF4A473A)\nprivate val md_theme_dark_onSurfaceVariant = Color(0xFFCBC6B5)\nprivate val md_theme_dark_outline = Color(0xFF959181)\nprivate val md_theme_dark_inverseOnSurface = Color(0xFF1D1C16)\nprivate val md_theme_dark_inverseSurface = Color(0xFFE7E2D9)\nprivate val md_theme_dark_inversePrimary = Color(0xFF695F00)\nprivate val md_theme_dark_shadow = Color(0xFF000000)\nprivate val md_theme_dark_surfaceTint = Color(0xFFDBC90A)\nprivate val md_theme_dark_outlineVariant = Color(0xFF4A473A)\nprivate val md_theme_dark_scrim = Color(0xFF000000)\n\nval LightYellowTheme = lightColorScheme(\n    primary = md_theme_light_primary,\n    onPrimary = md_theme_light_onPrimary,\n    primaryContainer = md_theme_light_primaryContainer,\n    onPrimaryContainer = md_theme_light_onPrimaryContainer,\n    secondary = md_theme_light_secondary,\n    onSecondary = md_theme_light_onSecondary,\n    secondaryContainer = md_theme_light_secondaryContainer,\n    onSecondaryContainer = md_theme_light_onSecondaryContainer,\n    tertiary = md_theme_light_tertiary,\n    onTertiary = md_theme_light_onTertiary,\n    tertiaryContainer = md_theme_light_tertiaryContainer,\n    onTertiaryContainer = md_theme_light_onTertiaryContainer,\n    error = md_theme_light_error,\n    errorContainer = md_theme_light_errorContainer,\n    onError = md_theme_light_onError,\n    onErrorContainer = md_theme_light_onErrorContainer,\n    background = md_theme_light_background,\n    onBackground = md_theme_light_onBackground,\n    surface = md_theme_light_surface,\n    onSurface = md_theme_light_onSurface,\n    surfaceVariant = md_theme_light_surfaceVariant,\n    onSurfaceVariant = md_theme_light_onSurfaceVariant,\n    outline = md_theme_light_outline,\n    inverseOnSurface = md_theme_light_inverseOnSurface,\n    inverseSurface = md_theme_light_inverseSurface,\n    inversePrimary = md_theme_light_inversePrimary,\n    surfaceTint = md_theme_light_surfaceTint,\n    outlineVariant = md_theme_light_outlineVariant,\n    scrim = md_theme_light_scrim,\n)\n\nval DarkYellowTheme = darkColorScheme(\n    primary = md_theme_dark_primary,\n    onPrimary = md_theme_dark_onPrimary,\n    primaryContainer = md_theme_dark_primaryContainer,\n    onPrimaryContainer = md_theme_dark_onPrimaryContainer,\n    secondary = md_theme_dark_secondary,\n    onSecondary = md_theme_dark_onSecondary,\n    secondaryContainer = md_theme_dark_secondaryContainer,\n    onSecondaryContainer = md_theme_dark_onSecondaryContainer,\n    tertiary = md_theme_dark_tertiary,\n    onTertiary = md_theme_dark_onTertiary,\n    tertiaryContainer = md_theme_dark_tertiaryContainer,\n    onTertiaryContainer = md_theme_dark_onTertiaryContainer,\n    error = md_theme_dark_error,\n    errorContainer = md_theme_dark_errorContainer,\n    onError = md_theme_dark_onError,\n    onErrorContainer = md_theme_dark_onErrorContainer,\n    background = md_theme_dark_background,\n    onBackground = md_theme_dark_onBackground,\n    surface = md_theme_dark_surface,\n    onSurface = md_theme_dark_onSurface,\n    surfaceVariant = md_theme_dark_surfaceVariant,\n    onSurfaceVariant = md_theme_dark_onSurfaceVariant,\n    outline = md_theme_dark_outline,\n    inverseOnSurface = md_theme_dark_inverseOnSurface,\n    inverseSurface = md_theme_dark_inverseSurface,\n    inversePrimary = md_theme_dark_inversePrimary,\n    surfaceTint = md_theme_dark_surfaceTint,\n    outlineVariant = md_theme_dark_outlineVariant,\n    scrim = md_theme_dark_scrim,\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/viewmodel/APModuleViewModel.kt",
    "content": "package me.bmax.apatch.ui.viewmodel\n\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.compose.runtime.derivedStateOf\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.setValue\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport me.bmax.apatch.apApp\nimport me.bmax.apatch.util.HanziToPinyin\nimport me.bmax.apatch.util.listModules\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport java.text.Collator\nimport java.util.Locale\n\nclass APModuleViewModel : ViewModel() {\n    companion object {\n        private const val TAG = \"ModuleViewModel\"\n        private var modules by mutableStateOf<List<ModuleInfo>>(emptyList())\n    }\n\n    data class ModuleInfo(\n        val id: String,\n        val name: String,\n        val author: String,\n        val version: String,\n        val versionCode: Int,\n        val description: String,\n        val enabled: Boolean,\n        val update: Boolean,\n        val remove: Boolean,\n        val updateJson: String,\n        val hasWebUi: Boolean,\n        val hasActionScript: Boolean,\n        val metamodule: Boolean,\n        val updateInfo: ModuleUpdateInfo? = null,\n    )\n\n    data class ModuleUpdateInfo(\n        val version: String,\n        val versionCode: Int,\n        val zipUrl: String,\n        val changelog: String,\n    )\n\n    var search by mutableStateOf(\"\")\n    var isRefreshing by mutableStateOf(false)\n        private set\n\n    val moduleList by derivedStateOf {\n        val collator = Collator.getInstance(Locale.getDefault())\n\n        val comparator = compareByDescending<ModuleInfo> { it.metamodule && it.enabled }\n            .thenBy(collator) { it.id }\n\n        modules.filter {\n            it.id.contains(search, true) || it.name.contains(search, true) || HanziToPinyin.getInstance()\n                .toPinyinString(it.name)?.contains(search, true) == true\n        }.sortedWith(comparator).also {\n            isRefreshing = false\n        }\n    }\n\n    var isNeedRefresh by mutableStateOf(false)\n        private set\n\n    fun markNeedRefresh() {\n        isNeedRefresh = true\n    }\n\n    fun fetchModuleList() {\n        viewModelScope.launch(Dispatchers.IO) {\n            isRefreshing = true\n\n            val oldModuleList = modules\n\n            val start = SystemClock.elapsedRealtime()\n\n            kotlin.runCatching {\n\n                val result = listModules()\n\n                Log.i(TAG, \"result: $result\")\n\n                val array = JSONArray(result)\n                modules = (0 until array.length())\n                    .asSequence()\n                    .map { array.getJSONObject(it) }\n                    .map { obj ->\n                        ModuleInfo(\n                            obj.getString(\"id\"),\n\n                            obj.optString(\"name\"),\n                            obj.optString(\"author\", \"Unknown\"),\n                            obj.optString(\"version\", \"Unknown\"),\n                            obj.optInt(\"versionCode\", 0),\n                            obj.optString(\"description\"),\n                            obj.getBoolean(\"enabled\"),\n                            obj.getBoolean(\"update\"),\n                            obj.getBoolean(\"remove\"),\n                            obj.optString(\"updateJson\"),\n                            obj.getBooleanCompat(\"web\"),\n                            obj.getBooleanCompat(\"action\"),\n                            obj.getBooleanCompat(\"metamodule\")\n                        )\n                    }.toList()\n                viewModelScope.launch(Dispatchers.IO) {\n                    val updatedModules = modules.map { module ->\n                        if (module.enabled && module.updateJson.isNotEmpty() && !module.update && !module.remove) {\n                            module.copy(updateInfo = runCatching { checkUpdate(module) }.getOrNull())\n                        } else module\n                    }\n                    modules = updatedModules\n                }\n                isNeedRefresh = false\n            }.onFailure { e ->\n                Log.e(TAG, \"fetchModuleList: \", e)\n                isRefreshing = false\n            }\n\n            // when both old and new is kotlin.collections.EmptyList\n            // moduleList update will don't trigger\n            if (oldModuleList === modules) {\n                isRefreshing = false\n            }\n\n            Log.i(TAG, \"load cost: ${SystemClock.elapsedRealtime() - start}, modules: $modules\")\n        }\n    }\n\n    private fun sanitizeVersionString(version: String): String {\n        return version.replace(Regex(\"[^a-zA-Z0-9.\\\\-_]\"), \"_\")\n    }\n\n    fun checkUpdate(m: ModuleInfo): ModuleUpdateInfo? {\n        if (m.updateJson.isEmpty() || m.remove || m.update || !m.enabled) {\n            return null\n        }\n        // download updateJson\n        val result = kotlin.runCatching {\n            val url = m.updateJson\n            Log.i(TAG, \"checkUpdate url: $url\")\n            val response = apApp.okhttpClient\n                .newCall(\n                    okhttp3.Request.Builder()\n                        .url(url)\n                        .build()\n                ).execute()\n            Log.d(TAG, \"checkUpdate code: ${response.code}\")\n            if (response.isSuccessful) {\n                response.body?.string() ?: \"\"\n            } else {\n                \"\"\n            }\n        }.getOrDefault(\"\")\n        Log.i(TAG, \"checkUpdate result: $result\")\n\n        if (result.isEmpty()) {\n            return null\n        }\n\n        val updateJson = kotlin.runCatching {\n            JSONObject(result)\n        }.getOrNull() ?: return null\n\n        val version = sanitizeVersionString(updateJson.optString(\"version\", \"\"))\n        val versionCode = updateJson.optInt(\"versionCode\", 0)\n        val zipUrl = updateJson.optString(\"zipUrl\", \"\")\n        val changelog = updateJson.optString(\"changelog\", \"\")\n        if (versionCode <= m.versionCode || zipUrl.isEmpty()) {\n            return null\n        }\n\n        return ModuleUpdateInfo(version, versionCode, zipUrl, changelog)\n    }\n}\n\nprivate fun JSONObject.getBooleanCompat(key: String, default: Boolean = false): Boolean {\n    if (!has(key)) return default\n    return when (val value = opt(key)) {\n        is Boolean -> value\n        is String -> value.equals(\"true\", ignoreCase = true) || value == \"1\"\n        is Number -> value.toInt() != 0\n        else -> default\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/viewmodel/KPModel.kt",
    "content": "package me.bmax.apatch.ui.viewmodel\n\nimport android.os.Parcelable\nimport androidx.annotation.Keep\nimport androidx.compose.runtime.Immutable\nimport kotlinx.parcelize.Parcelize\n\nobject KPModel {\n\n    enum class TriggerEvent(val event: String) {\n        PAGING_INIT(\"paging-init\"),\n        PRE_KERNEL_INIT(\"pre-kernel-init\"),\n        POST_KERNEL_INIT(\"post-kernel-init\"),\n    }\n\n\n    enum class ExtraType(val desc: String) {\n        NONE(\"none\"),\n        KPM(\"kpm\"),\n        SHELL(\"shell\"),\n        EXEC(\"exec\"),\n        RAW(\"raw\"),\n        ANDROID_RC(\"android_rc\");\n    }\n\n    interface IExtraInfo : Parcelable {\n        var type: ExtraType\n        var name: String\n        var event: String\n        var args: String\n    }\n\n    @Immutable\n    @Parcelize\n    @Keep\n    data class KPMInfo(\n        override var type: ExtraType,\n        override var name: String,\n        override var event: String,\n        override var args: String,\n        var version: String,\n        var license: String,\n        var author: String,\n        var description: String,\n    ) : IExtraInfo\n\n    @Immutable\n    @Parcelize\n    @Keep\n    data class KPImgInfo(\n        var version: String,\n        var compileTime: String,\n        var config: String,\n        var superKey: String,\n        var rootSuperkey: String\n    ) : Parcelable\n\n    @Immutable\n    @Parcelize\n    @Keep\n    data class KImgInfo(\n        var banner: String,\n        var patched: Boolean,\n    ) : Parcelable\n\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/viewmodel/KPModuleViewModel.kt",
    "content": "package me.bmax.apatch.ui.viewmodel\n\nimport android.os.SystemClock\nimport android.util.Log\nimport androidx.compose.runtime.derivedStateOf\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.setValue\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport me.bmax.apatch.Natives\nimport me.bmax.apatch.util.HanziToPinyin\nimport java.text.Collator\nimport java.util.Locale\n\nclass KPModuleViewModel : ViewModel() {\n    companion object {\n        private const val TAG = \"KPModuleViewModel\"\n        private var modules by mutableStateOf<List<KPModel.KPMInfo>>(emptyList())\n    }\n\n    var search by mutableStateOf(\"\")\n    var isRefreshing by mutableStateOf(false)\n        private set\n\n\n    val moduleList by derivedStateOf {\n        val comparator = compareBy(\n            comparator = Collator.getInstance(Locale.getDefault()),\n            selector = KPModel.KPMInfo::name\n        )\n\n        modules.filter {\n            it.name.contains(search, true) || it.name.contains(search, true) || HanziToPinyin.getInstance()\n                .toPinyinString(it.name)?.contains(search, true) == true\n        }.sortedWith(comparator).also {\n            isRefreshing = false\n        }\n    }\n\n    var isNeedRefresh by mutableStateOf(false)\n        private set\n\n    fun markNeedRefresh() {\n        isNeedRefresh = true\n    }\n\n    fun fetchModuleList() {\n        viewModelScope.launch(Dispatchers.IO) {\n            isRefreshing = true\n            val oldModuleList = modules\n            val start = SystemClock.elapsedRealtime()\n\n            kotlin.runCatching {\n                var names = Natives.kernelPatchModuleList()\n                if (Natives.kernelPatchModuleNum() <= 0)\n                    names = \"\"\n                val nameList = names.split('\\n').toList()\n                Log.d(TAG, \"kpm list: $nameList\")\n                modules = nameList.filter { it.isNotEmpty() }.map {\n                    val infoline = Natives.kernelPatchModuleInfo(it)\n                    val spi = infoline.split('\\n')\n                    val name = spi.find { it.startsWith(\"name=\") }?.removePrefix(\"name=\")\n                    val version = spi.find { it.startsWith(\"version=\") }?.removePrefix(\"version=\")\n                    val license = spi.find { it.startsWith(\"license=\") }?.removePrefix(\"license=\")\n                    val author = spi.find { it.startsWith(\"author=\") }?.removePrefix(\"author=\")\n                    val description =\n                        spi.find { it.startsWith(\"description=\") }?.removePrefix(\"description=\")\n                    val args = spi.find { it.startsWith(\"args=\") }?.removePrefix(\"args=\")\n                    val info = KPModel.KPMInfo(\n                        KPModel.ExtraType.KPM,\n                        name ?: \"\",\n                        \"\",\n                        args ?: \"\",\n                        version ?: \"\",\n                        license ?: \"\",\n                        author ?: \"\",\n                        description ?: \"\"\n                    )\n                    info\n                }\n                isNeedRefresh = false\n            }.onFailure { e ->\n                Log.e(TAG, \"fetchModuleList: \", e)\n                isRefreshing = false\n            }\n\n            // when both old and new is kotlin.collections.EmptyList\n            // moduleList update will don't trigger\n            if (oldModuleList === modules) {\n                isRefreshing = false\n            }\n\n            Log.i(TAG, \"load cost: ${SystemClock.elapsedRealtime() - start}, modules: $modules\")\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/viewmodel/PatchesViewModel.kt",
    "content": "package me.bmax.apatch.ui.viewmodel\n\nimport android.content.ContentValues\nimport android.content.Context\nimport android.net.Uri\nimport android.os.Build\nimport android.os.Environment\nimport android.provider.MediaStore\nimport android.system.Os\nimport android.util.Log\nimport androidx.annotation.RequiresApi\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateListOf\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.setValue\nimport androidx.core.content.FileProvider\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport com.topjohnwu.superuser.CallbackList\nimport com.topjohnwu.superuser.Shell\nimport com.topjohnwu.superuser.nio.ExtendedFile\nimport com.topjohnwu.superuser.nio.FileSystemManager\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.launch\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.BuildConfig\nimport me.bmax.apatch.R\nimport me.bmax.apatch.apApp\nimport me.bmax.apatch.util.Version\nimport me.bmax.apatch.util.copyAndClose\nimport me.bmax.apatch.util.copyAndCloseOut\nimport me.bmax.apatch.util.createRootShell\nimport me.bmax.apatch.util.inputStream\nimport me.bmax.apatch.util.shellForResult\nimport me.bmax.apatch.util.writeTo\nimport org.ini4j.Ini\nimport java.io.BufferedReader\nimport java.io.File\nimport java.io.FileNotFoundException\nimport java.io.IOException\nimport java.io.InputStreamReader\nimport java.io.StringReader\n\nprivate const val TAG = \"PatchViewModel\"\n\nclass PatchesViewModel : ViewModel() {\n\n    enum class PatchMode(val sId: Int) {\n        PATCH_ONLY(R.string.patch_mode_bootimg_patch),\n        PATCH_AND_INSTALL(R.string.patch_mode_patch_and_install),\n        INSTALL_TO_NEXT_SLOT(R.string.patch_mode_install_to_next_slot),\n        UNPATCH(R.string.patch_mode_uninstall_patch)\n    }\n\n    var bootSlot by mutableStateOf(\"\")\n    var bootDev by mutableStateOf(\"\")\n    var kimgInfo by mutableStateOf(KPModel.KImgInfo(\"\", false))\n    var kpimgInfo by mutableStateOf(KPModel.KPImgInfo(\"\", \"\", \"\", \"\", \"\"))\n    var superkey by mutableStateOf(APApplication.superKey)\n    var existedExtras = mutableStateListOf<KPModel.IExtraInfo>()\n    var newExtras = mutableStateListOf<KPModel.IExtraInfo>()\n    var newExtrasFileName = mutableListOf<String>()\n\n    var running by mutableStateOf(false)\n    var patching by mutableStateOf(false)\n    var patchdone by mutableStateOf(false)\n    var needReboot by mutableStateOf(false)\n\n    var error by mutableStateOf(\"\")\n    var patchLog by mutableStateOf(\"\")\n\n    private val patchDir: ExtendedFile = FileSystemManager.getLocal().getFile(apApp.filesDir.parent, \"patch\")\n    private var srcBoot: ExtendedFile = patchDir.getChildFile(\"boot.img\")\n    private var shell: Shell = createRootShell()\n    private var prepared: Boolean = false\n\n    private fun prepare() {\n        patchDir.deleteRecursively()\n        patchDir.mkdirs()\n        val execs = listOf(\n            \"libkptools.so\", \"libbusybox.so\", \"libkpatch.so\", \"libbootctl.so\"\n        )\n        error = \"\"\n\n        val info = apApp.applicationInfo\n        val libs = File(info.nativeLibraryDir).listFiles { _, name ->\n            execs.contains(name)\n        } ?: emptyArray()\n\n        for (lib in libs) {\n            val name = lib.name.substring(3, lib.name.length - 3)\n            Os.symlink(lib.path, \"$patchDir/$name\")\n        }\n\n        // Extract scripts\n        for (script in listOf(\n            \"boot_patch.sh\", \"boot_unpatch.sh\", \"boot_extract.sh\", \"util_functions.sh\", \"kpimg\"\n        )) {\n            val dest = File(patchDir, script)\n            apApp.assets.open(script).writeTo(dest)\n        }\n\n    }\n\n    private fun parseKpimg() {\n        val result = shellForResult(\n            shell, \"cd $patchDir\", \"./kptools -l -k kpimg\"\n        )\n\n        if (result.isSuccess) {\n            val ini = Ini(StringReader(result.out.joinToString(\"\\n\")))\n            val kpimg = ini[\"kpimg\"]\n            if (kpimg != null) {\n                kpimgInfo = KPModel.KPImgInfo(\n                    kpimg[\"version\"].toString(),\n                    kpimg[\"compile_time\"].toString(),\n                    kpimg[\"config\"].toString(),\n                    APApplication.superKey,     // current key\n                    kpimg[\"root_superkey\"].toString(),   // empty\n                )\n            } else {\n                error += \"parse kpimg error\\n\"\n            }\n        } else {\n            error = result.err.joinToString(\"\\n\")\n        }\n    }\n\n    private fun parseBootimg(bootimg: String) {\n        val result = shellForResult(\n            shell,\n            \"cd $patchDir\",\n            \"./kptools unpacknolog $bootimg\",\n            \"./kptools -l -i kernel\",\n        )\n        if (result.isSuccess) {\n            val ini = Ini(StringReader(result.out.joinToString(\"\\n\")))\n            Log.d(TAG, \"kernel image info: $ini\")\n\n            val kernel = ini[\"kernel\"]\n            if (kernel == null) {\n                error += \"empty kernel section\"\n                Log.d(TAG, error)\n                return\n            }\n            kimgInfo = KPModel.KImgInfo(kernel[\"banner\"].toString(), kernel[\"patched\"].toBoolean())\n            if (kimgInfo.patched) {\n                val superkey = ini[\"kpimg\"]?.getOrDefault(\"superkey\", \"\") ?: \"\"\n                kpimgInfo.superKey = superkey\n                if (checkSuperKeyValidation(superkey)) {\n                    this.superkey = superkey\n                }\n                var kpmNum = kernel[\"extra_num\"]?.toInt()\n                if (kpmNum == null) {\n                    val extras = ini[\"extras\"]\n                    kpmNum = extras?.get(\"num\")?.toInt()\n                }\n                if (kpmNum != null && kpmNum > 0) {\n                    for (i in 0..<kpmNum) {\n                        val extra = ini[\"extra $i\"]\n                        if (extra == null) {\n                            error += \"empty extra section\"\n                            break\n                        }\n                        val type = KPModel.ExtraType.valueOf(extra[\"type\"]!!.uppercase())\n                        val name = extra[\"name\"].toString()\n                        val args = extra[\"args\"].toString()\n                        var event = extra[\"event\"].toString()\n                        if (event.isEmpty()) {\n                            event = KPModel.TriggerEvent.PRE_KERNEL_INIT.event\n                        }\n                        if (type == KPModel.ExtraType.KPM) {\n                            val kpmInfo = KPModel.KPMInfo(\n                                type, name, event, args,\n                                extra[\"version\"].toString(),\n                                extra[\"license\"].toString(),\n                                extra[\"author\"].toString(),\n                                extra[\"description\"].toString(),\n                            )\n                            existedExtras.add(kpmInfo)\n                        }\n                    }\n\n                }\n            }\n        } else {\n            error += result.err.joinToString(\"\\n\")\n        }\n    }\n\n    val checkSuperKeyValidation: (superKey: String) -> Boolean = { superKey ->\n        superKey.length in 8..63 && superKey.any { it.isDigit() } && superKey.any { it.isLetter() }\n    }\n\n    fun copyAndParseBootimg(uri: Uri) {\n        viewModelScope.launch(Dispatchers.IO) {\n            if (running) return@launch\n            running = true\n            try {\n                uri.inputStream().buffered().use { src ->\n                    srcBoot.also {\n                        src.copyAndCloseOut(it.newOutputStream())\n                    }\n                }\n            } catch (e: IOException) {\n                Log.e(TAG, \"copy boot image error: $e\")\n            }\n            parseBootimg(srcBoot.path)\n            running = false\n        }\n    }\n\n    private fun extractAndParseBootimg(mode: PatchMode) {\n        var cmdBuilder = \"./boot_extract.sh\"\n\n        if (mode == PatchMode.INSTALL_TO_NEXT_SLOT) {\n            cmdBuilder += \" true\"\n        }\n\n        val result = shellForResult(\n            shell,\n            \"export ASH_STANDALONE=1\",\n            \"cd $patchDir\",\n            \"./busybox sh $cmdBuilder\",\n        )\n\n        if (result.isSuccess) {\n            bootSlot = if (!result.out.toString().contains(\"SLOT=\")) {\n                \"\"\n            } else {\n                result.out.filter { it.startsWith(\"SLOT=\") }[0].removePrefix(\"SLOT=\")\n            }\n            bootDev =\n                result.out.filter { it.startsWith(\"BOOTIMAGE=\") }[0].removePrefix(\"BOOTIMAGE=\")\n            Log.i(TAG, \"current slot: $bootSlot\")\n            Log.i(TAG, \"current bootimg: $bootDev\")\n            srcBoot = FileSystemManager.getLocal().getFile(bootDev)\n            parseBootimg(bootDev)\n        } else {\n            error = result.err.joinToString(\"\\n\")\n        }\n        running = false\n    }\n\n    fun prepare(mode: PatchMode) {\n        viewModelScope.launch(Dispatchers.IO) {\n            if (prepared) return@launch\n            prepared = true\n\n            running = true\n            prepare()\n            if (mode != PatchMode.UNPATCH) {\n                parseKpimg()\n            }\n            if (mode == PatchMode.PATCH_AND_INSTALL || mode == PatchMode.UNPATCH || mode == PatchMode.INSTALL_TO_NEXT_SLOT) {\n                extractAndParseBootimg(mode)\n            }\n            running = false\n        }\n    }\n\n    fun embedKPM(uri: Uri) {\n        viewModelScope.launch(Dispatchers.IO) {\n            if (running) return@launch\n            running = true\n            error = \"\"\n\n            val rand = (1..4).map { ('a'..'z').random() }.joinToString(\"\")\n            val kpmFileName = \"${rand}.kpm\"\n            val kpmFile: ExtendedFile = patchDir.getChildFile(kpmFileName)\n\n            Log.i(TAG, \"copy kpm to: \" + kpmFile.path)\n            try {\n                uri.inputStream().buffered().use { src ->\n                    kpmFile.also {\n                        src.copyAndCloseOut(it.newOutputStream())\n                    }\n                }\n            } catch (e: IOException) {\n                Log.e(TAG, \"Copy kpm error: $e\")\n            }\n\n            val result = shellForResult(\n                shell, \"cd $patchDir\", \"./kptools -l -M ${kpmFile.path}\"\n            )\n\n            if (result.isSuccess) {\n                val ini = Ini(StringReader(result.out.joinToString(\"\\n\")))\n                val kpm = ini[\"kpm\"]\n                if (kpm != null) {\n                    val kpmInfo = KPModel.KPMInfo(\n                        KPModel.ExtraType.KPM,\n                        kpm[\"name\"].toString(),\n                        KPModel.TriggerEvent.PRE_KERNEL_INIT.event,\n                        \"\",\n                        kpm[\"version\"].toString(),\n                        kpm[\"license\"].toString(),\n                        kpm[\"author\"].toString(),\n                        kpm[\"description\"].toString(),\n                    )\n                    newExtras.add(kpmInfo)\n                    newExtrasFileName.add(kpmFileName)\n                }\n            } else {\n                error = \"Invalid KPM\\n\"\n            }\n            running = false\n        }\n    }\n\n    fun doUnpatch() {\n        viewModelScope.launch(Dispatchers.IO) {\n            patching = true\n            patchLog = \"\"\n            Log.i(TAG, \"starting unpatching...\")\n\n            val logs = object : CallbackList<String>() {\n                override fun onAddElement(e: String?) {\n                    patchLog += e\n                    Log.i(TAG, \"\" + e)\n                    patchLog += \"\\n\"\n                }\n            }\n\n            val result = shell.newJob().add(\n                \"export ASH_STANDALONE=1\",\n                \"cd $patchDir\",\n                \"cp /data/adb/ap/ori.img new-boot.img\",\n                \"./busybox sh ./boot_unpatch.sh $bootDev\",\n                \"rm -f ${APApplication.APD_PATH}\",\n                \"rm -rf ${APApplication.APATCH_FOLDER}\",\n            ).to(logs, logs).exec()\n\n            if (result.isSuccess) {\n                logs.add(\" Unpatch successful\")\n                needReboot = true\n                APApplication.markNeedReboot()\n            } else {\n                logs.add(\" Unpatched failed\")\n                error = result.err.joinToString(\"\\n\")\n            }\n            logs.add(\"****************************\")\n\n            patchdone = true\n            patching = false\n        }\n    }\n    fun isSuExecutable(): Boolean {\n        val suFile = File(\"/system/bin/su\")\n        return suFile.exists() && suFile.canExecute()\n    }\n    fun doPatch(mode: PatchMode) {\n        viewModelScope.launch(Dispatchers.IO) {\n            patching = true\n            Log.d(TAG, \"starting patching...\")\n\n            val apVer = Version.getManagerVersion().second\n            val rand = (1..4).map { ('a'..'z').random() }.joinToString(\"\")\n            val outFilename = \"apatch_patched_${apVer}_${BuildConfig.buildKPV}_${rand}.img\"\n\n            val logs = object : CallbackList<String>() {\n                override fun onAddElement(e: String?) {\n                    patchLog += e\n                    Log.d(TAG, \"\" + e)\n                    patchLog += \"\\n\"\n                }\n            }\n            logs.add(\"****************************\")\n\n            var patchCommand = mutableListOf(\"./busybox sh boot_patch.sh \\\"$0\\\" \\\"$@\\\"\")\n\n            // adapt for 0.10.7 and lower KP\n            var isKpOld = false\n\n            if (mode == PatchMode.PATCH_AND_INSTALL || mode == PatchMode.INSTALL_TO_NEXT_SLOT) {\n\n                val KPCheck = shell.newJob().add(\"truncate $superkey -Z u:r:magisk:s0 -c whoami\").exec()\n\n                if (KPCheck.isSuccess && !isSuExecutable()) {\n                    patchCommand.addAll(0, listOf(\"truncate\", APApplication.superKey, \"-Z\", APApplication.MAGISK_SCONTEXT, \"-c\"))\n                    patchCommand.addAll(listOf(superkey, srcBoot.path, \"true\"))\n                } else {\n                    patchCommand = mutableListOf(\"./busybox\", \"sh\", \"boot_patch.sh\")\n                    patchCommand.addAll(listOf(superkey, srcBoot.path, \"true\"))\n                    isKpOld = true\n                }\n\n            } else {\n                patchCommand.addAll(0, listOf(\"sh\", \"-c\"))\n                patchCommand.addAll(listOf(superkey, srcBoot.path))\n            }\n\n            for (i in 0..<newExtrasFileName.size) {\n                patchCommand.addAll(listOf(\"-M\", newExtrasFileName[i]))\n                val extra = newExtras[i]\n                if (extra.args.isNotEmpty()) {\n                    patchCommand.addAll(listOf(\"-A\", extra.args))\n                }\n                if (extra.event.isNotEmpty()) {\n                    patchCommand.addAll(listOf(\"-V\", extra.event))\n                }\n                patchCommand.addAll(listOf(\"-T\", extra.type.desc))\n            }\n            for (i in 0..<existedExtras.size) {\n                val extra = existedExtras[i]\n                patchCommand.addAll(listOf(\"-E\", extra.name))\n                if (extra.args.isNotEmpty()) {\n                    patchCommand.addAll(listOf(\"-A\", extra.args))\n                }\n                if (extra.event.isNotEmpty()) {\n                    patchCommand.addAll(listOf(\"-V\", extra.event))\n                }\n                patchCommand.addAll(listOf(\"-T\", extra.type.desc))\n            }\n\n            val builder = ProcessBuilder(patchCommand)\n\n            Log.i(TAG, \"patchCommand: $patchCommand\")\n\n            var succ = false\n\n            if (isKpOld) {\n                val resultString = \"\\\"\" + patchCommand.joinToString(separator = \"\\\" \\\"\") + \"\\\"\"\n                val result = shell.newJob().add(\n                    \"export ASH_STANDALONE=1\",\n                    \"cd $patchDir\",\n                    resultString,\n                ).to(logs, logs).exec()\n                succ = result.isSuccess\n            } else {\n                builder.environment().put(\"ASH_STANDALONE\", \"1\")\n                builder.directory(patchDir)\n                builder.redirectErrorStream(true)\n\n                val process = builder.start()\n\n                Thread {\n                    BufferedReader(InputStreamReader(process.inputStream)).use { reader ->\n                        var line: String?\n                        while (reader.readLine().also { line = it } != null) {\n                            patchLog += line\n                            Log.i(TAG, \"\" + line)\n                            patchLog += \"\\n\"\n                        }\n                    }\n                }.start()\n                succ = process.waitFor() == 0\n            }\n\n            if (!succ) {\n                val msg = \" Patch failed.\"\n                error = msg\n//                error += result.err.joinToString(\"\\n\")\n                logs.add(error)\n                logs.add(\"****************************\")\n                patching = false\n                return@launch\n            }\n\n            if (mode == PatchMode.PATCH_AND_INSTALL) {\n                logs.add(\"- Reboot to finish the installation...\")\n                needReboot = true\n                APApplication.markNeedReboot()\n            } else if (mode == PatchMode.INSTALL_TO_NEXT_SLOT) {\n                logs.add(\"- Connecting boot hal...\")\n                val bootctlStatus = shell.newJob().add(\n                    \"cd $patchDir\", \"chmod 0777 $patchDir/bootctl\", \"./bootctl hal-info\"\n                ).to(logs, logs).exec()\n                if (!bootctlStatus.isSuccess) {\n                    logs.add(\"[X] Failed to connect to boot hal, you may need switch slot manually\")\n                } else {\n                    val currSlot = shellForResult(\n                        shell, \"cd $patchDir\", \"./bootctl get-current-slot\"\n                    ).out.toString()\n                    val targetSlot = if (currSlot.contains(\"0\")) {\n                        1\n                    } else {\n                        0\n                    }\n                    logs.add(\"- Switching to next slot: $targetSlot...\")\n                    val setNextActiveSlot = shell.newJob().add(\n                        \"cd $patchDir\", \"./bootctl set-active-boot-slot $targetSlot\"\n                    ).exec()\n                    if (setNextActiveSlot.isSuccess) {\n                        logs.add(\"- Switch done\")\n                        logs.add(\"- Writing boot marker script...\")\n                        val markBootableScript = shell.newJob().add(\n                            \"mkdir -p /data/adb/post-fs-data.d && rm -rf /data/adb/post-fs-data.d/post_ota.sh && touch /data/adb/post-fs-data.d/post_ota.sh\",\n                            \"echo \\\"chmod 0777 $patchDir/bootctl\\\" > /data/adb/post-fs-data.d/post_ota.sh\",\n                            \"echo \\\"chown root:root 0777 $patchDir/bootctl\\\" > /data/adb/post-fs-data.d/post_ota.sh\",\n                            \"echo \\\"$patchDir/bootctl mark-boot-successful\\\" > /data/adb/post-fs-data.d/post_ota.sh\",\n                            \"echo >> /data/adb/post-fs-data.d/post_ota.sh\",\n                            \"echo \\\"rm -rf $patchDir\\\" >> /data/adb/post-fs-data.d/post_ota.sh\",\n                            \"echo >> /data/adb/post-fs-data.d/post_ota.sh\",\n                            \"echo \\\"rm -f /data/adb/post-fs-data.d/post_ota.sh\\\" >> /data/adb/post-fs-data.d/post_ota.sh\",\n                            \"chmod 0777 /data/adb/post-fs-data.d/post_ota.sh\",\n                            \"chown root:root /data/adb/post-fs-data.d/post_ota.sh\",\n                        ).to(logs, logs).exec()\n                        if (markBootableScript.isSuccess) {\n                            logs.add(\"- Boot marker script write done\")\n                        } else {\n                            logs.add(\"[X] Boot marker scripts write failed\")\n                        }\n                    }\n                }\n                logs.add(\"- Reboot to finish the installation...\")\n                needReboot = true\n                APApplication.markNeedReboot()\n            } else if (mode == PatchMode.PATCH_ONLY) {\n                val newBootFile = patchDir.getChildFile(\"new-boot.img\")\n                val outDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)\n                if (!outDir.exists()) outDir.mkdirs()\n                val outPath = File(outDir, outFilename)\n                val inputUri = newBootFile.getUri(apApp)\n\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                    val outUri = createDownloadUri(apApp, outFilename)\n                    succ = insertDownload(apApp, outUri, inputUri)\n                } else {\n                    newBootFile.inputStream().copyAndClose(outPath.outputStream())\n                }\n                if (succ) {\n                    logs.add(\" Output file is written to \")\n                    logs.add(\" ${outPath.path}\")\n                } else {\n                    logs.add(\" Write patched boot.img failed\")\n                }\n            }\n            logs.add(\"****************************\")\n            patchdone = true\n            patching = false\n        }\n    }\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    fun createDownloadUri(context: Context, outFilename: String): Uri? {\n        val contentValues = ContentValues().apply {\n            put(MediaStore.Downloads.DISPLAY_NAME, outFilename)\n            put(MediaStore.Downloads.MIME_TYPE, \"application/octet-stream\")\n            put(MediaStore.Downloads.IS_PENDING, 1)\n        }\n\n        val resolver = context.contentResolver\n        return resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)\n    }\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    fun insertDownload(context: Context, outUri: Uri?, inputUri: Uri): Boolean {\n        if (outUri == null) return false\n\n        try {\n            val resolver = context.contentResolver\n            resolver.openInputStream(inputUri)?.use { inputStream ->\n                resolver.openOutputStream(outUri)?.use { outputStream ->\n                    inputStream.copyTo(outputStream)\n                }\n            }\n            val contentValues = ContentValues().apply {\n                put(MediaStore.Downloads.IS_PENDING, 0)\n            }\n            resolver.update(outUri, contentValues, null, null)\n\n            return true\n        } catch (_: FileNotFoundException) {\n            return false\n        }\n    }\n\n    fun File.getUri(context: Context): Uri {\n        val authority = \"${context.packageName}.fileprovider\"\n        return FileProvider.getUriForFile(context, authority, this)\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/viewmodel/SuperUserViewModel.kt",
    "content": "package me.bmax.apatch.ui.viewmodel\n\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport android.content.ServiceConnection\nimport android.content.pm.ApplicationInfo\nimport android.content.pm.PackageInfo\nimport android.graphics.drawable.Drawable\nimport android.os.IBinder\nimport android.os.Parcelable\nimport android.util.Log\nimport androidx.compose.runtime.derivedStateOf\nimport androidx.compose.runtime.getValue\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.setValue\nimport androidx.lifecycle.ViewModel\nimport com.topjohnwu.superuser.Shell\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport kotlinx.parcelize.Parcelize\nimport me.bmax.apatch.IAPRootService\nimport me.bmax.apatch.Natives\nimport me.bmax.apatch.apApp\nimport me.bmax.apatch.services.RootServices\nimport me.bmax.apatch.util.APatchCli\nimport me.bmax.apatch.util.HanziToPinyin\nimport me.bmax.apatch.util.PkgConfig\nimport java.text.Collator\nimport java.util.Locale\nimport kotlin.concurrent.thread\nimport kotlin.coroutines.resume\nimport kotlin.coroutines.suspendCoroutine\n\n\nclass SuperUserViewModel : ViewModel() {\n    companion object {\n        private const val TAG = \"SuperUserViewModel\"\n        private val appsLock = Any()\n        var apps by mutableStateOf<List<AppInfo>>(emptyList())\n\n        fun getAppIconDrawable(context: Context, packageName: String): Drawable? {\n            val appList = synchronized(appsLock) { apps }\n            val appDetail = appList.find { it.packageName == packageName }\n            return appDetail?.packageInfo?.applicationInfo?.loadIcon(context.packageManager)\n        }\n    }\n\n    @Parcelize\n    data class AppInfo(\n        val label: String, val packageInfo: PackageInfo, val config: PkgConfig.Config\n    ) : Parcelable {\n        val packageName: String\n            get() = packageInfo.packageName\n        val uid: Int\n            get() = packageInfo.applicationInfo!!.uid\n    }\n\n    var search by mutableStateOf(\"\")\n    var showSystemApps by mutableStateOf(false)\n    var isRefreshing by mutableStateOf(false)\n        private set\n\n    private val sortedList by derivedStateOf {\n        val comparator = compareBy<AppInfo> {\n            when {\n                it.config.allow != 0 -> 0\n                it.config.exclude == 1 -> 1\n                else -> 2\n            }\n        }.then(compareBy(Collator.getInstance(Locale.getDefault()), AppInfo::label))\n        apps.sortedWith(comparator)\n    }\n\n    val appList by derivedStateOf {\n        sortedList.filter {\n            it.label.lowercase().contains(search.lowercase()) || it.packageName.lowercase()\n                .contains(search.lowercase()) || HanziToPinyin.getInstance()\n                .toPinyinString(it.label).contains(search.lowercase())\n        }.filter {\n            it.uid == 2000 // Always show shell\n                    || showSystemApps || it.packageInfo.applicationInfo!!.flags.and(ApplicationInfo.FLAG_SYSTEM) == 0\n        }\n    }\n\n    private suspend inline fun connectRootService(\n        crossinline onDisconnect: () -> Unit = {}\n    ): Pair<IBinder, ServiceConnection> = suspendCoroutine {\n        val connection = object : ServiceConnection {\n            override fun onServiceDisconnected(name: ComponentName?) {\n                onDisconnect()\n            }\n\n            override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {\n                it.resume(binder as IBinder to this)\n            }\n        }\n        val intent = Intent(apApp, RootServices::class.java)\n        val task = RootServices.bindOrTask(\n            intent,\n            Shell.EXECUTOR,\n            connection,\n        )\n        val shell = APatchCli.SHELL\n        task?.let { it1 -> shell.execTask(it1) }\n    }\n\n    private fun stopRootService() {\n        val intent = Intent(apApp, RootServices::class.java)\n        RootServices.stop(intent)\n    }\n\n    suspend fun fetchAppList() {\n        isRefreshing = true\n\n        try {\n            val result = connectRootService {\n                Log.w(TAG, \"RootService disconnected\")\n            }\n\n            withContext(Dispatchers.IO) {\n                val binder = result.first\n                val allPackages = IAPRootService.Stub.asInterface(binder).getPackages(0)\n\n                withContext(Dispatchers.Main) {\n                    stopRootService()\n                }\n                val uids = Natives.suUids().toList()\n                Log.d(TAG, \"all allows: $uids\")\n\n                var configs: HashMap<Int, PkgConfig.Config> = HashMap()\n                thread {\n                    Natives.su()\n                    configs = PkgConfig.readConfigs()\n                }.join()\n\n                Log.d(TAG, \"all configs: $configs\")\n\n                val newApps = allPackages.list.map {\n                    val appInfo = it.applicationInfo\n                    val uid = appInfo!!.uid\n                    val actProfile = if (uids.contains(uid)) Natives.suProfile(uid) else null\n                    val config = configs.getOrDefault(\n                        uid, PkgConfig.Config(appInfo.packageName, Natives.isUidExcluded(uid), 0, Natives.Profile(uid = uid))\n                    )\n                    config.allow = 0\n\n                    // from kernel\n                    if (actProfile != null) {\n                        config.allow = 1\n                        config.profile = actProfile\n                    }\n                    AppInfo(\n                        label = appInfo.loadLabel(apApp.packageManager).toString(),\n                        packageInfo = it,\n                        config = config\n                    )\n                }\n\n                withContext(Dispatchers.Main) {\n                    synchronized(appsLock) {\n                        apps = newApps\n                    }\n                }\n            }\n        } catch (e: Exception) {\n            Log.e(TAG, \"Failed to fetch app list\", e)\n        } finally {\n            isRefreshing = false\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/webui/AppIconUtil.kt",
    "content": "package me.bmax.apatch.ui.webui\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.graphics.Canvas\nimport android.graphics.drawable.BitmapDrawable\nimport android.graphics.drawable.Drawable\nimport android.util.LruCache\nimport androidx.core.graphics.createBitmap\nimport androidx.core.graphics.scale\nimport me.bmax.apatch.ui.viewmodel.SuperUserViewModel.Companion.getAppIconDrawable\n\nobject AppIconUtil {\n    // Limit cache size to 200 icons\n    private const val CACHE_SIZE = 200\n    private val iconCache = LruCache<String?, Bitmap?>(CACHE_SIZE)\n\n    @Synchronized\n    fun loadAppIconSync(context: Context, packageName: String, sizePx: Int): Bitmap? {\n        val cached = iconCache.get(packageName)\n        if (cached != null) return cached\n\n        try {\n            val drawable = getAppIconDrawable(context, packageName) ?: return null\n            val raw = drawableToBitmap(drawable, sizePx)\n            val icon = raw.scale(sizePx, sizePx)\n            iconCache.put(packageName, icon)\n            return icon\n        } catch (_: Exception) {\n            return null\n        }\n    }\n\n    private fun drawableToBitmap(drawable: Drawable, size: Int): Bitmap {\n        if (drawable is BitmapDrawable) return drawable.bitmap\n\n        val width = if (drawable.intrinsicWidth > 0) drawable.intrinsicWidth else size\n        val height = if (drawable.intrinsicHeight > 0) drawable.intrinsicHeight else size\n\n        val bmp = createBitmap(width, height)\n        val canvas = Canvas(bmp)\n        drawable.setBounds(0, 0, canvas.width, canvas.height)\n        drawable.draw(canvas)\n        return bmp\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/webui/Insets.kt",
    "content": "package me.bmax.apatch.ui.webui\n\n/**\n * Insets data class from GitHub@MMRLApp/WebUI-X-Portable\n *\n * Data class representing insets (top, bottom, left, right) for a view.\n *\n * This class provides methods to generate CSS code that can be injected into a WebView\n * to apply these insets as CSS variables. This is useful for adapting web content\n * to the safe areas of a device screen, considering notches, status bars, and navigation bars.\n *\n * @property top The top inset value in pixels.\n * @property bottom The bottom inset value in pixels.\n * @property left The left inset value in pixels.\n * @property right The right inset value in pixels.\n */\ndata class Insets(\n    val top: Int,\n    val bottom: Int,\n    val left: Int,\n    val right: Int,\n) {\n    val css\n        get() = buildString {\n            appendLine(\":root {\")\n            appendLine(\"\\t--safe-area-inset-top: ${top}px;\")\n            appendLine(\"\\t--safe-area-inset-right: ${right}px;\")\n            appendLine(\"\\t--safe-area-inset-bottom: ${bottom}px;\")\n            appendLine(\"\\t--safe-area-inset-left: ${left}px;\")\n            appendLine(\"\\t--window-inset-top: var(--safe-area-inset-top, 0px);\")\n            appendLine(\"\\t--window-inset-bottom: var(--safe-area-inset-bottom, 0px);\")\n            appendLine(\"\\t--window-inset-left: var(--safe-area-inset-left, 0px);\")\n            appendLine(\"\\t--window-inset-right: var(--safe-area-inset-right, 0px);\")\n            appendLine(\"\\t--f7-safe-area-top: var(--window-inset-top, 0px) !important;\")\n            appendLine(\"\\t--f7-safe-area-bottom: var(--window-inset-bottom, 0px) !important;\")\n            appendLine(\"\\t--f7-safe-area-left: var(--window-inset-left, 0px) !important;\")\n            appendLine(\"\\t--f7-safe-area-right: var(--window-inset-right, 0px) !important;\")\n            append(\"}\")\n        }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/webui/MimeUtil.java",
    "content": "/*\n * Copyright 2023 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage me.bmax.apatch.ui.webui;\n\nimport java.net.URLConnection;\n\nclass MimeUtil {\n\n    public static String getMimeFromFileName(String fileName) {\n        if (fileName == null) {\n            return null;\n        }\n\n        // Copying the logic and mapping that Chromium follows.\n        // First we check against the OS (this is a limited list by default)\n        // but app developers can extend this.\n        // We then check against a list of hardcoded mime types above if the\n        // OS didn't provide a result.\n        String mimeType = URLConnection.guessContentTypeFromName(fileName);\n\n        if (mimeType != null) {\n            return mimeType;\n        }\n\n        return guessHardcodedMime(fileName);\n    }\n\n    // We should keep this map in sync with the lists under\n    // //net/base/mime_util.cc in Chromium.\n    // A bunch of the mime types don't really apply to Android land\n    // like word docs so feel free to filter out where necessary.\n    private static String guessHardcodedMime(String fileName) {\n        int finalFullStop = fileName.lastIndexOf('.');\n        if (finalFullStop == -1) {\n            return null;\n        }\n\n        final String extension = fileName.substring(finalFullStop + 1).toLowerCase();\n\n        switch (extension) {\n            case \"webm\":\n                return \"video/webm\";\n            case \"mpeg\":\n            case \"mpg\":\n                return \"video/mpeg\";\n            case \"mp3\":\n                return \"audio/mpeg\";\n            case \"wasm\":\n                return \"application/wasm\";\n            case \"xhtml\":\n            case \"xht\":\n            case \"xhtm\":\n                return \"application/xhtml+xml\";\n            case \"flac\":\n                return \"audio/flac\";\n            case \"ogg\":\n            case \"oga\":\n            case \"opus\":\n                return \"audio/ogg\";\n            case \"wav\":\n                return \"audio/wav\";\n            case \"m4a\":\n                return \"audio/x-m4a\";\n            case \"gif\":\n                return \"image/gif\";\n            case \"jpeg\":\n            case \"jpg\":\n            case \"jfif\":\n            case \"pjpeg\":\n            case \"pjp\":\n                return \"image/jpeg\";\n            case \"png\":\n                return \"image/png\";\n            case \"apng\":\n                return \"image/apng\";\n            case \"svg\":\n            case \"svgz\":\n                return \"image/svg+xml\";\n            case \"webp\":\n                return \"image/webp\";\n            case \"mht\":\n            case \"mhtml\":\n                return \"multipart/related\";\n            case \"css\":\n                return \"text/css\";\n            case \"html\":\n            case \"htm\":\n            case \"shtml\":\n            case \"shtm\":\n            case \"ehtml\":\n                return \"text/html\";\n            case \"js\":\n            case \"mjs\":\n                return \"application/javascript\";\n            case \"xml\":\n                return \"text/xml\";\n            case \"mp4\":\n            case \"m4v\":\n                return \"video/mp4\";\n            case \"ogv\":\n            case \"ogm\":\n                return \"video/ogg\";\n            case \"ico\":\n                return \"image/x-icon\";\n            case \"woff\":\n                return \"application/font-woff\";\n            case \"gz\":\n            case \"tgz\":\n                return \"application/gzip\";\n            case \"json\":\n                return \"application/json\";\n            case \"pdf\":\n                return \"application/pdf\";\n            case \"zip\":\n                return \"application/zip\";\n            case \"bmp\":\n                return \"image/bmp\";\n            case \"tiff\":\n            case \"tif\":\n                return \"image/tiff\";\n            default:\n                return null;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/webui/MonetColorsProvider.kt",
    "content": "package me.bmax.apatch.ui.webui\n\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.surfaceColorAtElevation\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.LaunchedEffect\nimport androidx.compose.ui.graphics.Color\nimport androidx.compose.ui.unit.dp\nimport java.util.concurrent.atomic.AtomicReference\n\n/**\n * @author rifsxd\n * @date 2025/6/2.\n */\nobject MonetColorsProvider {\n\n    private val colorsCss: AtomicReference<String?> = AtomicReference(null)\n\n    fun getColorsCss(): String {\n        return colorsCss.get() ?: \"\"\n    }\n\n    @Composable\n    fun UpdateCss() {\n        val colorScheme = MaterialTheme.colorScheme\n\n        LaunchedEffect(colorScheme) {\n            // Generate CSS only when colorScheme changes\n            val monetColors = mapOf(\n                // App Base Colors\n                \"primary\" to colorScheme.primary.toCssValue(),\n                \"onPrimary\" to colorScheme.onPrimary.toCssValue(),\n                \"primaryContainer\" to colorScheme.primaryContainer.toCssValue(),\n                \"onPrimaryContainer\" to colorScheme.onPrimaryContainer.toCssValue(),\n                \"inversePrimary\" to colorScheme.inversePrimary.toCssValue(),\n                \"secondary\" to colorScheme.secondary.toCssValue(),\n                \"onSecondary\" to colorScheme.onSecondary.toCssValue(),\n                \"secondaryContainer\" to colorScheme.secondaryContainer.toCssValue(),\n                \"onSecondaryContainer\" to colorScheme.onSecondaryContainer.toCssValue(),\n                \"tertiary\" to colorScheme.tertiary.toCssValue(),\n                \"onTertiary\" to colorScheme.onTertiary.toCssValue(),\n                \"tertiaryContainer\" to colorScheme.tertiaryContainer.toCssValue(),\n                \"onTertiaryContainer\" to colorScheme.onTertiaryContainer.toCssValue(),\n                \"background\" to colorScheme.background.toCssValue(),\n                \"onBackground\" to colorScheme.onBackground.toCssValue(),\n                \"surface\" to colorScheme.surface.toCssValue(),\n                \"tonalSurface\" to colorScheme.surfaceColorAtElevation(1.dp).toCssValue(),\n                \"onSurface\" to colorScheme.onSurface.toCssValue(),\n                \"surfaceVariant\" to colorScheme.surfaceVariant.toCssValue(),\n                \"onSurfaceVariant\" to colorScheme.onSurfaceVariant.toCssValue(),\n                \"surfaceTint\" to colorScheme.surfaceTint.toCssValue(),\n                \"inverseSurface\" to colorScheme.inverseSurface.toCssValue(),\n                \"inverseOnSurface\" to colorScheme.inverseOnSurface.toCssValue(),\n                \"error\" to colorScheme.error.toCssValue(),\n                \"onError\" to colorScheme.onError.toCssValue(),\n                \"errorContainer\" to colorScheme.errorContainer.toCssValue(),\n                \"onErrorContainer\" to colorScheme.onErrorContainer.toCssValue(),\n                \"outline\" to colorScheme.outline.toCssValue(),\n                \"outlineVariant\" to colorScheme.outlineVariant.toCssValue(),\n                \"scrim\" to colorScheme.scrim.toCssValue(),\n                \"surfaceBright\" to colorScheme.surfaceBright.toCssValue(),\n                \"surfaceDim\" to colorScheme.surfaceDim.toCssValue(),\n                \"surfaceContainer\" to colorScheme.surfaceContainer.toCssValue(),\n                \"surfaceContainerHigh\" to colorScheme.surfaceContainerHigh.toCssValue(),\n                \"surfaceContainerHighest\" to colorScheme.surfaceContainerHighest.toCssValue(),\n                \"surfaceContainerLow\" to colorScheme.surfaceContainerLow.toCssValue(),\n                \"surfaceContainerLowest\" to colorScheme.surfaceContainerLowest.toCssValue(),\n                \"filledTonalButtonContentColor\" to colorScheme.onPrimaryContainer.toCssValue(),\n                \"filledTonalButtonContainerColor\" to colorScheme.secondaryContainer.toCssValue(),\n                \"filledTonalButtonDisabledContentColor\" to colorScheme.onSurfaceVariant.toCssValue(),\n                \"filledTonalButtonDisabledContainerColor\" to colorScheme.surfaceVariant.toCssValue(),\n                \"filledCardContentColor\" to colorScheme.onPrimaryContainer.toCssValue(),\n                \"filledCardContainerColor\" to colorScheme.primaryContainer.toCssValue(),\n                \"filledCardDisabledContentColor\" to colorScheme.onSurfaceVariant.toCssValue(),\n                \"filledCardDisabledContainerColor\" to colorScheme.surfaceVariant.toCssValue()\n            )\n\n            colorsCss.set(monetColors.toCssVars())\n        }\n    }\n\n    private fun Map<String, String>.toCssVars(): String {\n        return buildString {\n            append(\":root {\\n\")\n            for ((k, v) in this@toCssVars) {\n                append(\"  --$k: $v;\\n\")\n            }\n            append(\"}\\n\")\n        }\n    }\n\n    private fun Color.toCssValue(): String {\n        fun Float.toHex(): String {\n            return (this * 255).toInt().coerceIn(0, 255).toString(16).padStart(2, '0')\n        }\n        return if (alpha == 1f) {\n            \"#${red.toHex()}${green.toHex()}${blue.toHex()}\"\n        } else {\n            \"#${red.toHex()}${green.toHex()}${blue.toHex()}${alpha.toHex()}\"\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/webui/SuFilePathHandler.java",
    "content": "package me.bmax.apatch.ui.webui;\n\nimport android.content.Context;\nimport android.util.Log;\nimport android.webkit.WebResourceResponse;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\nimport androidx.webkit.WebViewAssetLoader;\n\nimport com.topjohnwu.superuser.Shell;\nimport com.topjohnwu.superuser.io.SuFile;\nimport com.topjohnwu.superuser.io.SuFileInputStream;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.zip.GZIPInputStream;\n\nimport me.bmax.apatch.util.APatchCliKt;\n\n/**\n * Handler class to open files from file system by root access\n * For more information about android storage please refer to\n * <a href=\"https://developer.android.com/guide/topics/data/data-storage\">Android Developers\n * Docs: Data and file storage overview</a>.\n * <p class=\"note\">\n * To avoid leaking user or app data to the web, make sure to choose {@code directory}\n * carefully, and assume any file under this directory could be accessed by any web page subject\n * to same-origin rules.\n * <p>\n * A typical usage would be like:\n * <pre class=\"prettyprint\">\n * File publicDir = new File(context.getFilesDir(), \"public\");\n * // Host \"files/public/\" in app's data directory under:\n * // http://appassets.androidplatform.net/public/...\n * WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()\n *          .addPathHandler(\"/public/\", new InternalStoragePathHandler(context, publicDir))\n *          .build();\n * </pre>\n */\npublic final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {\n    private static final String TAG = \"SuFilePathHandler\";\n\n    /**\n     * Default value to be used as MIME type if guessing MIME type failed.\n     */\n    public static final String DEFAULT_MIME_TYPE = \"text/plain\";\n\n    /**\n     * Forbidden subdirectories of {@link Context#getDataDir} that cannot be exposed by this\n     * handler. They are forbidden as they often contain sensitive information.\n     * <p class=\"note\">\n     * Note: Any future addition to this list will be considered breaking changes to the API.\n     */\n    private static final String[] FORBIDDEN_DATA_DIRS =\n            new String[] {\"/data/data\", \"/data/system\"};\n\n    @NonNull\n    private final File mDirectory;\n\n    private final Shell mShell;\n    private final InsetsSupplier mInsetsSupplier;\n    @NonNull\n    private final OnInsetsRequestedListener mOnInsetsRequestedListener;\n\n    public interface InsetsSupplier {\n        @NonNull\n        Insets get();\n    }\n\n    public interface OnInsetsRequestedListener {\n        void onInsetsRequested(boolean enable);\n    }\n\n    /**\n     * Creates PathHandler for app's internal storage.\n     * The directory to be exposed must be inside either the application's internal data\n     * directory {@link Context#getDataDir} or cache directory {@link Context#getCacheDir}.\n     * External storage is not supported for security reasons, as other apps with\n     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} may be able to modify the\n     * files.\n     * <p>\n     * Exposing the entire data or cache directory is not permitted, to avoid accidentally\n     * exposing sensitive application files to the web. Certain existing subdirectories of\n     * {@link Context#getDataDir} are also not permitted as they are often sensitive.\n     * These files are ({@code \"app_webview/\"}, {@code \"databases/\"}, {@code \"lib/\"},\n     * {@code \"shared_prefs/\"} and {@code \"code_cache/\"}).\n     * <p>\n     * The application should typically use a dedicated subdirectory for the files it intends to\n     * expose and keep them separate from other files.\n     *\n     * @param context {@link Context} that is used to access app's internal storage.\n     * @param directory the absolute path of the exposed app internal storage directory from\n     *                  which files can be loaded.\n     * @param insetsSupplier {@link InsetsSupplier} to provide window insets for styling web content.\n     * @param onInsetsRequestedListener {@link OnInsetsRequestedListener} to notify when insets are requested.\n     * @throws IllegalArgumentException if the directory is not allowed.\n     */\n    public SuFilePathHandler(@NonNull Context context, @NonNull File directory, @NonNull InsetsSupplier insetsSupplier, @NonNull OnInsetsRequestedListener onInsetsRequestedListener) {\n        try {\n            mInsetsSupplier = insetsSupplier;\n            mOnInsetsRequestedListener = onInsetsRequestedListener;\n            mDirectory = new File(getCanonicalDirPath(directory));\n            if (!isAllowedInternalStorageDir(context)) {\n                throw new IllegalArgumentException(\"The given directory \\\"\" + directory\n                        + \"\\\" doesn't exist under an allowed app internal storage directory\");\n            }\n            mShell = APatchCliKt.createRootShell(true);\n        } catch (IOException e) {\n            throw new IllegalArgumentException(\n                    \"Failed to resolve the canonical path for the given directory: \"\n                            + directory.getPath(), e);\n        }\n    }\n\n    private boolean isAllowedInternalStorageDir(@NonNull Context context) throws IOException {\n        String dir = getCanonicalDirPath(mDirectory);\n\n        for (String forbiddenPath : FORBIDDEN_DATA_DIRS) {\n            if (dir.startsWith(forbiddenPath)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Opens the requested file from the exposed data directory.\n     * <p>\n     * The matched prefix path used shouldn't be a prefix of a real web path. Thus, if the\n     * requested file cannot be found or is outside the mounted directory a\n     * {@link WebResourceResponse} object with a {@code null} {@link InputStream} will be\n     * returned instead of {@code null}. This saves the time of falling back to network and\n     * trying to resolve a path that doesn't exist. A {@link WebResourceResponse} with\n     * {@code null} {@link InputStream} will be received as an HTTP response with status code\n     * {@code 404} and no body.\n     * <p class=\"note\">\n     * The MIME type for the file will be determined from the file's extension using\n     * {@link java.net.URLConnection#guessContentTypeFromName}. Developers should ensure that\n     * files are named using standard file extensions. If the file does not have a\n     * recognised extension, {@code \"text/plain\"} will be used by default.\n     *\n     * @param path the suffix path to be handled.\n     * @return {@link WebResourceResponse} for the requested file.\n     */\n    @Override\n    @WorkerThread\n    @NonNull\n    public WebResourceResponse handle(@NonNull String path) {\n        if (\"internal/insets.css\".equals(path)) {\n            mOnInsetsRequestedListener.onInsetsRequested(true);\n            String css = mInsetsSupplier.get().getCss();\n            return new WebResourceResponse(\n                    \"text/css\",\n                    \"utf-8\",\n                    new ByteArrayInputStream(css.getBytes(StandardCharsets.UTF_8))\n            );\n        }\n        if (\"internal/colors.css\".equals(path)) {\n            String css = MonetColorsProvider.INSTANCE.getColorsCss();\n            return new WebResourceResponse(\n                    \"text/css\",\n                    \"utf-8\",\n                    new ByteArrayInputStream(css.getBytes(StandardCharsets.UTF_8))\n            );\n        }\n        try {\n            File file = getCanonicalFileIfChild(mDirectory, path);\n            if (file != null) {\n                InputStream is = openFile(file, mShell);\n                String mimeType = guessMimeType(path);\n                return new WebResourceResponse(mimeType, null, is);\n            } else {\n                Log.e(TAG, String.format(\n                        \"The requested file: %s is outside the mounted directory: %s\", path,\n                        mDirectory));\n            }\n        } catch (IOException e) {\n            Log.e(TAG, \"Error opening the requested path: \" + path, e);\n        }\n        return new WebResourceResponse(null, null, null);\n    }\n\n    public static String getCanonicalDirPath(@NonNull File file) throws IOException {\n        String canonicalPath = file.getCanonicalPath();\n        if (!canonicalPath.endsWith(\"/\")) canonicalPath += \"/\";\n        return canonicalPath;\n    }\n\n    public static File getCanonicalFileIfChild(@NonNull File parent, @NonNull String child)\n            throws IOException {\n        String parentCanonicalPath = getCanonicalDirPath(parent);\n        String childCanonicalPath = new File(parent, child).getCanonicalPath();\n        if (childCanonicalPath.startsWith(parentCanonicalPath)) {\n            return new File(childCanonicalPath);\n        }\n        return null;\n    }\n\n    @NonNull\n    private static InputStream handleSvgzStream(@NonNull String path,\n                                                @NonNull InputStream stream) throws IOException {\n        return path.endsWith(\".svgz\") ? new GZIPInputStream(stream) : stream;\n    }\n\n    public static InputStream openFile(@NonNull File file, @NonNull Shell shell) throws FileNotFoundException,\n            IOException {\n        SuFile suFile = new SuFile(file.getAbsolutePath());\n        suFile.setShell(shell);\n        InputStream fis = SuFileInputStream.open(suFile);\n        return handleSvgzStream(file.getPath(), fis);\n    }\n\n    /**\n     * Use {@link MimeUtil#getMimeFromFileName} to guess MIME type or return the\n     * {@link #DEFAULT_MIME_TYPE} if it can't guess.\n     *\n     * @param filePath path of the file to guess its MIME type.\n     * @return MIME type guessed from file extension or {@link #DEFAULT_MIME_TYPE}.\n     */\n    @NonNull\n    public static String guessMimeType(@NonNull String filePath) {\n        String mimeType = MimeUtil.getMimeFromFileName(filePath);\n        return mimeType == null ? DEFAULT_MIME_TYPE : mimeType;\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/ui/webui/WebViewInterface.kt",
    "content": "package me.bmax.apatch.ui.webui\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.pm.ApplicationInfo\nimport android.os.Handler\nimport android.os.Looper\nimport android.text.TextUtils\nimport android.view.Window\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebView\nimport android.widget.Toast\nimport androidx.core.content.pm.PackageInfoCompat\nimport androidx.core.view.WindowInsetsCompat\nimport androidx.core.view.WindowInsetsControllerCompat\nimport com.topjohnwu.superuser.CallbackList\nimport com.topjohnwu.superuser.ShellUtils\nimport com.topjohnwu.superuser.internal.UiThreadHandler\nimport me.bmax.apatch.ui.WebUIActivity\nimport me.bmax.apatch.ui.viewmodel.SuperUserViewModel\nimport me.bmax.apatch.util.createRootShell\nimport org.json.JSONArray\nimport org.json.JSONObject\nimport java.util.concurrent.CompletableFuture\n\nclass WebViewInterface(val context: Context, private val webView: WebView) {\n    @JavascriptInterface\n    fun exec(cmd: String): String {\n        val shell = createRootShell()\n        return ShellUtils.fastCmd(shell, cmd)\n    }\n\n    @JavascriptInterface\n    fun exec(cmd: String, callbackFunc: String) {\n        exec(cmd, null, callbackFunc)\n    }\n\n    private fun processOptions(sb: StringBuilder, options: String?) {\n        val opts = if (options == null) JSONObject() else {\n            JSONObject(options)\n        }\n\n        val cwd = opts.optString(\"cwd\")\n        if (!TextUtils.isEmpty(cwd)) {\n            sb.append(\"cd ${cwd};\")\n        }\n\n        opts.optJSONObject(\"env\")?.let { env ->\n            env.keys().forEach { key ->\n                sb.append(\"export ${key}=${env.getString(key)};\")\n            }\n        }\n    }\n\n    @JavascriptInterface\n    fun exec(\n        cmd: String, options: String?, callbackFunc: String\n    ) {\n        val finalCommand = StringBuilder()\n        processOptions(finalCommand, options)\n        finalCommand.append(cmd)\n\n        val shell = createRootShell()\n        val result = shell.newJob().add(finalCommand.toString()).to(ArrayList(), ArrayList()).exec()\n        val stdout = result.out.joinToString(separator = \"\\n\")\n        val stderr = result.err.joinToString(separator = \"\\n\")\n\n        val jsCode = \"javascript: (function() { try { ${callbackFunc}(${result.code}, ${\n            JSONObject.quote(\n                stdout\n            )\n        }, ${JSONObject.quote(stderr)}); } catch(e) { console.error(e); } })();\"\n        webView.post {\n            webView.loadUrl(jsCode)\n        }\n    }\n\n    @JavascriptInterface\n    fun spawn(command: String, args: String, options: String?, callbackFunc: String) {\n        val finalCommand = StringBuilder()\n\n        processOptions(finalCommand, options)\n\n        if (!TextUtils.isEmpty(args)) {\n            finalCommand.append(command).append(\" \")\n            JSONArray(args).let { argsArray ->\n                for (i in 0 until argsArray.length()) {\n                    finalCommand.append(argsArray.getString(i))\n                    finalCommand.append(\" \")\n                }\n            }\n        } else {\n            finalCommand.append(command)\n        }\n\n        val shell = createRootShell()\n\n        val emitData = fun(name: String, data: String) {\n            val jsCode = \"javascript: (function() { try { ${callbackFunc}.${name}.emit('data', ${\n                JSONObject.quote(\n                    data\n                )\n            }); } catch(e) { console.error('emitData', e); } })();\"\n            webView.post {\n                webView.loadUrl(jsCode)\n            }\n        }\n\n        val stdout = object : CallbackList<String>(UiThreadHandler::runAndWait) {\n            override fun onAddElement(s: String) {\n                emitData(\"stdout\", s)\n            }\n        }\n\n        val stderr = object : CallbackList<String>(UiThreadHandler::runAndWait) {\n            override fun onAddElement(s: String) {\n                emitData(\"stderr\", s)\n            }\n        }\n\n        val future = shell.newJob().add(finalCommand.toString()).to(stdout, stderr).enqueue()\n        val completableFuture = CompletableFuture.supplyAsync {\n            future.get()\n        }\n\n        completableFuture.thenAccept { result ->\n            val emitExitCode =\n                \"javascript: (function() { try { ${callbackFunc}.emit('exit', ${result.code}); } catch(e) { console.error(`emitExit error: \\${e}`); } })();\"\n            webView.post {\n                webView.loadUrl(emitExitCode)\n            }\n\n            if (result.code != 0) {\n                val emitErrCode =\n                    \"javascript: (function() { try { var err = new Error(); err.exitCode = ${result.code}; err.message = ${\n                        JSONObject.quote(\n                            result.err.joinToString(\n                                \"\\n\"\n                            )\n                        )\n                    };${callbackFunc}.emit('error', err); } catch(e) { console.error('emitErr', e); } })();\"\n                webView.post {\n                    webView.loadUrl(emitErrCode)\n                }\n            }\n        }\n    }\n\n    @JavascriptInterface\n    fun toast(msg: String) {\n        webView.post {\n            Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()\n        }\n    }\n\n    @JavascriptInterface\n    fun fullScreen(enable: Boolean) {\n        if (context is Activity) {\n            Handler(Looper.getMainLooper()).post {\n                if (enable) {\n                    hideSystemUI(context.window)\n                } else {\n                    showSystemUI(context.window)\n                }\n            }\n        }\n        enableInsets(enable)\n    }\n\n    @JavascriptInterface\n    fun enableInsets(enable: Boolean = true) {\n        if (context is WebUIActivity) {\n            context.enableInsets(enable)\n        }\n    }\n\n    @JavascriptInterface\n    fun listPackages(type: String): String {\n        val packageNames = SuperUserViewModel.apps\n            .filter { appInfo ->\n                val flags = appInfo.packageInfo.applicationInfo?.flags ?: 0\n                when (type.lowercase()) {\n                    \"system\" -> (flags and ApplicationInfo.FLAG_SYSTEM) != 0\n                    \"user\" -> (flags and ApplicationInfo.FLAG_SYSTEM) == 0\n                    else -> true\n                }\n            }\n            .map { it.packageName }\n            .sorted()\n\n        val jsonArray = JSONArray()\n        for (pkgName in packageNames) {\n            jsonArray.put(pkgName)\n        }\n        return jsonArray.toString()\n    }\n\n    @JavascriptInterface\n    fun getPackagesInfo(packageNamesJson: String): String {\n        val packageNames = JSONArray(packageNamesJson)\n        val jsonArray = JSONArray()\n        val appMap = SuperUserViewModel.apps.associateBy { it.packageName }\n        for (i in 0 until packageNames.length()) {\n            val pkgName = packageNames.getString(i)\n            val appInfo = appMap[pkgName]\n            if (appInfo != null) {\n                val pkg = appInfo.packageInfo\n                val app = pkg.applicationInfo\n                val obj = JSONObject()\n                obj.put(\"packageName\", pkg.packageName)\n                obj.put(\"versionName\", pkg.versionName ?: \"\")\n                obj.put(\"versionCode\", PackageInfoCompat.getLongVersionCode(pkg))\n                obj.put(\"appLabel\", appInfo.label)\n                obj.put(\"isSystem\", if (app != null) ((app.flags and ApplicationInfo.FLAG_SYSTEM) != 0) else JSONObject.NULL)\n                obj.put(\"uid\", app?.uid ?: JSONObject.NULL)\n                jsonArray.put(obj)\n            } else {\n                val obj = JSONObject()\n                obj.put(\"packageName\", pkgName)\n                obj.put(\"error\", \"Package not found or inaccessible\")\n                jsonArray.put(obj)\n            }\n        }\n        return jsonArray.toString()\n    }\n}\n\nfun hideSystemUI(window: Window) {\n    WindowInsetsControllerCompat(window, window.decorView).let { controller ->\n        controller.hide(WindowInsetsCompat.Type.systemBars())\n        controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE\n    }\n}\n\nfun showSystemUI(window: Window) =\n    WindowInsetsControllerCompat(window, window.decorView).show(WindowInsetsCompat.Type.systemBars())"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/APatchCli.kt",
    "content": "package me.bmax.apatch.util\n\nimport android.content.ContentResolver\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.content.pm.Signature\nimport android.database.Cursor\nimport android.net.Uri\nimport android.os.Build\nimport android.provider.OpenableColumns\nimport android.util.Base64\nimport android.util.Log\nimport com.topjohnwu.superuser.CallbackList\nimport com.topjohnwu.superuser.Shell\nimport com.topjohnwu.superuser.ShellUtils\nimport com.topjohnwu.superuser.internal.MainShell\nimport com.topjohnwu.superuser.io.SuFile\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.APApplication.Companion.SUPERCMD\nimport me.bmax.apatch.BuildConfig\nimport me.bmax.apatch.apApp\nimport me.bmax.apatch.ui.screen.MODULE_TYPE\nimport java.io.File\nimport java.security.MessageDigest\nimport java.security.cert.CertificateFactory\nimport java.security.cert.X509Certificate\nimport java.util.Properties\nimport java.util.zip.ZipFile\n\nprivate const val TAG = \"APatchCli\"\n\nprivate fun getKPatchPath(): String {\n    return apApp.applicationInfo.nativeLibraryDir + File.separator + \"libkpatch.so\"\n}\n\nclass RootShellInitializer : Shell.Initializer() {\n    override fun onInit(context: Context, shell: Shell): Boolean {\n        shell.newJob().add(\"export PATH=\\$PATH:/system_ext/bin:/vendor/bin\").exec()\n        return true\n    }\n}\n\nfun createRootShell(globalMnt: Boolean = false): Shell {\n    Shell.enableVerboseLogging = BuildConfig.DEBUG\n    val builder = Shell.Builder.create().setInitializers(RootShellInitializer::class.java)\n    return try {\n        builder.build(\n            SUPERCMD, APApplication.superKey, \"-Z\", APApplication.MAGISK_SCONTEXT\n        )\n    } catch (e: Throwable) {\n        Log.e(TAG, \"su failed: \", e)\n        return try {\n            Log.e(TAG, \"retry compat kpatch su\")\n            if (globalMnt) {\n                builder.build(\n                    getKPatchPath(), APApplication.superKey, \"su\", \"-Z\", APApplication.MAGISK_SCONTEXT, \"--mount-master\"\n                )\n            }else{\n                builder.build(\n                    getKPatchPath(), APApplication.superKey, \"su\", \"-Z\", APApplication.MAGISK_SCONTEXT\n                )\n            }\n        } catch (e: Throwable) {\n            Log.e(TAG, \"retry kpatch su failed: \", e)\n            return try {\n                Log.e(TAG, \"retry su: \", e)\n                if (globalMnt) {\n                    builder.build(\"su\",\"-mm\")\n                }else{\n                    builder.build(\"su\")\n                }\n            } catch (e: Throwable) {\n                Log.e(TAG, \"retry su failed: \", e)\n                return builder.build(\"sh\")\n            }\n        }\n    }\n}\n\nprivate fun createMainRootShell() : Shell {\n    val builder = Shell.Builder.create()\n        .setInitializers(RootShellInitializer::class.java)\n        .setCommands(SUPERCMD, APApplication.superKey, \"-Z\", APApplication.MAGISK_SCONTEXT)\n    val shell = try {\n        builder.build()\n    } catch (e: Throwable) {\n        Log.e(TAG, \"su failed: \", e)\n        builder.setCommands(getKPatchPath(), APApplication.superKey, \"su\", \"-Z\", APApplication.MAGISK_SCONTEXT)\n        try {\n            builder.build()\n        } catch (e: Throwable) {\n            Log.e(TAG, \"retry kpatch su failed: \", e)\n            builder.setCommands(\"su\")\n            try {\n                builder.build()\n            } catch (e: Throwable) {\n                Log.e(TAG, \"retry su failed: \", e)\n                builder.setCommands(\"sh\")\n                builder.build()\n            }\n        }\n    }\n\n    MainShell.setBuilder(builder)\n    return shell\n}\n\nobject APatchCli {\n    var SHELL: Shell = createMainRootShell()\n    val GLOBAL_MNT_SHELL: Shell = createRootShell(true)\n    fun refresh() {\n        val tmp = SHELL\n\n        val clazz = MainShell::class.java // reset MainShell\n        clazz.getDeclaredField(\"isInitMain\").apply {\n            isAccessible = true\n            setBoolean(null, false)\n            isAccessible = false\n        }\n\n        clazz.getDeclaredField(\"mainShell\").apply {\n            isAccessible = true\n            @Suppress(\"UNCHECKED_CAST\")\n            val arr = get(null) as Array<Any?>\n            arr[0] = null\n            isAccessible = false\n        }\n\n        clazz.getDeclaredField(\"mainBuilder\").apply {\n            isAccessible = true\n            set(null, null)\n            isAccessible = false\n        }\n\n        SHELL = createMainRootShell()\n        tmp.close()\n    }\n}\n\nfun getRootShell(globalMnt: Boolean = false): Shell {\n\n    return if (globalMnt) APatchCli.GLOBAL_MNT_SHELL else {\n        APatchCli.SHELL\n    }\n}\n\ninline fun <T> withNewRootShell(\n    globalMnt: Boolean = false,\n    block: Shell.() -> T\n): T {\n    return createRootShell(globalMnt).use(block)\n}\n\nfun rootAvailable(): Boolean {\n    val shell = getRootShell()\n    return shell.isRoot\n}\n\nfun tryGetRootShell(): Shell {\n    Shell.enableVerboseLogging = BuildConfig.DEBUG\n    val builder = Shell.Builder.create()\n    return try {\n        builder.build(\n            SUPERCMD, APApplication.superKey, \"-Z\", APApplication.MAGISK_SCONTEXT\n        )\n    } catch (e: Throwable) {\n        Log.e(TAG, \"su failed: \", e)\n        return try {\n            Log.e(TAG, \"retry compat kpatch su\")\n            builder.build(\n                getKPatchPath(), APApplication.superKey, \"su\", \"-Z\", APApplication.MAGISK_SCONTEXT\n            )\n        } catch (e: Throwable) {\n            Log.e(TAG, \"retry kpatch su failed: \", e)\n            return try {\n                Log.e(TAG, \"retry su: \", e)\n                builder.build(\"su\")\n            } catch (e: Throwable) {\n                Log.e(TAG, \"retry su failed: \", e)\n                builder.build(\"sh\")\n            }\n        }\n    }\n}\n\nfun shellForResult(shell: Shell, vararg cmds: String): Shell.Result {\n    val out = ArrayList<String>()\n    val err = ArrayList<String>()\n    return shell.newJob().add(*cmds).to(out, err).exec()\n}\n\nfun rootShellForResult(vararg cmds: String): Shell.Result {\n    val out = ArrayList<String>()\n    val err = ArrayList<String>()\n    return getRootShell().newJob().add(*cmds).to(out, err).exec()\n}\n\nfun execApd(args: String, newShell: Boolean = false): Boolean {\n    return if (newShell) {\n        withNewRootShell {\n            ShellUtils.fastCmdResult(this, \"${APApplication.APD_PATH} $args\")\n        }\n    } else {\n        ShellUtils.fastCmdResult(getRootShell(), \"${APApplication.APD_PATH} $args\")\n    }\n}\n\nfun listModules(): String {\n    val shell = getRootShell()\n    val out =\n        shell.newJob().add(\"${APApplication.APD_PATH} module list\").to(ArrayList(), null).exec().out\n    withNewRootShell{\n       newJob().add(\"cp /data/user/*/me.bmax.apatch/patch/ori.img /data/adb/ap/ && rm /data/user/*/me.bmax.apatch/patch/ori.img\")\n       .to(ArrayList(),null).exec()\n   }\n    return out.joinToString(\"\\n\").ifBlank { \"[]\" }\n}\n\nfun hasMetaModule(): Boolean {\n    return getMetaModuleImplement() != \"None\"\n}\n\nfun getMetaModuleImplement(): String {\n    try {\n        val metaModuleProp = SuFile.open(\"/data/adb/metamodule/module.prop\")\n        if (!metaModuleProp.isFile) {\n            Log.i(TAG, \"Meta module implement: None\")\n            return \"None\"\n        }\n\n        val prop = Properties()\n        prop.load(metaModuleProp.newInputStream())\n\n        val name = prop.getProperty(\"name\")\n        Log.i(TAG, \"Meta module implement: $name\")\n        return name\n    } catch (t : Throwable) {\n        Log.i(TAG, \"Meta module implement: None\")\n        return \"None\"\n    }\n}\n\nfun toggleModule(id: String, enable: Boolean): Boolean {\n    val cmd = if (enable) {\n        \"module enable $id\"\n    } else {\n        \"module disable $id\"\n    }\n    val result = execApd(cmd,true)\n    Log.i(TAG, \"$cmd result: $result\")\n    return result\n}\n\nfun uninstallModule(id: String): Boolean {\n    val cmd = \"module uninstall $id\"\n    val result = execApd(cmd,true)\n    Log.i(TAG, \"uninstall module $id result: $result\")\n    return result\n}\n\nfun installModule(\n    uri: Uri, type: MODULE_TYPE, onFinish: (Boolean) -> Unit, onStdout: (String) -> Unit, onStderr: (String) -> Unit\n): Boolean {\n    val resolver = apApp.contentResolver\n    with(resolver.openInputStream(uri)) {\n        val file = File(apApp.cacheDir, \"module_$type.zip\")\n        file.outputStream().use { output ->\n            this?.copyTo(output)\n        }\n\n        val stdoutCallback: CallbackList<String?> = object : CallbackList<String?>() {\n            override fun onAddElement(s: String?) {\n                onStdout(s ?: \"\")\n            }\n        }\n\n        val stderrCallback: CallbackList<String?> = object : CallbackList<String?>() {\n            override fun onAddElement(s: String?) {\n                onStderr(s ?: \"\")\n            }\n        }\n\n        val shell = getRootShell()\n\n        var result = false\n        if(type == MODULE_TYPE.APM) {\n            val cmd = \"${APApplication.APD_PATH} module install ${file.absolutePath}\"\n            result = shell.newJob().add(cmd).to(stdoutCallback, stderrCallback)\n                    .exec().isSuccess\n        } else {\n//            ZipUtils.\n        }\n\n        Log.i(TAG, \"install $type module $uri result: $result\")\n\n        file.delete()\n\n        onFinish(result)\n        return result\n    }\n}\n\nfun runAPModuleAction(\n    moduleId: String, onStdout: (String) -> Unit, onStderr: (String) -> Unit\n): Boolean {\n    val stdoutCallback: CallbackList<String?> = object : CallbackList<String?>() {\n        override fun onAddElement(s: String?) {\n            onStdout(s ?: \"\")\n        }\n    }\n\n    val stderrCallback: CallbackList<String?> = object : CallbackList<String?>() {\n        override fun onAddElement(s: String?) {\n            onStderr(s ?: \"\")\n        }\n    }\n\n    val result = withNewRootShell{ \n        newJob().add(\"${APApplication.APD_PATH} module action $moduleId\")\n        .to(stdoutCallback, stderrCallback).exec()\n    }\n    Log.i(TAG, \"APModule runAction result: $result\")\n\n    return result.isSuccess\n}\n\nfun reboot(reason: String = \"\") {\n    if (reason == \"recovery\") {\n        // KEYCODE_POWER = 26, hide incorrect \"Factory data reset\" message\n        getRootShell().newJob().add(\"/system/bin/input keyevent 26\").exec()\n    }\n    getRootShell().newJob()\n        .add(\"/system/bin/svc power reboot $reason || /system/bin/reboot $reason\").exec()\n}\n\nfun hasMagisk(): Boolean {\n    val shell = getRootShell()\n    val result = shell.newJob().add(\"nsenter --mount=/proc/1/ns/mnt which magisk\").exec()\n    Log.i(TAG, \"has magisk: ${result.isSuccess}\")\n    return result.isSuccess\n}\n\nfun isGlobalNamespaceEnabled(): Boolean {\n    val shell = getRootShell()\n    val result = ShellUtils.fastCmd(shell, \"cat ${APApplication.GLOBAL_NAMESPACE_FILE}\")\n    Log.i(TAG, \"is global namespace enabled: $result\")\n    return result == \"1\"\n}\n\nfun setGlobalNamespaceEnabled(value: String) {\n    getRootShell().newJob().add(\"echo $value > ${APApplication.GLOBAL_NAMESPACE_FILE}\")\n        .submit { result ->\n            Log.i(TAG, \"setGlobalNamespaceEnabled result: ${result.isSuccess} [${result.out}]\")\n        }\n}\n\nfun getFileNameFromUri(context: Context, uri: Uri): String? {\n    var fileName: String? = null\n    val contentResolver: ContentResolver = context.contentResolver\n    val cursor: Cursor? = contentResolver.query(uri, null, null, null, null)\n    cursor?.use {\n        if (it.moveToFirst()) {\n            fileName = it.getString(it.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))\n        }\n    }\n    return fileName\n}\n\n@Suppress(\"DEPRECATION\")\nprivate fun signatureFromAPI(context: Context): ByteArray? {\n    return try {\n        val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            context.packageManager.getPackageInfo(\n                context.packageName, PackageManager.GET_SIGNING_CERTIFICATES\n            )\n        } else {\n            context.packageManager.getPackageInfo(\n                context.packageName,\n                PackageManager.GET_SIGNATURES\n            )\n        }\n\n        val signatures: Array<out Signature>? =\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                packageInfo.signingInfo?.apkContentsSigners\n            } else {\n                packageInfo.signatures\n            }\n\n        signatures?.firstOrNull()?.toByteArray()\n    } catch (e: Exception) {\n        e.printStackTrace()\n        null\n    }\n}\n\nprivate fun signatureFromAPK(context: Context): ByteArray? {\n    var signatureBytes: ByteArray? = null\n    try {\n        ZipFile(context.packageResourcePath).use { zipFile ->\n            val entries = zipFile.entries()\n            while (entries.hasMoreElements() && signatureBytes == null) {\n                val entry = entries.nextElement()\n                if (entry.name.matches(\"(META-INF/.*)\\\\.(RSA|DSA|EC)\".toRegex())) {\n                    zipFile.getInputStream(entry).use { inputStream ->\n                        val certFactory = CertificateFactory.getInstance(\"X509\")\n                        val x509Cert =\n                            certFactory.generateCertificate(inputStream) as X509Certificate\n                        signatureBytes = x509Cert.encoded\n                    }\n                }\n            }\n        }\n    } catch (e: Exception) {\n        e.printStackTrace()\n    }\n    return signatureBytes\n}\n\nprivate fun validateSignature(signatureBytes: ByteArray?, validSignature: String): Boolean {\n    signatureBytes ?: return false\n    val digest = MessageDigest.getInstance(\"SHA-256\")\n    val signatureHash = Base64.encodeToString(digest.digest(signatureBytes), Base64.NO_WRAP)\n    return signatureHash == validSignature\n}\n\nfun verifyAppSignature(validSignature: String): Boolean {\n    val context = apApp.applicationContext\n    val apkSignature = signatureFromAPK(context)\n    val apiSignature = signatureFromAPI(context)\n\n    return validateSignature(apiSignature, validSignature) && validateSignature(\n        apkSignature,\n        validSignature\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/APatchKeyHelper.java",
    "content": "package me.bmax.apatch.util;\n\nimport android.content.SharedPreferences;\nimport android.security.keystore.KeyGenParameterSpec;\nimport android.security.keystore.KeyProperties;\nimport android.util.Base64;\nimport android.util.Log;\n\nimport java.nio.charset.StandardCharsets;\nimport java.security.KeyStore;\nimport java.security.SecureRandom;\nimport java.security.spec.AlgorithmParameterSpec;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.GCMParameterSpec;\n\n\npublic class APatchKeyHelper {\n    protected static final String SUPER_KEY = \"super_key\";\n    protected static final String SUPER_KEY_ENC = \"super_key_enc\";\n    private static final String TAG = \"APatchSecurityHelper\";\n    private static final String ANDROID_KEYSTORE = \"AndroidKeyStore\";\n    private static final String SKIP_STORE_SUPER_KEY = \"skip_store_super_key\";\n    private static final String SUPER_KEY_IV = \"super_key_iv\";\n    private static final String KEY_ALIAS = \"APatchSecurityKey\";\n    private static final String ENCRYPT_MODE = \"AES/GCM/NoPadding\";\n    private static SharedPreferences prefs = null;\n\n    static {\n        try {\n            KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);\n            keyStore.load(null);\n            if (!keyStore.containsAlias(KEY_ALIAS)) {\n                generateSecretKey();\n            }\n        } catch (Exception e) {\n            Log.e(TAG, \"Failed to checkAndGenerateSecretKey\", e);\n        }\n    }\n\n    public static void setSharedPreferences(SharedPreferences sp) {\n        prefs = sp;\n    }\n\n    private static void generateSecretKey() {\n        try {\n            KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);\n            keyStore.load(null);\n\n            if (!keyStore.containsAlias(KEY_ALIAS)) {\n                KeyGenerator keyGenerator = KeyGenerator.getInstance(\n                        KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE);\n\n                AlgorithmParameterSpec spec = new KeyGenParameterSpec.Builder(\n                        KEY_ALIAS,\n                        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)\n                        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)\n                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)\n                        .setRandomizedEncryptionRequired(false)\n                        .build();\n\n                keyGenerator.init(spec);\n                keyGenerator.generateKey();\n            }\n        } catch (Exception e) {\n            Log.e(TAG, \"Failed to generateSecretKey\", e);\n        }\n    }\n\n    private static String getRandomIV() {\n        String randIV = prefs.getString(SUPER_KEY_IV, null);\n        if (randIV == null) {\n            SecureRandom secureRandom = new SecureRandom();\n            byte[] generated = secureRandom.generateSeed(12);\n            randIV = Base64.encodeToString(generated, Base64.DEFAULT);\n            prefs.edit().putString(SUPER_KEY_IV, randIV).apply();\n        }\n        return randIV;\n    }\n\n    private static String encrypt(String orig) {\n        try {\n            KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);\n            keyStore.load(null);\n            SecretKey secretKey = (SecretKey) keyStore.getKey(KEY_ALIAS, null);\n\n            Cipher cipher = Cipher.getInstance(ENCRYPT_MODE);\n            cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(128, Base64.decode(getRandomIV(), Base64.DEFAULT)));\n\n            return Base64.encodeToString(cipher.doFinal(orig.getBytes(StandardCharsets.UTF_8)), Base64.DEFAULT);\n        } catch (Exception e) {\n            Log.e(TAG, \"Failed to encrypt: \", e);\n            return null;\n        }\n    }\n\n    private static String decrypt(String encryptedData) {\n        try {\n            KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);\n            keyStore.load(null);\n            SecretKey secretKey = (SecretKey) keyStore.getKey(KEY_ALIAS, null);\n\n            Cipher cipher = Cipher.getInstance(ENCRYPT_MODE);\n            cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, Base64.decode(getRandomIV(), Base64.DEFAULT)));\n\n            return new String(cipher.doFinal(Base64.decode(encryptedData, Base64.DEFAULT)), StandardCharsets.UTF_8);\n        } catch (Exception e) {\n            Log.e(TAG, \"Failed to decrypt\", e);\n            return null;\n        }\n    }\n\n    public static boolean shouldSkipStoreSuperKey() {\n        return prefs.getInt(SKIP_STORE_SUPER_KEY, 0) != 0;\n    }\n\n    public static void clearConfigKey() {\n        prefs.edit().remove(SUPER_KEY).apply();\n        prefs.edit().remove(SUPER_KEY_ENC).apply();\n        prefs.edit().remove(SUPER_KEY_IV).apply();\n    }\n\n    public static void setShouldSkipStoreSuperKey(boolean should) {\n        clearConfigKey();\n        prefs.edit().putInt(SKIP_STORE_SUPER_KEY, should ? 1 : 0).apply();\n    }\n\n    public static String readSPSuperKey() {\n        String encKey = prefs.getString(SUPER_KEY_ENC, \"\");\n        if (!encKey.isEmpty()) {\n            return decrypt(encKey);\n        }\n\n        @Deprecated()\n        String key = prefs.getString(SUPER_KEY, \"\");\n        writeSPSuperKey(key);\n        prefs.edit().remove(SUPER_KEY).apply();\n        return key;\n    }\n\n    public static void writeSPSuperKey(String key) {\n        if (shouldSkipStoreSuperKey()) return;\n        key = APatchKeyHelper.encrypt(key);\n        prefs.edit().putString(SUPER_KEY_ENC, key).apply();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/DeviceInfoUtils.kt",
    "content": "package me.bmax.apatch.util\n\nimport android.util.Log\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.res.stringResource\nimport com.topjohnwu.superuser.Shell\nimport me.bmax.apatch.R\n\n@Composable\nfun getSELinuxStatus(): String {\n    val shell = Shell.Builder.create()\n        .build(\"sh\")\n\n    val list = ArrayList<String>()\n    val result = shell.newJob().add(\"getenforce\").to(list, list).exec()\n    val output = result.out.joinToString(\"\\n\").trim()\n\n    if (result.isSuccess) {\n        return when (output) {\n            \"Enforcing\" -> stringResource(R.string.home_selinux_status_enforcing)\n            \"Permissive\" -> stringResource(R.string.home_selinux_status_permissive)\n            \"Disabled\" -> stringResource(R.string.home_selinux_status_disabled)\n            else -> stringResource(R.string.home_selinux_status_unknown)\n        }\n    }\n\n    return if (output.endsWith(\"Permission denied\")) {\n        stringResource(R.string.home_selinux_status_enforcing)\n    } else {\n        stringResource(R.string.home_selinux_status_unknown)\n    }\n}\n\nprivate fun getSystemProperty(key: String): Boolean {\n    try {\n        val c = Class.forName(\"android.os.SystemProperties\")\n        val get = c.getMethod(\n            \"getBoolean\",\n            String::class.java,\n            Boolean::class.javaPrimitiveType\n        )\n        return get.invoke(c, key, false) as Boolean\n    } catch (e: Exception) {\n        Log.e(\"APatch\", \"[DeviceUtils] Failed to get system property: \", e)\n    }\n    return false\n}\n\n// Check to see if device supports A/B (seamless) system updates\nfun isABDevice(): Boolean {\n    return getSystemProperty(\"ro.build.ab_update\")\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/Downloader.kt",
    "content": "package me.bmax.apatch.util\n\nimport android.annotation.SuppressLint\nimport android.app.DownloadManager\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.net.Uri\nimport android.os.Environment\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.DisposableEffect\nimport androidx.core.net.toUri\nimport me.bmax.apatch.apApp\nimport androidx.core.content.ContextCompat\n\n@SuppressLint(\"Range\")\nfun download(\n    context: Context,\n    url: String,\n    fileName: String,\n    description: String,\n    onDownloaded: (Uri) -> Unit = {},\n    onDownloading: () -> Unit = {}\n) {\n    val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager\n    val query = DownloadManager.Query()\n\n    query.setFilterByStatus(DownloadManager.STATUS_RUNNING or DownloadManager.STATUS_PAUSED or DownloadManager.STATUS_PENDING)\n    downloadManager.query(query)?.use { cursor ->\n        while (cursor.moveToNext()) {\n            val uri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_URI))\n            val localUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))\n            val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))\n            val columnTitle = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE))\n            if (url == uri || fileName == columnTitle) {\n                if (status == DownloadManager.STATUS_RUNNING || status == DownloadManager.STATUS_PENDING) {\n                    onDownloading()\n                    return\n                } else if (status == DownloadManager.STATUS_SUCCESSFUL) {\n                    onDownloaded(localUri.toUri())\n                    return\n                }\n            }\n        }\n    }\n\n    val request = DownloadManager.Request(url.toUri()).setDestinationInExternalPublicDir(\n        Environment.DIRECTORY_DOWNLOADS, fileName\n    ).setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)\n        .setMimeType(\"application/zip\").setTitle(fileName).setDescription(description)\n\n    downloadManager.enqueue(request)\n}\n\nfun checkNewVersion(): LatestVersionInfo {\n    val url = \"https://api.github.com/repos/bmax121/APatch/releases/latest\"\n    val defaultValue = LatestVersionInfo()\n    runCatching {\n        apApp.okhttpClient.newCall(okhttp3.Request.Builder().url(url).build()).execute()\n            .use { response ->\n                if (!response.isSuccessful) {\n                    return defaultValue\n                }\n                val body = response.body?.string() ?: return defaultValue\n\n                val json = org.json.JSONObject(body)\n                val changelog = json.optString(\"body\")\n                val versionCode = json.getInt(\"name\")\n\n                val assets = json.getJSONArray(\"assets\")\n                for (i in 0 until assets.length()) {\n                    val asset = assets.getJSONObject(i)\n                    val name = asset.getString(\"name\")\n                    if (!name.endsWith(\".apk\")) {\n                        continue\n                    }\n                    val downloadUrl = asset.getString(\"browser_download_url\")\n\n                    return LatestVersionInfo(\n                        versionCode, downloadUrl, changelog\n                    )\n                }\n            }\n    }\n    return defaultValue\n}\n\n@Composable\nfun DownloadListener(context: Context, onDownloaded: (Uri) -> Unit) {\n    DisposableEffect(context) {\n        val receiver = object : BroadcastReceiver() {\n            @SuppressLint(\"Range\")\n            override fun onReceive(context: Context?, intent: Intent?) {\n                if (intent?.action == DownloadManager.ACTION_DOWNLOAD_COMPLETE) {\n                    val id = intent.getLongExtra(\n                        DownloadManager.EXTRA_DOWNLOAD_ID, -1\n                    )\n                    val downloadManager = context?.getSystemService(Context.DOWNLOAD_SERVICE) as? DownloadManager\n                    val query = DownloadManager.Query().setFilterById(id)\n\n                    downloadManager?.query(query)?.use { cursor ->\n                        if (cursor.moveToFirst()) {\n                            val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))\n                            if (status == DownloadManager.STATUS_SUCCESSFUL) {\n                                val uriString = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))\n                                uriString?.toUri()?.let { onDownloaded(it) }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        val intentFilter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)\n        ContextCompat.registerReceiver(\n            context,\n            receiver,\n            intentFilter,\n            ContextCompat.RECEIVER_EXPORTED\n        )\n        onDispose {\n            context.unregisterReceiver(receiver)\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/HanziToPinyin.java",
    "content": "package me.bmax.apatch.util;\n/*\n * Copyright (C) 2009 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport java.text.Collator;\nimport java.util.ArrayList;\nimport java.util.Locale;\n\n/**\n * An object to convert Chinese character to its corresponding pinyin string. For characters with\n * multiple possible pinyin string, only one is selected according to collator. Polyphone is not\n * supported in this implementation. This class is implemented to achieve the best runtime\n * performance and minimum runtime resources with tolerable sacrifice of accuracy. This\n * implementation highly depends on zh_CN ICU collation data and must be always synchronized with\n * ICU.\n * <p>\n * Currently this file is aligned to zh.txt in ICU 4.6\n */\npublic class HanziToPinyin {\n    /**\n     * Unihans array.\n     * <p>\n     * Each unihans is the first one within same pinyin when collator is zh_CN.\n     */\n    public static final char[] UNIHANS = {\n            '\\u963f', '\\u54ce', '\\u5b89', '\\u80ae', '\\u51f9', '\\u516b',\n            '\\u6300', '\\u6273', '\\u90a6', '\\u52f9', '\\u9642', '\\u5954',\n            '\\u4f3b', '\\u5c44', '\\u8fb9', '\\u706c', '\\u618b', '\\u6c43',\n            '\\u51ab', '\\u7676', '\\u5cec', '\\u5693', '\\u5072', '\\u53c2',\n            '\\u4ed3', '\\u64a1', '\\u518a', '\\u5d7e', '\\u66fd', '\\u66fe',\n            '\\u5c64', '\\u53c9', '\\u8286', '\\u8fbf', '\\u4f25', '\\u6284',\n            '\\u8f66', '\\u62bb', '\\u6c88', '\\u6c89', '\\u9637', '\\u5403',\n            '\\u5145', '\\u62bd', '\\u51fa', '\\u6b3b', '\\u63e3', '\\u5ddb',\n            '\\u5205', '\\u5439', '\\u65fe', '\\u9034', '\\u5472', '\\u5306',\n            '\\u51d1', '\\u7c97', '\\u6c46', '\\u5d14', '\\u90a8', '\\u6413',\n            '\\u5491', '\\u5446', '\\u4e39', '\\u5f53', '\\u5200', '\\u561a',\n            '\\u6265', '\\u706f', '\\u6c10', '\\u55f2', '\\u7538', '\\u5201',\n            '\\u7239', '\\u4e01', '\\u4e1f', '\\u4e1c', '\\u543a', '\\u53be',\n            '\\u8011', '\\u8968', '\\u5428', '\\u591a', '\\u59b8', '\\u8bf6',\n            '\\u5940', '\\u97a5', '\\u513f', '\\u53d1', '\\u5e06', '\\u531a',\n            '\\u98de', '\\u5206', '\\u4e30', '\\u8985', '\\u4ecf', '\\u7d11',\n            '\\u4f15', '\\u65ee', '\\u4f85', '\\u7518', '\\u5188', '\\u768b',\n            '\\u6208', '\\u7ed9', '\\u6839', '\\u522f', '\\u5de5', '\\u52fe',\n            '\\u4f30', '\\u74dc', '\\u4e56', '\\u5173', '\\u5149', '\\u5f52',\n            '\\u4e28', '\\u5459', '\\u54c8', '\\u548d', '\\u4f44', '\\u592f',\n            '\\u8320', '\\u8bc3', '\\u9ed2', '\\u62eb', '\\u4ea8', '\\u5677',\n            '\\u53ff', '\\u9f41', '\\u4e6f', '\\u82b1', '\\u6000', '\\u72bf',\n            '\\u5ddf', '\\u7070', '\\u660f', '\\u5419', '\\u4e0c', '\\u52a0',\n            '\\u620b', '\\u6c5f', '\\u827d', '\\u9636', '\\u5dfe', '\\u5755',\n            '\\u5182', '\\u4e29', '\\u51e5', '\\u59e2', '\\u5658', '\\u519b',\n            '\\u5494', '\\u5f00', '\\u520a', '\\u5ffc', '\\u5c3b', '\\u533c',\n            '\\u808e', '\\u52a5', '\\u7a7a', '\\u62a0', '\\u625d', '\\u5938',\n            '\\u84af', '\\u5bbd', '\\u5321', '\\u4e8f', '\\u5764', '\\u6269',\n            '\\u5783', '\\u6765', '\\u5170', '\\u5577', '\\u635e', '\\u808b',\n            '\\u52d2', '\\u5d1a', '\\u5215', '\\u4fe9', '\\u5941', '\\u826f',\n            '\\u64a9', '\\u5217', '\\u62ce', '\\u5222', '\\u6e9c', '\\u56d6',\n            '\\u9f99', '\\u779c', '\\u565c', '\\u5a08', '\\u7567', '\\u62a1',\n            '\\u7f57', '\\u5463', '\\u5988', '\\u57cb', '\\u5ada', '\\u7264',\n            '\\u732b', '\\u4e48', '\\u5445', '\\u95e8', '\\u753f', '\\u54aa',\n            '\\u5b80', '\\u55b5', '\\u4e5c', '\\u6c11', '\\u540d', '\\u8c2c',\n            '\\u6478', '\\u54de', '\\u6bea', '\\u55ef', '\\u62cf', '\\u8149',\n            '\\u56e1', '\\u56d4', '\\u5b6c', '\\u7592', '\\u5a1e', '\\u6041',\n            '\\u80fd', '\\u59ae', '\\u62c8', '\\u5b22', '\\u9e1f', '\\u634f',\n            '\\u56dc', '\\u5b81', '\\u599e', '\\u519c', '\\u7fba', '\\u5974',\n            '\\u597b', '\\u759f', '\\u9ec1', '\\u90cd', '\\u5594', '\\u8bb4',\n            '\\u5991', '\\u62cd', '\\u7705', '\\u4e53', '\\u629b', '\\u5478',\n            '\\u55b7', '\\u5309', '\\u4e15', '\\u56e8', '\\u527d', '\\u6c15',\n            '\\u59d8', '\\u4e52', '\\u948b', '\\u5256', '\\u4ec6', '\\u4e03',\n            '\\u6390', '\\u5343', '\\u545b', '\\u6084', '\\u767f', '\\u4eb2',\n            '\\u72c5', '\\u828e', '\\u4e18', '\\u533a', '\\u5cd1', '\\u7f3a',\n            '\\u590b', '\\u5465', '\\u7a63', '\\u5a06', '\\u60f9', '\\u4eba',\n            '\\u6254', '\\u65e5', '\\u8338', '\\u53b9', '\\u909a', '\\u633c',\n            '\\u5827', '\\u5a51', '\\u77a4', '\\u637c', '\\u4ee8', '\\u6be2',\n            '\\u4e09', '\\u6852', '\\u63bb', '\\u95aa', '\\u68ee', '\\u50e7',\n            '\\u6740', '\\u7b5b', '\\u5c71', '\\u4f24', '\\u5f30', '\\u5962',\n            '\\u7533', '\\u8398', '\\u6552', '\\u5347', '\\u5c38', '\\u53ce',\n            '\\u4e66', '\\u5237', '\\u8870', '\\u95e9', '\\u53cc', '\\u8c01',\n            '\\u542e', '\\u8bf4', '\\u53b6', '\\u5fea', '\\u635c', '\\u82cf',\n            '\\u72fb', '\\u590a', '\\u5b59', '\\u5506', '\\u4ed6', '\\u56fc',\n            '\\u574d', '\\u6c64', '\\u5932', '\\u5fd1', '\\u71a5', '\\u5254',\n            '\\u5929', '\\u65eb', '\\u5e16', '\\u5385', '\\u56f2', '\\u5077',\n            '\\u51f8', '\\u6e4d', '\\u63a8', '\\u541e', '\\u4e47', '\\u7a75',\n            '\\u6b6a', '\\u5f2f', '\\u5c23', '\\u5371', '\\u6637', '\\u7fc1',\n            '\\u631d', '\\u4e4c', '\\u5915', '\\u8672', '\\u4eda', '\\u4e61',\n            '\\u7071', '\\u4e9b', '\\u5fc3', '\\u661f', '\\u51f6', '\\u4f11',\n            '\\u5401', '\\u5405', '\\u524a', '\\u5743', '\\u4e2b', '\\u6079',\n            '\\u592e', '\\u5e7a', '\\u503b', '\\u4e00', '\\u56d9', '\\u5e94',\n            '\\u54df', '\\u4f63', '\\u4f18', '\\u625c', '\\u56e6', '\\u66f0',\n            '\\u6655', '\\u7b60', '\\u7b7c', '\\u5e00', '\\u707d', '\\u5142',\n            '\\u5328', '\\u50ae', '\\u5219', '\\u8d3c', '\\u600e', '\\u5897',\n            '\\u624e', '\\u635a', '\\u6cbe', '\\u5f20', '\\u957f', '\\u9577',\n            '\\u4f4b', '\\u8707', '\\u8d1e', '\\u4e89', '\\u4e4b', '\\u5cd9',\n            '\\u5ea2', '\\u4e2d', '\\u5dde', '\\u6731', '\\u6293', '\\u62fd',\n            '\\u4e13', '\\u5986', '\\u96b9', '\\u5b92', '\\u5353', '\\u4e72',\n            '\\u5b97', '\\u90b9', '\\u79df', '\\u94bb', '\\u539c', '\\u5c0a',\n            '\\u6628', '\\u5159', '\\u9fc3', '\\u9fc4',};\n    /**\n     * Pinyin array.\n     * <p>\n     * Each pinyin is corresponding to unihans of same\n     * offset in the unihans array.\n     */\n    public static final byte[][] PINYINS = {\n            {65, 0, 0, 0, 0, 0}, {65, 73, 0, 0, 0, 0},\n            {65, 78, 0, 0, 0, 0}, {65, 78, 71, 0, 0, 0},\n            {65, 79, 0, 0, 0, 0}, {66, 65, 0, 0, 0, 0},\n            {66, 65, 73, 0, 0, 0}, {66, 65, 78, 0, 0, 0},\n            {66, 65, 78, 71, 0, 0}, {66, 65, 79, 0, 0, 0},\n            {66, 69, 73, 0, 0, 0}, {66, 69, 78, 0, 0, 0},\n            {66, 69, 78, 71, 0, 0}, {66, 73, 0, 0, 0, 0},\n            {66, 73, 65, 78, 0, 0}, {66, 73, 65, 79, 0, 0},\n            {66, 73, 69, 0, 0, 0}, {66, 73, 78, 0, 0, 0},\n            {66, 73, 78, 71, 0, 0}, {66, 79, 0, 0, 0, 0},\n            {66, 85, 0, 0, 0, 0}, {67, 65, 0, 0, 0, 0},\n            {67, 65, 73, 0, 0, 0}, {67, 65, 78, 0, 0, 0},\n            {67, 65, 78, 71, 0, 0}, {67, 65, 79, 0, 0, 0},\n            {67, 69, 0, 0, 0, 0}, {67, 69, 78, 0, 0, 0},\n            {67, 69, 78, 71, 0, 0}, {90, 69, 78, 71, 0, 0},\n            {67, 69, 78, 71, 0, 0}, {67, 72, 65, 0, 0, 0},\n            {67, 72, 65, 73, 0, 0}, {67, 72, 65, 78, 0, 0},\n            {67, 72, 65, 78, 71, 0}, {67, 72, 65, 79, 0, 0},\n            {67, 72, 69, 0, 0, 0}, {67, 72, 69, 78, 0, 0},\n            {83, 72, 69, 78, 0, 0}, {67, 72, 69, 78, 0, 0},\n            {67, 72, 69, 78, 71, 0}, {67, 72, 73, 0, 0, 0},\n            {67, 72, 79, 78, 71, 0}, {67, 72, 79, 85, 0, 0},\n            {67, 72, 85, 0, 0, 0}, {67, 72, 85, 65, 0, 0},\n            {67, 72, 85, 65, 73, 0}, {67, 72, 85, 65, 78, 0},\n            {67, 72, 85, 65, 78, 71}, {67, 72, 85, 73, 0, 0},\n            {67, 72, 85, 78, 0, 0}, {67, 72, 85, 79, 0, 0},\n            {67, 73, 0, 0, 0, 0}, {67, 79, 78, 71, 0, 0},\n            {67, 79, 85, 0, 0, 0}, {67, 85, 0, 0, 0, 0},\n            {67, 85, 65, 78, 0, 0}, {67, 85, 73, 0, 0, 0},\n            {67, 85, 78, 0, 0, 0}, {67, 85, 79, 0, 0, 0},\n            {68, 65, 0, 0, 0, 0}, {68, 65, 73, 0, 0, 0},\n            {68, 65, 78, 0, 0, 0}, {68, 65, 78, 71, 0, 0},\n            {68, 65, 79, 0, 0, 0}, {68, 69, 0, 0, 0, 0},\n            {68, 69, 78, 0, 0, 0}, {68, 69, 78, 71, 0, 0},\n            {68, 73, 0, 0, 0, 0}, {68, 73, 65, 0, 0, 0},\n            {68, 73, 65, 78, 0, 0}, {68, 73, 65, 79, 0, 0},\n            {68, 73, 69, 0, 0, 0}, {68, 73, 78, 71, 0, 0},\n            {68, 73, 85, 0, 0, 0}, {68, 79, 78, 71, 0, 0},\n            {68, 79, 85, 0, 0, 0}, {68, 85, 0, 0, 0, 0},\n            {68, 85, 65, 78, 0, 0}, {68, 85, 73, 0, 0, 0},\n            {68, 85, 78, 0, 0, 0}, {68, 85, 79, 0, 0, 0},\n            {69, 0, 0, 0, 0, 0}, {69, 73, 0, 0, 0, 0},\n            {69, 78, 0, 0, 0, 0}, {69, 78, 71, 0, 0, 0},\n            {69, 82, 0, 0, 0, 0}, {70, 65, 0, 0, 0, 0},\n            {70, 65, 78, 0, 0, 0}, {70, 65, 78, 71, 0, 0},\n            {70, 69, 73, 0, 0, 0}, {70, 69, 78, 0, 0, 0},\n            {70, 69, 78, 71, 0, 0}, {70, 73, 65, 79, 0, 0},\n            {70, 79, 0, 0, 0, 0}, {70, 79, 85, 0, 0, 0},\n            {70, 85, 0, 0, 0, 0}, {71, 65, 0, 0, 0, 0},\n            {71, 65, 73, 0, 0, 0}, {71, 65, 78, 0, 0, 0},\n            {71, 65, 78, 71, 0, 0}, {71, 65, 79, 0, 0, 0},\n            {71, 69, 0, 0, 0, 0}, {71, 69, 73, 0, 0, 0},\n            {71, 69, 78, 0, 0, 0}, {71, 69, 78, 71, 0, 0},\n            {71, 79, 78, 71, 0, 0}, {71, 79, 85, 0, 0, 0},\n            {71, 85, 0, 0, 0, 0}, {71, 85, 65, 0, 0, 0},\n            {71, 85, 65, 73, 0, 0}, {71, 85, 65, 78, 0, 0},\n            {71, 85, 65, 78, 71, 0}, {71, 85, 73, 0, 0, 0},\n            {71, 85, 78, 0, 0, 0}, {71, 85, 79, 0, 0, 0},\n            {72, 65, 0, 0, 0, 0}, {72, 65, 73, 0, 0, 0},\n            {72, 65, 78, 0, 0, 0}, {72, 65, 78, 71, 0, 0},\n            {72, 65, 79, 0, 0, 0}, {72, 69, 0, 0, 0, 0},\n            {72, 69, 73, 0, 0, 0}, {72, 69, 78, 0, 0, 0},\n            {72, 69, 78, 71, 0, 0}, {72, 77, 0, 0, 0, 0},\n            {72, 79, 78, 71, 0, 0}, {72, 79, 85, 0, 0, 0},\n            {72, 85, 0, 0, 0, 0}, {72, 85, 65, 0, 0, 0},\n            {72, 85, 65, 73, 0, 0}, {72, 85, 65, 78, 0, 0},\n            {72, 85, 65, 78, 71, 0}, {72, 85, 73, 0, 0, 0},\n            {72, 85, 78, 0, 0, 0}, {72, 85, 79, 0, 0, 0},\n            {74, 73, 0, 0, 0, 0}, {74, 73, 65, 0, 0, 0},\n            {74, 73, 65, 78, 0, 0}, {74, 73, 65, 78, 71, 0},\n            {74, 73, 65, 79, 0, 0}, {74, 73, 69, 0, 0, 0},\n            {74, 73, 78, 0, 0, 0}, {74, 73, 78, 71, 0, 0},\n            {74, 73, 79, 78, 71, 0}, {74, 73, 85, 0, 0, 0},\n            {74, 85, 0, 0, 0, 0}, {74, 85, 65, 78, 0, 0},\n            {74, 85, 69, 0, 0, 0}, {74, 85, 78, 0, 0, 0},\n            {75, 65, 0, 0, 0, 0}, {75, 65, 73, 0, 0, 0},\n            {75, 65, 78, 0, 0, 0}, {75, 65, 78, 71, 0, 0},\n            {75, 65, 79, 0, 0, 0}, {75, 69, 0, 0, 0, 0},\n            {75, 69, 78, 0, 0, 0}, {75, 69, 78, 71, 0, 0},\n            {75, 79, 78, 71, 0, 0}, {75, 79, 85, 0, 0, 0},\n            {75, 85, 0, 0, 0, 0}, {75, 85, 65, 0, 0, 0},\n            {75, 85, 65, 73, 0, 0}, {75, 85, 65, 78, 0, 0},\n            {75, 85, 65, 78, 71, 0}, {75, 85, 73, 0, 0, 0},\n            {75, 85, 78, 0, 0, 0}, {75, 85, 79, 0, 0, 0},\n            {76, 65, 0, 0, 0, 0}, {76, 65, 73, 0, 0, 0},\n            {76, 65, 78, 0, 0, 0}, {76, 65, 78, 71, 0, 0},\n            {76, 65, 79, 0, 0, 0}, {76, 69, 0, 0, 0, 0},\n            {76, 69, 73, 0, 0, 0}, {76, 69, 78, 71, 0, 0},\n            {76, 73, 0, 0, 0, 0}, {76, 73, 65, 0, 0, 0},\n            {76, 73, 65, 78, 0, 0}, {76, 73, 65, 78, 71, 0},\n            {76, 73, 65, 79, 0, 0}, {76, 73, 69, 0, 0, 0},\n            {76, 73, 78, 0, 0, 0}, {76, 73, 78, 71, 0, 0},\n            {76, 73, 85, 0, 0, 0}, {76, 79, 0, 0, 0, 0},\n            {76, 79, 78, 71, 0, 0}, {76, 79, 85, 0, 0, 0},\n            {76, 85, 0, 0, 0, 0}, {76, 85, 65, 78, 0, 0},\n            {76, 85, 69, 0, 0, 0}, {76, 85, 78, 0, 0, 0},\n            {76, 85, 79, 0, 0, 0}, {77, 0, 0, 0, 0, 0},\n            {77, 65, 0, 0, 0, 0}, {77, 65, 73, 0, 0, 0},\n            {77, 65, 78, 0, 0, 0}, {77, 65, 78, 71, 0, 0},\n            {77, 65, 79, 0, 0, 0}, {77, 69, 0, 0, 0, 0},\n            {77, 69, 73, 0, 0, 0}, {77, 69, 78, 0, 0, 0},\n            {77, 69, 78, 71, 0, 0}, {77, 73, 0, 0, 0, 0},\n            {77, 73, 65, 78, 0, 0}, {77, 73, 65, 79, 0, 0},\n            {77, 73, 69, 0, 0, 0}, {77, 73, 78, 0, 0, 0},\n            {77, 73, 78, 71, 0, 0}, {77, 73, 85, 0, 0, 0},\n            {77, 79, 0, 0, 0, 0}, {77, 79, 85, 0, 0, 0},\n            {77, 85, 0, 0, 0, 0}, {78, 0, 0, 0, 0, 0},\n            {78, 65, 0, 0, 0, 0}, {78, 65, 73, 0, 0, 0},\n            {78, 65, 78, 0, 0, 0}, {78, 65, 78, 71, 0, 0},\n            {78, 65, 79, 0, 0, 0}, {78, 69, 0, 0, 0, 0},\n            {78, 69, 73, 0, 0, 0}, {78, 69, 78, 0, 0, 0},\n            {78, 69, 78, 71, 0, 0}, {78, 73, 0, 0, 0, 0},\n            {78, 73, 65, 78, 0, 0}, {78, 73, 65, 78, 71, 0},\n            {78, 73, 65, 79, 0, 0}, {78, 73, 69, 0, 0, 0},\n            {78, 73, 78, 0, 0, 0}, {78, 73, 78, 71, 0, 0},\n            {78, 73, 85, 0, 0, 0}, {78, 79, 78, 71, 0, 0},\n            {78, 79, 85, 0, 0, 0}, {78, 85, 0, 0, 0, 0},\n            {78, 85, 65, 78, 0, 0}, {78, 85, 69, 0, 0, 0},\n            {78, 85, 78, 0, 0, 0}, {78, 85, 79, 0, 0, 0},\n            {79, 0, 0, 0, 0, 0}, {79, 85, 0, 0, 0, 0},\n            {80, 65, 0, 0, 0, 0}, {80, 65, 73, 0, 0, 0},\n            {80, 65, 78, 0, 0, 0}, {80, 65, 78, 71, 0, 0},\n            {80, 65, 79, 0, 0, 0}, {80, 69, 73, 0, 0, 0},\n            {80, 69, 78, 0, 0, 0}, {80, 69, 78, 71, 0, 0},\n            {80, 73, 0, 0, 0, 0}, {80, 73, 65, 78, 0, 0},\n            {80, 73, 65, 79, 0, 0}, {80, 73, 69, 0, 0, 0},\n            {80, 73, 78, 0, 0, 0}, {80, 73, 78, 71, 0, 0},\n            {80, 79, 0, 0, 0, 0}, {80, 79, 85, 0, 0, 0},\n            {80, 85, 0, 0, 0, 0}, {81, 73, 0, 0, 0, 0},\n            {81, 73, 65, 0, 0, 0}, {81, 73, 65, 78, 0, 0},\n            {81, 73, 65, 78, 71, 0}, {81, 73, 65, 79, 0, 0},\n            {81, 73, 69, 0, 0, 0}, {81, 73, 78, 0, 0, 0},\n            {81, 73, 78, 71, 0, 0}, {81, 73, 79, 78, 71, 0},\n            {81, 73, 85, 0, 0, 0}, {81, 85, 0, 0, 0, 0},\n            {81, 85, 65, 78, 0, 0}, {81, 85, 69, 0, 0, 0},\n            {81, 85, 78, 0, 0, 0}, {82, 65, 78, 0, 0, 0},\n            {82, 65, 78, 71, 0, 0}, {82, 65, 79, 0, 0, 0},\n            {82, 69, 0, 0, 0, 0}, {82, 69, 78, 0, 0, 0},\n            {82, 69, 78, 71, 0, 0}, {82, 73, 0, 0, 0, 0},\n            {82, 79, 78, 71, 0, 0}, {82, 79, 85, 0, 0, 0},\n            {82, 85, 0, 0, 0, 0}, {82, 85, 65, 0, 0, 0},\n            {82, 85, 65, 78, 0, 0}, {82, 85, 73, 0, 0, 0},\n            {82, 85, 78, 0, 0, 0}, {82, 85, 79, 0, 0, 0},\n            {83, 65, 0, 0, 0, 0}, {83, 65, 73, 0, 0, 0},\n            {83, 65, 78, 0, 0, 0}, {83, 65, 78, 71, 0, 0},\n            {83, 65, 79, 0, 0, 0}, {83, 69, 0, 0, 0, 0},\n            {83, 69, 78, 0, 0, 0}, {83, 69, 78, 71, 0, 0},\n            {83, 72, 65, 0, 0, 0}, {83, 72, 65, 73, 0, 0},\n            {83, 72, 65, 78, 0, 0}, {83, 72, 65, 78, 71, 0},\n            {83, 72, 65, 79, 0, 0}, {83, 72, 69, 0, 0, 0},\n            {83, 72, 69, 78, 0, 0}, {88, 73, 78, 0, 0, 0},\n            {83, 72, 69, 78, 0, 0}, {83, 72, 69, 78, 71, 0},\n            {83, 72, 73, 0, 0, 0}, {83, 72, 79, 85, 0, 0},\n            {83, 72, 85, 0, 0, 0}, {83, 72, 85, 65, 0, 0},\n            {83, 72, 85, 65, 73, 0}, {83, 72, 85, 65, 78, 0},\n            {83, 72, 85, 65, 78, 71}, {83, 72, 85, 73, 0, 0},\n            {83, 72, 85, 78, 0, 0}, {83, 72, 85, 79, 0, 0},\n            {83, 73, 0, 0, 0, 0}, {83, 79, 78, 71, 0, 0},\n            {83, 79, 85, 0, 0, 0}, {83, 85, 0, 0, 0, 0},\n            {83, 85, 65, 78, 0, 0}, {83, 85, 73, 0, 0, 0},\n            {83, 85, 78, 0, 0, 0}, {83, 85, 79, 0, 0, 0},\n            {84, 65, 0, 0, 0, 0}, {84, 65, 73, 0, 0, 0},\n            {84, 65, 78, 0, 0, 0}, {84, 65, 78, 71, 0, 0},\n            {84, 65, 79, 0, 0, 0}, {84, 69, 0, 0, 0, 0},\n            {84, 69, 78, 71, 0, 0}, {84, 73, 0, 0, 0, 0},\n            {84, 73, 65, 78, 0, 0}, {84, 73, 65, 79, 0, 0},\n            {84, 73, 69, 0, 0, 0}, {84, 73, 78, 71, 0, 0},\n            {84, 79, 78, 71, 0, 0}, {84, 79, 85, 0, 0, 0},\n            {84, 85, 0, 0, 0, 0}, {84, 85, 65, 78, 0, 0},\n            {84, 85, 73, 0, 0, 0}, {84, 85, 78, 0, 0, 0},\n            {84, 85, 79, 0, 0, 0}, {87, 65, 0, 0, 0, 0},\n            {87, 65, 73, 0, 0, 0}, {87, 65, 78, 0, 0, 0},\n            {87, 65, 78, 71, 0, 0}, {87, 69, 73, 0, 0, 0},\n            {87, 69, 78, 0, 0, 0}, {87, 69, 78, 71, 0, 0},\n            {87, 79, 0, 0, 0, 0}, {87, 85, 0, 0, 0, 0},\n            {88, 73, 0, 0, 0, 0}, {88, 73, 65, 0, 0, 0},\n            {88, 73, 65, 78, 0, 0}, {88, 73, 65, 78, 71, 0},\n            {88, 73, 65, 79, 0, 0}, {88, 73, 69, 0, 0, 0},\n            {88, 73, 78, 0, 0, 0}, {88, 73, 78, 71, 0, 0},\n            {88, 73, 79, 78, 71, 0}, {88, 73, 85, 0, 0, 0},\n            {88, 85, 0, 0, 0, 0}, {88, 85, 65, 78, 0, 0},\n            {88, 85, 69, 0, 0, 0}, {88, 85, 78, 0, 0, 0},\n            {89, 65, 0, 0, 0, 0}, {89, 65, 78, 0, 0, 0},\n            {89, 65, 78, 71, 0, 0}, {89, 65, 79, 0, 0, 0},\n            {89, 69, 0, 0, 0, 0}, {89, 73, 0, 0, 0, 0},\n            {89, 73, 78, 0, 0, 0}, {89, 73, 78, 71, 0, 0},\n            {89, 79, 0, 0, 0, 0}, {89, 79, 78, 71, 0, 0},\n            {89, 79, 85, 0, 0, 0}, {89, 85, 0, 0, 0, 0},\n            {89, 85, 65, 78, 0, 0}, {89, 85, 69, 0, 0, 0},\n            {89, 85, 78, 0, 0, 0}, {74, 85, 78, 0, 0, 0},\n            {89, 85, 78, 0, 0, 0}, {90, 65, 0, 0, 0, 0},\n            {90, 65, 73, 0, 0, 0}, {90, 65, 78, 0, 0, 0},\n            {90, 65, 78, 71, 0, 0}, {90, 65, 79, 0, 0, 0},\n            {90, 69, 0, 0, 0, 0}, {90, 69, 73, 0, 0, 0},\n            {90, 69, 78, 0, 0, 0}, {90, 69, 78, 71, 0, 0},\n            {90, 72, 65, 0, 0, 0}, {90, 72, 65, 73, 0, 0},\n            {90, 72, 65, 78, 0, 0}, {90, 72, 65, 78, 71, 0},\n            {67, 72, 65, 78, 71, 0}, {90, 72, 65, 78, 71, 0},\n            {90, 72, 65, 79, 0, 0}, {90, 72, 69, 0, 0, 0},\n            {90, 72, 69, 78, 0, 0}, {90, 72, 69, 78, 71, 0},\n            {90, 72, 73, 0, 0, 0}, {83, 72, 73, 0, 0, 0},\n            {90, 72, 73, 0, 0, 0}, {90, 72, 79, 78, 71, 0},\n            {90, 72, 79, 85, 0, 0}, {90, 72, 85, 0, 0, 0},\n            {90, 72, 85, 65, 0, 0}, {90, 72, 85, 65, 73, 0},\n            {90, 72, 85, 65, 78, 0}, {90, 72, 85, 65, 78, 71},\n            {90, 72, 85, 73, 0, 0}, {90, 72, 85, 78, 0, 0},\n            {90, 72, 85, 79, 0, 0}, {90, 73, 0, 0, 0, 0},\n            {90, 79, 78, 71, 0, 0}, {90, 79, 85, 0, 0, 0},\n            {90, 85, 0, 0, 0, 0}, {90, 85, 65, 78, 0, 0},\n            {90, 85, 73, 0, 0, 0}, {90, 85, 78, 0, 0, 0},\n            {90, 85, 79, 0, 0, 0}, {0, 0, 0, 0, 0, 0},\n            {83, 72, 65, 78, 0, 0}, {0, 0, 0, 0, 0, 0},};\n    private static final String TAG = \"HanziToPinyin\";\n    // Turn on this flag when we want to check internal data structure.\n    private static final boolean DEBUG = false;\n    /**\n     * First and last Chinese character with known Pinyin according to zh collation\n     */\n    private static final String FIRST_PINYIN_UNIHAN = \"\\u963F\";\n    private static final String LAST_PINYIN_UNIHAN = \"\\u9FFF\";\n\n    private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA);\n\n    private static HanziToPinyin sInstance;\n    private final boolean mHasChinaCollator;\n\n    protected HanziToPinyin(boolean hasChinaCollator) {\n        mHasChinaCollator = hasChinaCollator;\n    }\n\n    public static HanziToPinyin getInstance() {\n        synchronized (HanziToPinyin.class) {\n            if (sInstance != null) {\n                return sInstance;\n            }\n            // Check if zh_CN collation data is available\n            final Locale[] locale = Collator.getAvailableLocales();\n            for (int i = 0; i < locale.length; i++) {\n                if (locale[i].equals(Locale.CHINA) || locale[i].getLanguage().contains(\"zh\")) {\n                    // Do self validation just once.\n                    if (DEBUG) {\n                        Log.d(TAG, \"Self validation. Result: \" + doSelfValidation());\n                    }\n                    sInstance = new HanziToPinyin(true);\n                    return sInstance;\n                }\n            }\n            if (sInstance == null) {//这个判断是用于处理国产ROM的兼容性问题\n                if (Locale.CHINA.equals(Locale.getDefault())) {\n                    sInstance = new HanziToPinyin(true);\n                    return sInstance;\n                }\n            }\n            Log.w(TAG, \"There is no Chinese collator, HanziToPinyin is disabled\");\n            sInstance = new HanziToPinyin(false);\n            return sInstance;\n        }\n    }\n\n    /**\n     * Validate if our internal table has some wrong value.\n     *\n     * @return true when the table looks correct.\n     */\n    private static boolean doSelfValidation() {\n        char lastChar = UNIHANS[0];\n        String lastString = Character.toString(lastChar);\n        for (char c : UNIHANS) {\n            if (lastChar == c) {\n                continue;\n            }\n            final String curString = Character.toString(c);\n            int cmp = COLLATOR.compare(lastString, curString);\n            if (cmp >= 0) {\n                Log.e(TAG, \"Internal error in Unihan table. \" + \"The last string \\\"\" + lastString\n                        + \"\\\" is greater than current string \\\"\" + curString + \"\\\".\");\n                return false;\n            }\n            lastString = curString;\n        }\n        return true;\n    }\n\n    private Token getToken(char character) {\n        Token token = new Token();\n        final String letter = Character.toString(character);\n        token.source = letter;\n        int offset = -1;\n        int cmp;\n        if (character < 256) {\n            token.type = Token.LATIN;\n            token.target = letter;\n            return token;\n        } else {\n            cmp = COLLATOR.compare(letter, FIRST_PINYIN_UNIHAN);\n            if (cmp < 0) {\n                token.type = Token.UNKNOWN;\n                token.target = letter;\n                return token;\n            } else if (cmp == 0) {\n                token.type = Token.PINYIN;\n                offset = 0;\n            } else {\n                cmp = COLLATOR.compare(letter, LAST_PINYIN_UNIHAN);\n                if (cmp > 0) {\n                    token.type = Token.UNKNOWN;\n                    token.target = letter;\n                    return token;\n                } else if (cmp == 0) {\n                    token.type = Token.PINYIN;\n                    offset = UNIHANS.length - 1;\n                }\n            }\n        }\n\n        token.type = Token.PINYIN;\n        if (offset < 0) {\n            int begin = 0;\n            int end = UNIHANS.length - 1;\n            while (begin <= end) {\n                offset = (begin + end) / 2;\n                final String unihan = Character.toString(UNIHANS[offset]);\n                cmp = COLLATOR.compare(letter, unihan);\n                if (cmp == 0) {\n                    break;\n                } else if (cmp > 0) {\n                    begin = offset + 1;\n                } else {\n                    end = offset - 1;\n                }\n            }\n        }\n        if (cmp < 0) {\n            offset--;\n        }\n        StringBuilder pinyin = new StringBuilder();\n        for (int j = 0; j < PINYINS[offset].length && PINYINS[offset][j] != 0; j++) {\n            pinyin.append((char) PINYINS[offset][j]);\n        }\n        token.target = pinyin.toString();\n        if (TextUtils.isEmpty(token.target)) {\n            token.type = Token.UNKNOWN;\n            token.target = token.source;\n        }\n        return token;\n    }\n\n    /**\n     * Convert the input to a array of tokens. The sequence of ASCII or Unknown characters without\n     * space will be put into a Token, One Hanzi character which has pinyin will be treated as a\n     * Token. If these is no China collator, the empty token array is returned.\n     */\n    public ArrayList<Token> get(final String input) {\n        ArrayList<Token> tokens = new ArrayList<Token>();\n        if (!mHasChinaCollator || TextUtils.isEmpty(input)) {\n            // return empty tokens.\n            return tokens;\n        }\n        final int inputLength = input.length();\n        final StringBuilder sb = new StringBuilder();\n        int tokenType = Token.LATIN;\n        // Go through the input, create a new token when\n        // a. Token type changed\n        // b. Get the Pinyin of current charater.\n        // c. current character is space.\n        for (int i = 0; i < inputLength; i++) {\n            final char character = input.charAt(i);\n            if (character == ' ') {\n                if (sb.length() > 0) {\n                    addToken(sb, tokens, tokenType);\n                }\n            } else if (character < 256) {\n                if (tokenType != Token.LATIN && sb.length() > 0) {\n                    addToken(sb, tokens, tokenType);\n                }\n                tokenType = Token.LATIN;\n                sb.append(character);\n            } else {\n                Token t = getToken(character);\n                if (t.type == Token.PINYIN) {\n                    if (sb.length() > 0) {\n                        addToken(sb, tokens, tokenType);\n                    }\n                    tokens.add(t);\n                    tokenType = Token.PINYIN;\n                } else {\n                    if (tokenType != t.type && sb.length() > 0) {\n                        addToken(sb, tokens, tokenType);\n                    }\n                    tokenType = t.type;\n                    sb.append(character);\n                }\n            }\n        }\n        if (sb.length() > 0) {\n            addToken(sb, tokens, tokenType);\n        }\n        return tokens;\n    }\n\n    private void addToken(\n            final StringBuilder sb, final ArrayList<Token> tokens, final int tokenType) {\n        String str = sb.toString();\n        tokens.add(new Token(tokenType, str, str));\n        sb.setLength(0);\n    }\n\n    public String toPinyinString(String string) {\n        if (string == null) {\n            return null;\n        }\n        StringBuilder sb = new StringBuilder();\n        ArrayList<Token> tokens = get(string);\n        for (Token token : tokens) {\n            sb.append(token.target);\n        }\n        return sb.toString().toLowerCase();\n    }\n\n    public static class Token {\n        /**\n         * Separator between target string for each source char\n         */\n        public static final String SEPARATOR = \" \";\n\n        public static final int LATIN = 1;\n        public static final int PINYIN = 2;\n        public static final int UNKNOWN = 3;\n        /**\n         * Type of this token, ASCII, PINYIN or UNKNOWN.\n         */\n        public int type;\n        /**\n         * Original string before translation.\n         */\n        public String source;\n        /**\n         * Translated string of source. For Han, target is corresponding Pinyin. Otherwise target is\n         * original string in source.\n         */\n        public String target;\n        public Token() {\n        }\n        public Token(int type, String source, String target) {\n            this.type = type;\n            this.source = source;\n            this.target = target;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/IOStreamUtils.kt",
    "content": "package me.bmax.apatch.util\n\nimport android.content.ContentResolver\nimport android.net.Uri\nimport me.bmax.apatch.apApp\nimport java.io.File\nimport java.io.FileNotFoundException\nimport java.io.InputStream\nimport java.io.OutputStream\n\n\nval cr: ContentResolver get() = apApp.contentResolver\n\nfun Uri.inputStream() = cr.openInputStream(this) ?: throw FileNotFoundException()\n\nfun Uri.outputStream() = cr.openOutputStream(this, \"rwt\") ?: throw FileNotFoundException()\n\nfun Uri.fileDescriptor(mode: String) =\n    cr.openFileDescriptor(this, mode) ?: throw FileNotFoundException()\n\ninline fun <In : InputStream, Out : OutputStream> withStreams(\n    inStream: In,\n    outStream: Out,\n    withBoth: (In, Out) -> Unit\n) {\n    inStream.use { reader ->\n        outStream.use { writer ->\n            withBoth(reader, writer)\n        }\n    }\n}\n\nfun InputStream.copyAndClose(out: OutputStream) = withStreams(this, out) { i, o -> i.copyTo(o) }\nfun InputStream.writeTo(file: File) = copyAndClose(file.outputStream())\n\nfun InputStream.copyAndCloseOut(out: OutputStream) = out.use { copyTo(it) }\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/LatestVersionInfo.kt",
    "content": "package me.bmax.apatch.util\n\ndata class LatestVersionInfo(\n    val versionCode: Int = 0, val downloadUrl: String = \"\", val changelog: String = \"\"\n)"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/LogEvent.kt",
    "content": "package me.bmax.apatch.util\n\nimport android.content.Context\nimport android.os.Build\nimport android.system.Os\nimport com.topjohnwu.superuser.ShellUtils\nimport java.io.File\nimport java.io.FileWriter\nimport java.io.PrintWriter\nimport java.time.LocalDateTime\nimport java.time.format.DateTimeFormatter\n\nfun getBugreportFile(context: Context): File {\n\n    val bugreportDir = File(context.cacheDir, \"bugreport\")\n    bugreportDir.mkdirs()\n\n    val dmesgFile = File(bugreportDir, \"dmesg.txt\")\n    val logcatFile = File(bugreportDir, \"logcat.txt\")\n    val tombstonesFile = File(bugreportDir, \"tombstones.tar.gz\")\n    val dropboxFile = File(bugreportDir, \"dropbox.tar.gz\")\n    val pstoreFile = File(bugreportDir, \"pstore.tar.gz\")\n    val diagFile = File(bugreportDir, \"diag.tar.gz\")\n    val bootlogFile = File(bugreportDir, \"bootlog.tar.gz\")\n    val mountsFile = File(bugreportDir, \"mounts.txt\")\n    val fileSystemsFile = File(bugreportDir, \"filesystems.txt\")\n    val apFileTree = File(bugreportDir, \"ap_tree.txt\")\n    val appListFile = File(bugreportDir, \"packages.txt\")\n    val propFile = File(bugreportDir, \"props.txt\")\n    val packageConfigFile = File(bugreportDir, \"package_config\")\n    val kernelConfig = File(bugreportDir, \"defconfig\")\n\n    val shell = tryGetRootShell()\n\n    shell.newJob().add(\"dmesg > ${dmesgFile.absolutePath}\").exec()\n    shell.newJob().add(\"logcat -d > ${logcatFile.absolutePath}\").exec()\n    shell.newJob().add(\"tar -czf ${tombstonesFile.absolutePath} -C /data/tombstones .\").exec()\n    shell.newJob().add(\"tar -czf ${dropboxFile.absolutePath} -C /data/system/dropbox .\").exec()\n    shell.newJob().add(\"tar -czf ${pstoreFile.absolutePath} -C /sys/fs/pstore .\").exec()\n    shell.newJob().add(\"tar -czf ${diagFile.absolutePath} -C /data/vendor/diag .\").exec()\n    shell.newJob().add(\"tar -czf ${bootlogFile.absolutePath} -C /data/adb/ap/log .\").exec()\n\n    shell.newJob().add(\"cat /proc/1/mountinfo > ${mountsFile.absolutePath}\").exec()\n    shell.newJob().add(\"cat /proc/filesystems > ${fileSystemsFile.absolutePath}\").exec()\n    shell.newJob().add(\"ls -alRZ /data/adb > ${apFileTree.absolutePath}\").exec()\n    shell.newJob().add(\"cp /data/system/packages.list ${appListFile.absolutePath}\").exec()\n    shell.newJob().add(\"getprop > ${propFile.absolutePath}\").exec()\n    shell.newJob().add(\"cp /data/adb/ap/package_config ${packageConfigFile.absolutePath}\").exec()\n    shell.newJob().add(\"zcat /proc/config.gz > ${kernelConfig.absolutePath}\").exec()\n\n    val selinux = ShellUtils.fastCmd(shell, \"getenforce\")\n\n    // basic information\n    val buildInfo = File(bugreportDir, \"basic.txt\")\n    PrintWriter(FileWriter(buildInfo)).use { pw ->\n        pw.println(\"Kernel: ${System.getProperty(\"os.version\")}\")\n        pw.println(\"BRAND: \" + Build.BRAND)\n        pw.println(\"MODEL: \" + Build.MODEL)\n        pw.println(\"PRODUCT: \" + Build.PRODUCT)\n        pw.println(\"MANUFACTURER: \" + Build.MANUFACTURER)\n        pw.println(\"SDK: \" + Build.VERSION.SDK_INT)\n        pw.println(\"PREVIEW_SDK: \" + Build.VERSION.PREVIEW_SDK_INT)\n        pw.println(\"FINGERPRINT: \" + Build.FINGERPRINT)\n        pw.println(\"DEVICE: \" + Build.DEVICE)\n        pw.println(\"Manager: \" + Version.getManagerVersion())\n        pw.println(\"SELinux: $selinux\")\n\n        val uname = Os.uname()\n        pw.println(\"KernelRelease: ${uname.release}\")\n        pw.println(\"KernelVersion: ${uname.version}\")\n        pw.println(\"Mahcine: ${uname.machine}\")\n        pw.println(\"Nodename: ${uname.nodename}\")\n        pw.println(\"Sysname: ${uname.sysname}\")\n\n        pw.println(\"KPatch: ${Version.installedKPVString()}\")\n        pw.println(\"APatch: ${Version.installedApdVString}\")\n        val safeMode = false\n        pw.println(\"SafeMode: $safeMode\")\n    }\n\n    // modules\n    val modulesFile = File(bugreportDir, \"modules.json\")\n    modulesFile.writeText(listModules())\n\n    val formatter = DateTimeFormatter.ofPattern(\"yyyy-MM-dd_HH_mm\")\n    val current = LocalDateTime.now().format(formatter)\n\n    val targetFile = File(context.cacheDir, \"APatch_bugreport_${current}.tar.gz\")\n\n    shell.newJob().add(\"tar czf ${targetFile.absolutePath} -C ${bugreportDir.absolutePath} .\")\n        .exec()\n    shell.newJob().add(\"rm -rf ${bugreportDir.absolutePath}\").exec()\n    shell.newJob().add(\"chmod 0644 ${targetFile.absolutePath}\").exec()\n\n    return targetFile\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/PkgConfig.kt",
    "content": "package me.bmax.apatch.util\n\nimport android.os.Parcelable\nimport android.util.Log\nimport androidx.annotation.Keep\nimport androidx.compose.runtime.Immutable\nimport kotlinx.parcelize.Parcelize\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.Natives\nimport java.io.File\nimport java.io.FileWriter\nimport kotlin.concurrent.thread\n\nobject PkgConfig {\n    private const val TAG = \"PkgConfig\"\n\n    private const val CSV_HEADER = \"pkg,exclude,allow,uid,to_uid,sctx\"\n\n    @Immutable\n    @Parcelize\n    @Keep\n    data class Config(\n        var pkg: String = \"\", var exclude: Int = 0, var allow: Int = 0, var profile: Natives.Profile\n    ) : Parcelable {\n        companion object {\n            fun fromLine(line: String): Config {\n                val sp = line.split(\",\")\n                val profile = Natives.Profile(sp[3].toInt(), sp[4].toInt(), sp[5])\n                return Config(sp[0], sp[1].toInt(), sp[2].toInt(), profile)\n            }\n        }\n\n        fun isDefault(): Boolean {\n            return allow == 0 && exclude == 0\n        }\n\n        fun toLine(): String {\n            return \"${pkg},${exclude},${allow},${profile.uid},${profile.toUid},${profile.scontext}\"\n        }\n    }\n\n    fun readConfigs(): HashMap<Int, Config> {\n        val configs = HashMap<Int, Config>()\n        val file = File(APApplication.PACKAGE_CONFIG_FILE)\n        if (file.exists()) {\n            file.readLines().drop(1).filter { it.isNotEmpty() }.forEach {\n                Log.d(TAG, it)\n                val p = Config.fromLine(it)\n                if (!p.isDefault()) {\n                    configs[p.profile.uid] = p\n                }\n            }\n        }\n        return configs\n    }\n\n    private fun writeConfigs(configs: HashMap<Int, Config>) {\n        val file = File(APApplication.PACKAGE_CONFIG_FILE)\n        if (!file.parentFile?.exists()!!) file.parentFile?.mkdirs()\n        val writer = FileWriter(file, false)\n        writer.write(CSV_HEADER + '\\n')\n        configs.values.forEach {\n            if (!it.isDefault()) {\n                writer.write(it.toLine() + '\\n')\n            }\n        }\n        writer.flush()\n        writer.close()\n    }\n\n    fun changeConfig(config: Config) {\n        thread {\n            synchronized(PkgConfig.javaClass) {\n                Natives.su()\n                val configs = readConfigs()\n                val uid = config.profile.uid\n                // Root App should not be excluded\n                if (config.allow == 1) {\n                    config.exclude = 0\n                }\n                if (config.allow == 0 && configs[uid] != null && config.exclude != 0) {\n                    configs.remove(uid)\n                } else {\n                    Log.d(TAG, \"change config: $config\")\n                    configs[uid] = config\n                }\n                writeConfigs(configs)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/Version.kt",
    "content": "package me.bmax.apatch.util\n\nimport android.util.Log\nimport androidx.core.content.pm.PackageInfoCompat\nimport me.bmax.apatch.APApplication\nimport me.bmax.apatch.BuildConfig\nimport me.bmax.apatch.Natives\nimport me.bmax.apatch.apApp\nimport me.bmax.apatch.util.shellForResult\nimport org.ini4j.Ini\nimport java.io.StringReader\nimport me.bmax.apatch.ui.viewmodel.KPModel\nimport com.topjohnwu.superuser.nio.ExtendedFile\nimport com.topjohnwu.superuser.nio.FileSystemManager\nimport com.topjohnwu.superuser.Shell\nimport androidx.compose.runtime.mutableStateOf\nimport java.io.File\nimport android.system.Os\n\n\n/**\n * version string is like 0.9.0 or 0.9.0-dev\n * version uint is hex number like: 0x000900\n */\nobject Version {\n\n    private fun string2UInt(ver: String): UInt {\n        val v = ver.trim().split(\"-\")[0]\n        val vn = v.split('.')\n        val vi = vn[0].toInt().shl(16) + vn[1].toInt().shl(8) + vn[2].toInt()\n        return vi.toUInt()\n    }\n\n    fun getKpImg(): String {\n        var shell: Shell = createRootShell()\n        var kimgInfo = mutableStateOf(KPModel.KImgInfo(\"\", false))\n        var kpimgInfo = mutableStateOf(KPModel.KPImgInfo(\"\", \"\", \"\", \"\", \"\"))\n        val patchDir: ExtendedFile = FileSystemManager.getLocal().getFile(apApp.filesDir.parent, \"check\")\n        patchDir.deleteRecursively()\n        patchDir.mkdirs()\n        val execs = listOf(\n            \"libkptools.so\",  \"libbusybox.so\"\n        )\n\n        val info = apApp.applicationInfo\n        val libs = File(info.nativeLibraryDir).listFiles { _, name ->\n            execs.contains(name)\n        } ?: emptyArray()\n\n        for (lib in libs) {\n            val name = lib.name.substring(3, lib.name.length - 3)\n            Os.symlink(lib.path, \"$patchDir/$name\")\n        }\n\n        for (script in listOf(\n            \"boot_patch.sh\", \"boot_unpatch.sh\", \"boot_extract.sh\", \"util_functions.sh\", \"kpimg\"\n        )) {\n            val dest = File(patchDir, script)\n            apApp.assets.open(script).writeTo(dest)\n        }\n        val result = shellForResult(\n            shell, \"cd $patchDir\", \"./kptools -l -k kpimg\"\n        )\n\n        if (result.isSuccess) {\n            val ini = Ini(StringReader(result.out.joinToString(\"\\n\")))\n            val kpimg = ini[\"kpimg\"]\n            if (kpimg != null) {\n                kpimgInfo.value = KPModel.KPImgInfo(\n                    kpimg[\"version\"].toString(),\n                    kpimg[\"compile_time\"].toString(),\n                    kpimg[\"config\"].toString(),\n                    APApplication.superKey,     // current key\n                    kpimg[\"root_superkey\"].toString()      // possibly empty\n                )\n                return kpimg[\"compile_time\"].toString()\n            } \n        } \n\n        return \"unknown\"\n    }\n\n    fun uInt2String(ver: UInt): String {\n        return \"%d.%d.%d\".format(\n            ver.and(0xff0000u).shr(16).toInt(),\n            ver.and(0xff00u).shr(8).toInt(),\n            ver.and(0xffu).toInt()\n        )\n    }\n    \n    fun installedKPTime(): String {\n        val time = Natives.kernelPatchBuildTime()\n        return if (time.startsWith(\"ERROR_\")) \"读取失败\" else time\n    }\n\n    fun buildKPVUInt(): UInt {\n        val buildVS = BuildConfig.buildKPV\n        return string2UInt(buildVS)\n    }\n\n    fun buildKPVString(): String {\n        return BuildConfig.buildKPV\n    }\n\n    /**\n     * installed KernelPatch version (installed kpimg)\n     */\n    fun installedKPVUInt(): UInt {\n        return Natives.kernelPatchVersion().toUInt()\n    }\n\n    fun installedKPVString(): String {\n        return uInt2String(installedKPVUInt())\n    }\n\n\n    private fun installedKPatchVString(): String {\n        val resultShell = rootShellForResult(\"${APApplication.APD_PATH} -V\")\n        val result = resultShell.out.toString()\n        return result.trim().ifEmpty { \"0\" }\n    }\n\n    fun installedKPatchVUInt(): UInt {\n        return installedKPatchVString().trim().toUInt(0x10)\n    }\n\n    private fun installedApdVString(): String {\n        val resultShell = rootShellForResult(\"${APApplication.APD_PATH} -V\")\n        installedApdVString = if (resultShell.isSuccess) {\n            val result = resultShell.out.toString()\n            Log.i(\"APatch\", \"[installedApdVString@Version] resultFromShell: $result\")\n            Regex(\"\\\\d+\").find(result)?.value ?: \"0\"\n        } else {\n            \"0\"\n        }\n        return installedApdVString\n    }\n\n    fun installedApdVUInt(): Int {\n        installedApdVInt = installedApdVString().toInt()\n        return installedApdVInt\n    }\n\n\n    fun getManagerVersion(): Pair<String, Long> {\n        val packageInfo = apApp.packageManager.getPackageInfo(apApp.packageName, 0)!!\n        val versionCode = PackageInfoCompat.getLongVersionCode(packageInfo)\n        return Pair(packageInfo.versionName!!, versionCode)\n    }\n\n    var installedApdVInt: Int = 0\n    var installedApdVString: String = \"0\"\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/ui/APDialogBlurBehindUtils.kt",
    "content": "package me.bmax.apatch.util.ui\n\nimport android.animation.ValueAnimator\nimport android.annotation.SuppressLint\nimport android.os.Build\nimport android.util.Log\nimport android.view.SurfaceControl\nimport android.view.View\nimport android.view.Window\nimport android.view.WindowManager\nimport android.view.animation.DecelerateInterpolator\nimport java.lang.reflect.Method\n\nopen class APDialogBlurBehindUtils {\n    companion object {\n        private val bIsBlurSupport =\n            getSystemProperty(\"ro.surface_flinger.supports_background_blur\") && !getSystemProperty(\"persist.sys.sf.disable_blurs\")\n\n        private fun getSystemProperty(key: String?): Boolean {\n            var value = false\n            try {\n                val c = Class.forName(\"android.os.SystemProperties\")\n                val get = c.getMethod(\n                    \"getBoolean\", String::class.java, Boolean::class.javaPrimitiveType\n                )\n                value = get.invoke(c, key, false) as Boolean\n            } catch (e: Exception) {\n                Log.e(\"APatchUI\", \"[APDialogBlurBehindUtils] Failed to getSystemProperty: \", e)\n            }\n            return value\n        }\n\n        private fun updateWindowForBlurs(window: Window, blursEnabled: Boolean) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                window.setDimAmount(0.27f)\n                window.attributes.blurBehindRadius = 20\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {\n                if (blursEnabled) {\n                    val view = window.decorView\n                    val animator = ValueAnimator.ofInt(1, 53)\n                    animator.duration = 667\n                    animator.interpolator = DecelerateInterpolator()\n                    try {\n                        val viewRootImpl =\n                            view.javaClass.getMethod(\"getViewRootImpl\").invoke(view) ?: return\n                        val surfaceControl = viewRootImpl.javaClass.getMethod(\"getSurfaceControl\")\n                            .invoke(viewRootImpl) as SurfaceControl\n                        @SuppressLint(\"BlockedPrivateApi\") val setBackgroundBlurRadius: Method =\n                            SurfaceControl.Transaction::class.java.getDeclaredMethod(\n                                \"setBackgroundBlurRadius\",\n                                SurfaceControl::class.java,\n                                Int::class.javaPrimitiveType\n                            )\n                        animator.addUpdateListener { animation: ValueAnimator ->\n                            try {\n                                val transaction = SurfaceControl.Transaction()\n                                val animatedValue = animation.animatedValue\n                                if (animatedValue != null) {\n                                    setBackgroundBlurRadius.invoke(\n                                        transaction, surfaceControl, animatedValue as Int\n                                    )\n                                }\n                                transaction.apply()\n                            } catch (t: Throwable) {\n                                Log.e(\n                                    \"APatchUI\",\n                                    \"[APDialogBlurBehindUtils] Blur behind dialog builder: \" + t.toString()\n                                )\n                            }\n                        }\n                    } catch (t: Throwable) {\n                        Log.e(\n                            \"APatchUI\",\n                            \"[APDialogBlurBehindUtils] Blur behind dialog builder: \" + t.toString()\n                        )\n                    }\n                    view.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {\n                        override fun onViewAttachedToWindow(v: View) {}\n                        override fun onViewDetachedFromWindow(v: View) {\n                            animator.cancel()\n                        }\n                    })\n                    animator.start()\n                }\n            }\n        }\n\n        fun setupWindowBlurListener(window: Window) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                window.setFlags(\n                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND,\n                    WindowManager.LayoutParams.FLAG_BLUR_BEHIND\n                )\n                updateWindowForBlurs(window, true)\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {\n                updateWindowForBlurs(\n                    window, bIsBlurSupport\n                )\n            }\n        }\n\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/ui/CompositionProvider.kt",
    "content": "package me.bmax.apatch.util.ui\n\nimport androidx.compose.material3.SnackbarHostState\nimport androidx.compose.runtime.compositionLocalOf\n\nval LocalSnackbarHost = compositionLocalOf<SnackbarHostState> {\n    error(\"CompositionLocal LocalSnackbarController not present\")\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/ui/HyperlinkText.kt",
    "content": "package me.bmax.apatch.util.ui\n\nimport androidx.compose.foundation.gestures.detectTapGestures\nimport androidx.compose.material3.MaterialTheme\nimport androidx.compose.material3.Text\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.mutableStateOf\nimport androidx.compose.runtime.remember\nimport androidx.compose.ui.Modifier\nimport androidx.compose.ui.input.pointer.pointerInput\nimport androidx.compose.ui.platform.LocalUriHandler\nimport androidx.compose.ui.text.SpanStyle\nimport androidx.compose.ui.text.TextLayoutResult\nimport androidx.compose.ui.text.buildAnnotatedString\nimport androidx.compose.ui.text.style.TextDecoration\nimport java.util.regex.Pattern\n\n@Composable\nfun LinkifyText(\n    text: String,\n    modifier: Modifier = Modifier\n) {\n    val uriHandler = LocalUriHandler.current\n    val layoutResult = remember {\n        mutableStateOf<TextLayoutResult?>(null)\n    }\n    val linksList = extractUrls(text)\n    val annotatedString = buildAnnotatedString {\n        append(text)\n        linksList.forEach {\n            addStyle(\n                style = SpanStyle(\n                    color = MaterialTheme.colorScheme.primary,\n                    textDecoration = TextDecoration.Underline\n                ),\n                start = it.start,\n                end = it.end\n            )\n            addStringAnnotation(\n                tag = \"URL\",\n                annotation = it.url,\n                start = it.start,\n                end = it.end\n            )\n        }\n    }\n    Text(\n        text = annotatedString,\n        modifier = modifier.pointerInput(Unit) {\n            detectTapGestures { offsetPosition ->\n                layoutResult.value?.let {\n                    val position = it.getOffsetForPosition(offsetPosition)\n                    annotatedString.getStringAnnotations(position, position).firstOrNull()\n                        ?.let { result ->\n                            if (result.tag == \"URL\") {\n                                uriHandler.openUri(result.item)\n                            }\n                        }\n                }\n            }\n        },\n        onTextLayout = { layoutResult.value = it }\n    )\n}\n\nprivate val urlPattern: Pattern = Pattern.compile(\n    \"(?:^|[\\\\W])((ht|f)tp(s?):\\\\/\\\\/|www\\\\.)\"\n            + \"(([\\\\w\\\\-]+\\\\.){1,}?([\\\\w\\\\-.~]+\\\\/?)*\"\n            + \"[\\\\p{Alnum}.,%_=?&#\\\\-+()\\\\[\\\\]\\\\*$~@!:/{};']*)\",\n    Pattern.CASE_INSENSITIVE or Pattern.MULTILINE or Pattern.DOTALL\n)\n\nprivate data class LinkInfo(\n    val url: String,\n    val start: Int,\n    val end: Int\n)\n\nprivate fun extractUrls(text: String): List<LinkInfo> = buildList {\n    val matcher = urlPattern.matcher(text)\n    while (matcher.find()) {\n        val matchStart = matcher.start(1)\n        val matchEnd = matcher.end()\n        val url = text.substring(matchStart, matchEnd).replaceFirst(\"http://\", \"https://\")\n        add(LinkInfo(url, matchStart, matchEnd))\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/me/bmax/apatch/util/ui/NavigationBarsSpacer.kt",
    "content": "package me.bmax.apatch.util.ui\n\nimport androidx.compose.foundation.layout.Box\nimport androidx.compose.foundation.layout.Spacer\nimport androidx.compose.foundation.layout.WindowInsets\nimport androidx.compose.foundation.layout.asPaddingValues\nimport androidx.compose.foundation.layout.navigationBars\nimport androidx.compose.foundation.layout.padding\nimport androidx.compose.runtime.Composable\nimport androidx.compose.ui.Modifier\n\n@Composable\nfun NavigationBarsSpacer(\n    modifier: Modifier = Modifier\n) {\n    val paddingValues = WindowInsets.navigationBars.asPaddingValues()\n\n    Box(\n        modifier = Modifier.padding(paddingValues)\n    ) {\n        Spacer(modifier = modifier)\n    }\n}"
  },
  {
    "path": "app/src/main/res/drawable/device_mobile_down.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:pathData=\"M12.5,21h-4.5a2,2 0,0 1,-2 -2v-14a2,2 0,0 1,2 -2h8a2,2 0,0 1,2 2v7\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M11,4h2\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M12,17v0.01\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M19,16v6\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M22,19l-3,3l-3,-3\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/github.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24.0dip\"\n    android:height=\"24.0dip\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\">\n    <path\n        android:fillColor=\"#ffff\"\n        android:pathData=\"M12,2A10,10 0 0,0 2,12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0 0,0 12,2Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"192\"\n    android:viewportHeight=\"192\">\n\n  <group android:scaleX=\"0.97\"\n      android:scaleY=\"0.97\"\n      android:translateX=\"2.88\"\n      android:translateY=\"2.88\">\n      <path\n          android:pathData=\"M0 0L192 0L192 192L0 192L0 0Z\"\n          android:fillColor=\"#FFFFFF\"\n          android:strokeColor=\"#FFFFFF\"\n          android:strokeWidth=\"1\" />\n  </group>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <group android:scaleX=\"0.7135135\"\n      android:scaleY=\"0.7135135\"\n      android:translateX=\"73.34054\"\n      android:translateY=\"73.34054\">\n    <path\n        android:pathData=\"M304.42,123.08Q319,99.08 322,92.18a7.08,7.08 0,0 0,-1.31 -7.8,3.79 3.79,0 0,0 -3.18,-1.44c-3.51,0.12 -5.65,-0.63 -7.93,2.69a60.66,60.66 0,0 0,-5.37 9.64c-3.33,7.48 -7.67,14.36 -11.54,21.59a0.86,0.86 0,0 1,-1.07 0.39c-14.4,-5.52 -30.47,-7.17 -45.76,-6a94.62,94.62 0,0 0,-26 6,1.15 1.15,0 0,1 -1.41,-0.5c-3.84,-6.48 -7.19,-12.44 -10.77,-20 -2.1,-4.42 -4.6,-9.64 -8.21,-13.08a1.81,1.81 0,0 0,-1 -0.49c-4.23,-0.57 -9.27,-0.79 -9.95,4.78a12.35,12.35 0,0 0,1.87 7.43q7.75,14 15.7,27.43a1.21,1.21 0,0 1,-0.43 1.64c-26.65,15.7 -44,42.33 -43.91,73.42a0.67,0.67 0,0 0,0.67 0.67l186.39,-0.1a1.39,1.39 0,0 0,1.39 -1.4v-0.08c-0.76,-11.39 -2.94,-22.68 -8,-33.18q-12,-25.2 -37.52,-40a0.45,0.45 0,0 1,-0.18 -0.69\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M136.32,330.27A21.63,21.63 0,0 0,156 309.12q0,-43.94 0,-86c0,-5.5 -1.13,-10.51 -4.75,-14.87a22.21,22.21 0,0 0,-35.45 1.63,9.93 9.93,0 0,0 -1.81,5.86q0,49.15 0,98.85a10.64,10.64 0,0 0,1.8 6q7.55,10.76 20.5,9.7\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M398.87,221.61a21.3,21.3 0,0 0,-21.33 -21.26h-1.48a21.3,21.3 0,0 0,-21.27 21.34l0.16,87.22a21.3,21.3 0,0 0,21.33 21.26h1.48A21.3,21.3 0,0 0,399 308.83l-0.16,-87.22\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M243.08,363l24.62,-0.05a0.45,0.45 0,0 1,0.52 0.51q0.13,17.21 -0.06,34.75 -0.14,11 1.41,16 2.76,8.84 12.66,13.73c3,1.5 7.25,1.17 10.62,1.18a15,15 0,0 0,9.09 -3q10,-7.66 10.08,-20.67 0.14,-19.67 -0.07,-41.42c0,-0.76 0.36,-1.12 1.13,-1.09a115.4,115.4 0,0 0,11.91 0c16.94,-0.9 25.13,-12.07 25.11,-28.21q-0.06,-64.95 0,-129.87a0.8,0.8 0,0 0,-0.8 -0.81h-187a0.83,0.83 0,0 0,-0.82 0.83h0q0.35,61.24 0.08,128c0,9.74 0.26,15.67 6.6,22.33 8.58,9 19.77,8 31.25,7.75a0.42,0.42 0,0 1,0.42 0.41q0,21.4 -0.08,43.79a22.1,22.1 0,0 0,1.47 8.58c2.18,5.27 8.63,12.65 15.17,13.15 4.89,0.37 10.12,0.7 14.42,-1.79 7.15,-4.16 12,-10.91 11.91,-19.12q-0.18,-22.17 -0.09,-44.46a0.48,0.48 0,0 1,0.54 -0.54\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M202.24,142.7a73.29,73.29 0,0 0,-26 41.57,0.6 0.6,0 0,0 0.46,0.71h0.12q78.3,0 156.93,0a3,3 0,0 0,1 -0.16,0.52 0.52,0 0,0 0.39,-0.7c-2.83,-12 -8.39,-23.5 -16.83,-32.58a93.87,93.87 0,0 0,-21.1 -17.25,63.89 63.89,0 0,0 -13.06,-5.64 98.42,98.42 0,0 0,-13.78 -3.44,89.93 89.93,0 0,0 -45.77,4.37 61,61 0,0 0,-13.44 6.6q-4.54,3.09 -8.86,6.55\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M143,222.08a8.63,8.63 0,0 0,-8.63 -8.63H134a8.63,8.63 0,0 0,-8.63 8.63h0V308.7a8.63,8.63 0,0 0,8.63 8.63h0.3A8.63,8.63 0,0 0,143 308.7V222.08\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M385.51,221.45a7.87,7.87 0,0 0,-7.84 -7.9h-1a7.87,7.87 0,0 0,-7.9 7.84l-0.3,88a7.87,7.87 0,0 0,7.84 7.9h1a7.87,7.87 0,0 0,7.9 -7.84l0.3,-88\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M204.46,350.63c5.26,1.85 7.52,8.11 7.51,13.3q0,18.68 0,40.92a18.92,18.92 0,0 0,0.66 5A8.41,8.41 0,0 0,225 415q5,-2.91 5,-10.15 -0.07,-20.33 0,-42.76 0,-7.64 6.29,-11.18a17.67,17.67 0,0 1,7.48 -1.69q12.3,0 23.73,0a5.94,5.94 0,0 1,1.77 0.27c1.44,0.45 3,0.49 4.37,1.13q7.94,3.69 7.85,12.49 -0.25,23.72 0.25,43.09a10.52,10.52 0,0 0,3.45 7.89,8.43 8.43,0 0,0 13.05,-2.88 13.45,13.45 0,0 0,1 -5.33q-0.1,-20.39 0,-39.88c0,-6.48 2.17,-13.84 9,-15.7a24,24 0,0 1,6 -1.08q5.76,0 11.39,0.07a10.06,10.06 0,0 0,8.7 -3.85c2.38,-3.09 2.06,-7.7 2,-11.44q-0.24,-50.9 0,-100.2 0,-8.13 0.52,-16.54a0.48,0.48 0,0 0,-0.45 -0.51h-161a0.48,0.48 0,0 0,-0.49 0.48h0q0,59.14 -0.07,118.94c0,5.08 0.71,9.07 5.52,11.79a12.21,12.21 0,0 0,6.63 1.36c5.86,-0.24 12,-0.69 17.6,1.26\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M256.14,241.06c2.47,1.21 4.51,5.41 5.77,7.73a1.87,1.87 0,0 0,2.66 0.93l5.18,-2.23a1.7,1.7 0,0 0,1 -2.45,28.37 28.37,0 0,0 -8.27,-11.56c-9.1,-7.71 -17.26,1.13 -21.57,9.18a14.06,14.06 0,0 0,-1.4 3.83,1 1,0 0,0 0.29,0.94c1.51,1.49 4.46,2.26 6.39,3a2.41,2.41 0,0 0,3.13 -1.35l0.05,-0.14a19.08,19.08 0,0 1,4.66 -7.56,1.83 1.83,0 0,1 2.08,-0.34\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M244,262.69a0.45,0.45 0,0 1,0.2 0.6,0.4 0.4,0 0,1 -0.16,0.18c-8.73,5.77 -16.12,12.75 -23.42,20.14a77.72,77.72 0,0 0,-9.36 11.74c-5.51,8.31 -10.38,26.49 5.94,27.34 11,0.56 23.33,-4.52 33.21,-9.79 5.46,-2.91 10.75,-6.8 16,-10.29C279.23,294 293.2,281.16 301.47,267a24.68,24.68 0,0 0,2.5 -16.87c-0.84,-4.13 -6.55,-6.3 -10.17,-6.6a40.62,40.62 0,0 0,-15.52 2.07,98.9 98.9,0 0,0 -22.7,10.19 0.79,0.79 0,0 1,-0.84 0,136.77 136.77,0 0,0 -18.21,-8.14c-8.95,-3.25 -29.8,-8.43 -30.71,7.3 -0.2,3.48 1,6.81 2.12,10.08a8,8 0,0 1,0.25 4.07c-0.89,4.78 0.63,9.48 5.19,11.62q6.41,3 11.39,-1.84c6.58,-6.38 3.13,-16.56 -5.94,-17.65A3.7,3.7 0,0 1,215.6 257a2.54,2.54 0,0 1,2.53 -2.4c8,-0.67 18.37,4.28 25.87,8.09\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M295.13,307.57c0,0.63 0,1.25 0,1.88a2.06,2.06 0,0 1,-2.13 2.28c-8.24,0.66 -17.51,-3.69 -24.95,-7.42a2.45,2.45 0,0 0,-2.4 0.11l-6.94,4.3a1.72,1.72 0,0 0,-0.56 2.37,1.7 1.7,0 0,0 0.64,0.61 89.73,89.73 0,0 0,28.29 10.15c4.74,0.81 13.83,0.63 16.4,-4.11 3,-5.59 1.52,-10.36 0,-17 -0.66,-2.82 0.13,-5.78 -0.93,-8.44 -1.8,-4.51 -6.79,-8.14 -11.84,-6.81 -5.57,1.47 -10.46,7.66 -7.77,13.69q3.13,7 10.69,7a1.32,1.32 0,0 1,1.51 1.43\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M258.74,323c-4.24,6 -8,-2.7 -9.08,-5.69a1.92,1.92 0,0 0,-2.24 -1.23,21.29 21.29,0 0,0 -6.63,2.68 1.86,1.86 0,0 0,-0.8 2.55c3.17,7.55 12,19.16 21.61,12.47q5.94,-4.15 9.42,-12.37a2.53,2.53 0,0 0,-1.44 -3.69l-4.16,-1.88a2.34,2.34 0,0 0,-3.54 1.39,30.07 30.07,0 0,1 -3.14,5.77\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M252.39,295.58a1.36,1.36 0,0 1,-0.44 1.57,65 65,0 0,1 -6.55,4.29 2.69,2.69 0,0 1,-3.07 -0.08,124 124,0 0,1 -12.82,-10.07 0.93,0.93 0,0 0,-1.29 0c-4,4 -12.35,13 -12.18,18.91a2.06,2.06 0,0 0,1.92 2,26.58 26.58,0 0,0 11.29,-1.58 121.66,121.66 0,0 0,24.36 -12.43,212.63 212.63,0 0,0 25.07,-19.73c6,-5.5 14,-13.41 16,-21.4 1.65,-6.65 -13.58,-1.58 -16.06,-0.51q-6,2.61 -12.34,5.71a0.54,0.54 0,0 0,-0.25 0.71,0.64 0.64,0 0,0 0.19,0.21 137.63,137.63 0,0 1,12.46 9.29,2 2,0 0,1 0.3,3.15 21.39,21.39 0,0 1,-6 5.14,2.06 2.06,0 0,1 -2.34,-0.21 134.52,134.52 0,0 0,-14.92 -10.77,0.78 0.78,0 0,0 -0.9,0 157.9,157.9 0,0 0,-17.7 13.43,0.33 0.33,0 0,0 0,0.45l0.06,0.05q7.53,5.38 14.56,10.95a2.16,2.16 0,0 1,0.68 0.9\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M261.87,275a8.83,8.83 0,0 0,-12.49 0l-2,2a8.82,8.82 0,0 0,0 12.48h0l2,2a8.83,8.83 0,0 0,12.49 0l2,-2a8.82,8.82 0,0 0,0 -12.48h0l-2,-2\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#237c4b\"/>\n    <path\n        android:pathData=\"M304.6,123.77q25.48,14.78 37.52,40c5,10.5 7.2,21.79 8,33.18a1.4,1.4 0,0 1,-1.31 1.48h-0.08l-186.39,0.1a0.67,0.67 0,0 1,-0.67 -0.67c-0.09,-31.09 17.26,-57.72 43.91,-73.42a1.21,1.21 0,0 0,0.43 -1.64q-7.93,-13.45 -15.7,-27.43a12.35,12.35 0,0 1,-1.87 -7.43c0.68,-5.57 5.72,-5.35 9.95,-4.78a1.81,1.81 0,0 1,1 0.49c3.61,3.44 6.11,8.66 8.21,13.08 3.58,7.57 6.93,13.53 10.77,20a1.15,1.15 0,0 0,1.41 0.5,94.62 94.62,0 0,1 26,-6c15.29,-1.15 31.36,0.5 45.76,6a0.86,0.86 0,0 0,1.07 -0.39c3.87,-7.23 8.21,-14.11 11.54,-21.59a60.66,60.66 0,0 1,5.37 -9.64c2.28,-3.32 4.42,-2.57 7.93,-2.69a3.79,3.79 0,0 1,3.18 1.44,7.08 7.08,0 0,1 1.31,7.8q-3,6.9 -17.56,30.9A0.45,0.45 0,0 0,304.6 123.77ZM202.24,142.7a73.29,73.29 0,0 0,-26 41.57,0.6 0.6,0 0,0 0.46,0.71h0.12q78.3,0 156.93,0a3,3 0,0 0,1 -0.16,0.52 0.52,0 0,0 0.39,-0.7c-2.83,-12 -8.39,-23.5 -16.83,-32.58a93.87,93.87 0,0 0,-21.1 -17.25,63.89 63.89,0 0,0 -13.06,-5.64 98.42,98.42 0,0 0,-13.78 -3.44,89.93 89.93,0 0,0 -45.77,4.37 61,61 0,0 0,-13.44 6.6Q206.56,139.24 202.24,142.7Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M156,309.12a21.63,21.63 0,0 1,-19.68 21.15q-13,1.07 -20.5,-9.7a10.64,10.64 0,0 1,-1.8 -6q0,-49.69 0,-98.85a9.93,9.93 0,0 1,1.81 -5.86,22.21 22.21,0 0,1 35.45,-1.63c3.62,4.36 4.75,9.37 4.75,14.87Q156,265.18 156,309.12ZM142.95,222.12a8.63,8.63 0,0 0,-8.63 -8.63L134,213.49a8.63,8.63 0,0 0,-8.63 8.63h0L125.37,308.7a8.63,8.63 0,0 0,8.63 8.63h0.3A8.63,8.63 0,0 0,143 308.7Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M399,308.83a21.3,21.3 0,0 1,-21.27 21.34h-1.48A21.3,21.3 0,0 1,355 308.91h0l-0.16,-87.22a21.3,21.3 0,0 1,21.27 -21.34h1.48a21.3,21.3 0,0 1,21.33 21.26h0ZM385.48,221.45a7.87,7.87 0,0 0,-7.84 -7.9h-1a7.87,7.87 0,0 0,-7.9 7.84l-0.3,88a7.87,7.87 0,0 0,7.84 7.9h1a7.87,7.87 0,0 0,7.9 -7.84Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M242.54,363.52q-0.09,22.29 0.09,44.46c0.07,8.21 -4.76,15 -11.91,19.12 -4.3,2.49 -9.53,2.16 -14.42,1.79 -6.54,-0.5 -13,-7.88 -15.17,-13.15a22.1,22.1 0,0 1,-1.47 -8.58q0.12,-22.4 0.08,-43.79a0.42,0.42 0,0 0,-0.42 -0.41c-11.48,0.22 -22.67,1.25 -31.25,-7.75 -6.34,-6.66 -6.64,-12.59 -6.6,-22.33q0.27,-66.81 -0.08,-128a0.83,0.83 0,0 1,0.82 -0.83h187a0.8,0.8 0,0 1,0.8 0.81q0,64.92 0,129.87c0,16.14 -8.17,27.31 -25.11,28.21a115.4,115.4 0,0 1,-11.91 0c-0.77,0 -1.14,0.33 -1.13,1.09q0.19,21.76 0.07,41.42 -0.09,13 -10.08,20.67a15,15 0,0 1,-9.09 3c-3.37,0 -7.6,0.32 -10.62,-1.18q-9.9,-4.9 -12.66,-13.73 -1.54,-4.92 -1.41,-16 0.19,-17.55 0.06,-34.75a0.45,0.45 0,0 0,-0.52 -0.51l-24.62,0.05A0.48,0.48 0,0 0,242.54 363.52ZM204.46,350.63c5.26,1.85 7.52,8.11 7.51,13.3q0,18.68 0,40.92a18.92,18.92 0,0 0,0.66 5A8.41,8.41 0,0 0,225 415q5,-2.91 5,-10.15 -0.07,-20.33 0,-42.76 0,-7.64 6.29,-11.18a17.67,17.67 0,0 1,7.48 -1.69q12.3,0 23.73,0a5.94,5.94 0,0 1,1.77 0.27c1.44,0.45 3,0.49 4.37,1.13q7.94,3.69 7.85,12.49 -0.25,23.72 0.25,43.09a10.52,10.52 0,0 0,3.45 7.89,8.43 8.43,0 0,0 13.05,-2.88 13.45,13.45 0,0 0,1 -5.33q-0.1,-20.39 0,-39.88c0,-6.48 2.17,-13.84 9,-15.7a24,24 0,0 1,6 -1.08q5.76,0 11.39,0.07a10.06,10.06 0,0 0,8.7 -3.85c2.38,-3.09 2.06,-7.7 2,-11.44q-0.24,-50.9 0,-100.2 0,-8.13 0.52,-16.54a0.48,0.48 0,0 0,-0.45 -0.51h-161a0.48,0.48 0,0 0,-0.49 0.48h0q0,59.14 -0.07,118.94c0,5.08 0.71,9.07 5.52,11.79a12.21,12.21 0,0 0,6.63 1.36C192.72,349.13 198.89,348.68 204.46,350.63Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M256.14,241.06a1.83,1.83 0,0 0,-2.08 0.34A19.08,19.08 0,0 0,249.4 249a2.42,2.42 0,0 1,-3 1.54l-0.14,-0.05c-1.93,-0.76 -4.88,-1.53 -6.39,-3a1,1 0,0 1,-0.29 -0.94,14.06 14.06,0 0,1 1.4,-3.83c4.31,-8 12.47,-16.89 21.57,-9.18A28.37,28.37 0,0 1,270.78 245a1.7,1.7 0,0 1,-1 2.45l-5.18,2.23a1.87,1.87 0,0 1,-2.66 -0.93C260.65,246.47 258.61,242.27 256.14,241.06Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M244,262.69c-7.5,-3.81 -17.85,-8.76 -25.87,-8.09a2.54,2.54 0,0 0,-2.53 2.4,3.7 3.7,0 0,0 3.23,4.21c9.07,1.09 12.52,11.27 5.94,17.65q-5,4.83 -11.39,1.84c-4.56,-2.14 -6.08,-6.84 -5.19,-11.62a8,8 0,0 0,-0.25 -4.07c-1.1,-3.27 -2.32,-6.6 -2.12,-10.08 0.91,-15.73 21.76,-10.55 30.71,-7.3a136.77,136.77 0,0 1,18.21 8.14,0.79 0.79,0 0,0 0.84,0 98.9,98.9 0,0 1,22.7 -10.19,40.62 40.62,0 0,1 15.52,-2.07c3.62,0.3 9.33,2.47 10.17,6.6a24.68,24.68 0,0 1,-2.5 16.87c-8.27,14.21 -22.24,27.08 -35.09,35.66 -5.22,3.49 -10.51,7.38 -16,10.29 -9.88,5.27 -22.24,10.35 -33.21,9.79 -16.32,-0.85 -11.45,-19 -5.94,-27.34a77.72,77.72 0,0 1,9.36 -11.74c7.3,-7.39 14.69,-14.37 23.42,-20.14a0.45,0.45 0,0 0,0.14 -0.62A0.55,0.55 0,0 0,244 262.69ZM252.39,295.58a1.36,1.36 0,0 1,-0.44 1.57,65 65,0 0,1 -6.55,4.29 2.69,2.69 0,0 1,-3.07 -0.08,124 124,0 0,1 -12.82,-10.07 0.93,0.93 0,0 0,-1.29 0c-4,4 -12.35,13 -12.18,18.91a2.06,2.06 0,0 0,1.92 2,26.58 26.58,0 0,0 11.29,-1.58 121.66,121.66 0,0 0,24.36 -12.43,212.63 212.63,0 0,0 25.07,-19.73c6,-5.5 14,-13.41 16,-21.4 1.65,-6.65 -13.58,-1.58 -16.06,-0.51q-6,2.61 -12.34,5.71a0.54,0.54 0,0 0,-0.25 0.71,0.64 0.64,0 0,0 0.19,0.21 137.63,137.63 0,0 1,12.46 9.29,2 2,0 0,1 0.3,3.15 21.39,21.39 0,0 1,-6 5.14,2.06 2.06,0 0,1 -2.34,-0.21 134.52,134.52 0,0 0,-14.92 -10.77,0.78 0.78,0 0,0 -0.9,0 157.9,157.9 0,0 0,-17.7 13.43,0.33 0.33,0 0,0 0,0.45l0.06,0.05q7.53,5.38 14.56,10.95A2.16,2.16 0,0 1,252.39 295.58Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M247.42,276.94L249.39,274.98A8.83,8.83 90.2,0 1,261.88 275.02L263.88,277.04A8.83,8.83 90.2,0 1,263.83 289.53L261.86,291.49A8.83,8.83 90.2,0 1,249.37 291.44L247.37,289.43A8.83,8.83 90.2,0 1,247.42 276.94z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M293.62,306.14q-7.56,0 -10.69,-7c-2.69,-6 2.2,-12.22 7.77,-13.69 5.05,-1.33 10,2.3 11.84,6.81 1.06,2.66 0.27,5.62 0.93,8.44 1.56,6.67 3.08,11.44 0,17 -2.57,4.74 -11.66,4.92 -16.4,4.11a89.73,89.73 0,0 1,-28.29 -10.15,1.73 1.73,0 0,1 -0.69,-2.34 1.78,1.78 0,0 1,0.61 -0.64l6.94,-4.3a2.45,2.45 0,0 1,2.4 -0.11c7.44,3.73 16.71,8.08 24.95,7.42a2.06,2.06 0,0 0,2.13 -2.28c0,-0.63 0,-1.25 0,-1.88A1.32,1.32 0,0 0,293.62 306.14Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M249.66,317.34c1.05,3 4.84,11.72 9.08,5.69a30.07,30.07 0,0 0,3.14 -5.77,2.34 2.34,0 0,1 3.54,-1.39l4.16,1.88a2.53,2.53 0,0 1,1.44 3.69q-3.48,8.22 -9.42,12.37c-9.59,6.69 -18.44,-4.92 -21.61,-12.47a1.86,1.86 0,0 1,0.8 -2.55,21.29 21.29,0 0,1 6.63,-2.68A1.92,1.92 0,0 1,249.66 317.34Z\"\n        android:fillColor=\"#3ddc84\"/>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_monochrome.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"512\"\n    android:viewportHeight=\"512\">\n  <group android:scaleX=\"0.7135135\"\n      android:scaleY=\"0.7135135\"\n      android:translateX=\"73.34054\"\n      android:translateY=\"73.34054\">\n    <path\n        android:pathData=\"M304.42,123.08Q319,99.08 322,92.18a7.08,7.08 0,0 0,-1.31 -7.8,3.79 3.79,0 0,0 -3.18,-1.44c-3.51,0.12 -5.65,-0.63 -7.93,2.69a60.66,60.66 0,0 0,-5.37 9.64c-3.33,7.48 -7.67,14.36 -11.54,21.59a0.86,0.86 0,0 1,-1.07 0.39c-14.4,-5.52 -30.47,-7.17 -45.76,-6a94.62,94.62 0,0 0,-26 6,1.15 1.15,0 0,1 -1.41,-0.5c-3.84,-6.48 -7.19,-12.44 -10.77,-20 -2.1,-4.42 -4.6,-9.64 -8.21,-13.08a1.81,1.81 0,0 0,-1 -0.49c-4.23,-0.57 -9.27,-0.79 -9.95,4.78a12.35,12.35 0,0 0,1.87 7.43q7.75,14 15.7,27.43a1.21,1.21 0,0 1,-0.43 1.64c-26.65,15.7 -44,42.33 -43.91,73.42a0.67,0.67 0,0 0,0.67 0.67l186.39,-0.1a1.39,1.39 0,0 0,1.39 -1.4v-0.08c-0.76,-11.39 -2.94,-22.68 -8,-33.18q-12,-25.2 -37.52,-40a0.45,0.45 0,0 1,-0.18 -0.69\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M136.32,330.27A21.63,21.63 0,0 0,156 309.12q0,-43.94 0,-86c0,-5.5 -1.13,-10.51 -4.75,-14.87a22.21,22.21 0,0 0,-35.45 1.63,9.93 9.93,0 0,0 -1.81,5.86q0,49.15 0,98.85a10.64,10.64 0,0 0,1.8 6q7.55,10.76 20.5,9.7\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M398.87,221.61a21.3,21.3 0,0 0,-21.33 -21.26h-1.48a21.3,21.3 0,0 0,-21.27 21.34l0.16,87.22a21.3,21.3 0,0 0,21.33 21.26h1.48A21.3,21.3 0,0 0,399 308.83l-0.16,-87.22\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M243.08,363l24.62,-0.05a0.45,0.45 0,0 1,0.52 0.51q0.13,17.21 -0.06,34.75 -0.14,11 1.41,16 2.76,8.84 12.66,13.73c3,1.5 7.25,1.17 10.62,1.18a15,15 0,0 0,9.09 -3q10,-7.66 10.08,-20.67 0.14,-19.67 -0.07,-41.42c0,-0.76 0.36,-1.12 1.13,-1.09a115.4,115.4 0,0 0,11.91 0c16.94,-0.9 25.13,-12.07 25.11,-28.21q-0.06,-64.95 0,-129.87a0.8,0.8 0,0 0,-0.8 -0.81h-187a0.83,0.83 0,0 0,-0.82 0.83h0q0.35,61.24 0.08,128c0,9.74 0.26,15.67 6.6,22.33 8.58,9 19.77,8 31.25,7.75a0.42,0.42 0,0 1,0.42 0.41q0,21.4 -0.08,43.79a22.1,22.1 0,0 0,1.47 8.58c2.18,5.27 8.63,12.65 15.17,13.15 4.89,0.37 10.12,0.7 14.42,-1.79 7.15,-4.16 12,-10.91 11.91,-19.12q-0.18,-22.17 -0.09,-44.46a0.48,0.48 0,0 1,0.54 -0.54\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M202.24,142.7a73.29,73.29 0,0 0,-26 41.57,0.6 0.6,0 0,0 0.46,0.71h0.12q78.3,0 156.93,0a3,3 0,0 0,1 -0.16,0.52 0.52,0 0,0 0.39,-0.7c-2.83,-12 -8.39,-23.5 -16.83,-32.58a93.87,93.87 0,0 0,-21.1 -17.25,63.89 63.89,0 0,0 -13.06,-5.64 98.42,98.42 0,0 0,-13.78 -3.44,89.93 89.93,0 0,0 -45.77,4.37 61,61 0,0 0,-13.44 6.6q-4.54,3.09 -8.86,6.55\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M143,222.08a8.63,8.63 0,0 0,-8.63 -8.63H134a8.63,8.63 0,0 0,-8.63 8.63h0V308.7a8.63,8.63 0,0 0,8.63 8.63h0.3A8.63,8.63 0,0 0,143 308.7V222.08\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M385.51,221.45a7.87,7.87 0,0 0,-7.84 -7.9h-1a7.87,7.87 0,0 0,-7.9 7.84l-0.3,88a7.87,7.87 0,0 0,7.84 7.9h1a7.87,7.87 0,0 0,7.9 -7.84l0.3,-88\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M204.46,350.63c5.26,1.85 7.52,8.11 7.51,13.3q0,18.68 0,40.92a18.92,18.92 0,0 0,0.66 5A8.41,8.41 0,0 0,225 415q5,-2.91 5,-10.15 -0.07,-20.33 0,-42.76 0,-7.64 6.29,-11.18a17.67,17.67 0,0 1,7.48 -1.69q12.3,0 23.73,0a5.94,5.94 0,0 1,1.77 0.27c1.44,0.45 3,0.49 4.37,1.13q7.94,3.69 7.85,12.49 -0.25,23.72 0.25,43.09a10.52,10.52 0,0 0,3.45 7.89,8.43 8.43,0 0,0 13.05,-2.88 13.45,13.45 0,0 0,1 -5.33q-0.1,-20.39 0,-39.88c0,-6.48 2.17,-13.84 9,-15.7a24,24 0,0 1,6 -1.08q5.76,0 11.39,0.07a10.06,10.06 0,0 0,8.7 -3.85c2.38,-3.09 2.06,-7.7 2,-11.44q-0.24,-50.9 0,-100.2 0,-8.13 0.52,-16.54a0.48,0.48 0,0 0,-0.45 -0.51h-161a0.48,0.48 0,0 0,-0.49 0.48h0q0,59.14 -0.07,118.94c0,5.08 0.71,9.07 5.52,11.79a12.21,12.21 0,0 0,6.63 1.36c5.86,-0.24 12,-0.69 17.6,1.26\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M256.14,241.06c2.47,1.21 4.51,5.41 5.77,7.73a1.87,1.87 0,0 0,2.66 0.93l5.18,-2.23a1.7,1.7 0,0 0,1 -2.45,28.37 28.37,0 0,0 -8.27,-11.56c-9.1,-7.71 -17.26,1.13 -21.57,9.18a14.06,14.06 0,0 0,-1.4 3.83,1 1,0 0,0 0.29,0.94c1.51,1.49 4.46,2.26 6.39,3a2.41,2.41 0,0 0,3.13 -1.35l0.05,-0.14a19.08,19.08 0,0 1,4.66 -7.56,1.83 1.83,0 0,1 2.08,-0.34\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M244,262.69a0.45,0.45 0,0 1,0.2 0.6,0.4 0.4,0 0,1 -0.16,0.18c-8.73,5.77 -16.12,12.75 -23.42,20.14a77.72,77.72 0,0 0,-9.36 11.74c-5.51,8.31 -10.38,26.49 5.94,27.34 11,0.56 23.33,-4.52 33.21,-9.79 5.46,-2.91 10.75,-6.8 16,-10.29C279.23,294 293.2,281.16 301.47,267a24.68,24.68 0,0 0,2.5 -16.87c-0.84,-4.13 -6.55,-6.3 -10.17,-6.6a40.62,40.62 0,0 0,-15.52 2.07,98.9 98.9,0 0,0 -22.7,10.19 0.79,0.79 0,0 1,-0.84 0,136.77 136.77,0 0,0 -18.21,-8.14c-8.95,-3.25 -29.8,-8.43 -30.71,7.3 -0.2,3.48 1,6.81 2.12,10.08a8,8 0,0 1,0.25 4.07c-0.89,4.78 0.63,9.48 5.19,11.62q6.41,3 11.39,-1.84c6.58,-6.38 3.13,-16.56 -5.94,-17.65A3.7,3.7 0,0 1,215.6 257a2.54,2.54 0,0 1,2.53 -2.4c8,-0.67 18.37,4.28 25.87,8.09\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M295.13,307.57c0,0.63 0,1.25 0,1.88a2.06,2.06 0,0 1,-2.13 2.28c-8.24,0.66 -17.51,-3.69 -24.95,-7.42a2.45,2.45 0,0 0,-2.4 0.11l-6.94,4.3a1.72,1.72 0,0 0,-0.56 2.37,1.7 1.7,0 0,0 0.64,0.61 89.73,89.73 0,0 0,28.29 10.15c4.74,0.81 13.83,0.63 16.4,-4.11 3,-5.59 1.52,-10.36 0,-17 -0.66,-2.82 0.13,-5.78 -0.93,-8.44 -1.8,-4.51 -6.79,-8.14 -11.84,-6.81 -5.57,1.47 -10.46,7.66 -7.77,13.69q3.13,7 10.69,7a1.32,1.32 0,0 1,1.51 1.43\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M258.74,323c-4.24,6 -8,-2.7 -9.08,-5.69a1.92,1.92 0,0 0,-2.24 -1.23,21.29 21.29,0 0,0 -6.63,2.68 1.86,1.86 0,0 0,-0.8 2.55c3.17,7.55 12,19.16 21.61,12.47q5.94,-4.15 9.42,-12.37a2.53,2.53 0,0 0,-1.44 -3.69l-4.16,-1.88a2.34,2.34 0,0 0,-3.54 1.39,30.07 30.07,0 0,1 -3.14,5.77\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M252.39,295.58a1.36,1.36 0,0 1,-0.44 1.57,65 65,0 0,1 -6.55,4.29 2.69,2.69 0,0 1,-3.07 -0.08,124 124,0 0,1 -12.82,-10.07 0.93,0.93 0,0 0,-1.29 0c-4,4 -12.35,13 -12.18,18.91a2.06,2.06 0,0 0,1.92 2,26.58 26.58,0 0,0 11.29,-1.58 121.66,121.66 0,0 0,24.36 -12.43,212.63 212.63,0 0,0 25.07,-19.73c6,-5.5 14,-13.41 16,-21.4 1.65,-6.65 -13.58,-1.58 -16.06,-0.51q-6,2.61 -12.34,5.71a0.54,0.54 0,0 0,-0.25 0.71,0.64 0.64,0 0,0 0.19,0.21 137.63,137.63 0,0 1,12.46 9.29,2 2,0 0,1 0.3,3.15 21.39,21.39 0,0 1,-6 5.14,2.06 2.06,0 0,1 -2.34,-0.21 134.52,134.52 0,0 0,-14.92 -10.77,0.78 0.78,0 0,0 -0.9,0 157.9,157.9 0,0 0,-17.7 13.43,0.33 0.33,0 0,0 0,0.45l0.06,0.05q7.53,5.38 14.56,10.95a2.16,2.16 0,0 1,0.68 0.9\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M261.87,275a8.83,8.83 0,0 0,-12.49 0l-2,2a8.82,8.82 0,0 0,0 12.48h0l2,2a8.83,8.83 0,0 0,12.49 0l2,-2a8.82,8.82 0,0 0,0 -12.48h0l-2,-2\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#FF000000\"/>\n    <path\n        android:pathData=\"M304.6,123.77q25.48,14.78 37.52,40c5,10.5 7.2,21.79 8,33.18a1.4,1.4 0,0 1,-1.31 1.48h-0.08l-186.39,0.1a0.67,0.67 0,0 1,-0.67 -0.67c-0.09,-31.09 17.26,-57.72 43.91,-73.42a1.21,1.21 0,0 0,0.43 -1.64q-7.93,-13.45 -15.7,-27.43a12.35,12.35 0,0 1,-1.87 -7.43c0.68,-5.57 5.72,-5.35 9.95,-4.78a1.81,1.81 0,0 1,1 0.49c3.61,3.44 6.11,8.66 8.21,13.08 3.58,7.57 6.93,13.53 10.77,20a1.15,1.15 0,0 0,1.41 0.5,94.62 94.62,0 0,1 26,-6c15.29,-1.15 31.36,0.5 45.76,6a0.86,0.86 0,0 0,1.07 -0.39c3.87,-7.23 8.21,-14.11 11.54,-21.59a60.66,60.66 0,0 1,5.37 -9.64c2.28,-3.32 4.42,-2.57 7.93,-2.69a3.79,3.79 0,0 1,3.18 1.44,7.08 7.08,0 0,1 1.31,7.8q-3,6.9 -17.56,30.9A0.45,0.45 0,0 0,304.6 123.77ZM202.24,142.7a73.29,73.29 0,0 0,-26 41.57,0.6 0.6,0 0,0 0.46,0.71h0.12q78.3,0 156.93,0a3,3 0,0 0,1 -0.16,0.52 0.52,0 0,0 0.39,-0.7c-2.83,-12 -8.39,-23.5 -16.83,-32.58a93.87,93.87 0,0 0,-21.1 -17.25,63.89 63.89,0 0,0 -13.06,-5.64 98.42,98.42 0,0 0,-13.78 -3.44,89.93 89.93,0 0,0 -45.77,4.37 61,61 0,0 0,-13.44 6.6Q206.56,139.24 202.24,142.7Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M156,309.12a21.63,21.63 0,0 1,-19.68 21.15q-13,1.07 -20.5,-9.7a10.64,10.64 0,0 1,-1.8 -6q0,-49.69 0,-98.85a9.93,9.93 0,0 1,1.81 -5.86,22.21 22.21,0 0,1 35.45,-1.63c3.62,4.36 4.75,9.37 4.75,14.87Q156,265.18 156,309.12ZM142.95,222.12a8.63,8.63 0,0 0,-8.63 -8.63L134,213.49a8.63,8.63 0,0 0,-8.63 8.63h0L125.37,308.7a8.63,8.63 0,0 0,8.63 8.63h0.3A8.63,8.63 0,0 0,143 308.7Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M399,308.83a21.3,21.3 0,0 1,-21.27 21.34h-1.48A21.3,21.3 0,0 1,355 308.91h0l-0.16,-87.22a21.3,21.3 0,0 1,21.27 -21.34h1.48a21.3,21.3 0,0 1,21.33 21.26h0ZM385.48,221.45a7.87,7.87 0,0 0,-7.84 -7.9h-1a7.87,7.87 0,0 0,-7.9 7.84l-0.3,88a7.87,7.87 0,0 0,7.84 7.9h1a7.87,7.87 0,0 0,7.9 -7.84Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M242.54,363.52q-0.09,22.29 0.09,44.46c0.07,8.21 -4.76,15 -11.91,19.12 -4.3,2.49 -9.53,2.16 -14.42,1.79 -6.54,-0.5 -13,-7.88 -15.17,-13.15a22.1,22.1 0,0 1,-1.47 -8.58q0.12,-22.4 0.08,-43.79a0.42,0.42 0,0 0,-0.42 -0.41c-11.48,0.22 -22.67,1.25 -31.25,-7.75 -6.34,-6.66 -6.64,-12.59 -6.6,-22.33q0.27,-66.81 -0.08,-128a0.83,0.83 0,0 1,0.82 -0.83h187a0.8,0.8 0,0 1,0.8 0.81q0,64.92 0,129.87c0,16.14 -8.17,27.31 -25.11,28.21a115.4,115.4 0,0 1,-11.91 0c-0.77,0 -1.14,0.33 -1.13,1.09q0.19,21.76 0.07,41.42 -0.09,13 -10.08,20.67a15,15 0,0 1,-9.09 3c-3.37,0 -7.6,0.32 -10.62,-1.18q-9.9,-4.9 -12.66,-13.73 -1.54,-4.92 -1.41,-16 0.19,-17.55 0.06,-34.75a0.45,0.45 0,0 0,-0.52 -0.51l-24.62,0.05A0.48,0.48 0,0 0,242.54 363.52ZM204.46,350.63c5.26,1.85 7.52,8.11 7.51,13.3q0,18.68 0,40.92a18.92,18.92 0,0 0,0.66 5A8.41,8.41 0,0 0,225 415q5,-2.91 5,-10.15 -0.07,-20.33 0,-42.76 0,-7.64 6.29,-11.18a17.67,17.67 0,0 1,7.48 -1.69q12.3,0 23.73,0a5.94,5.94 0,0 1,1.77 0.27c1.44,0.45 3,0.49 4.37,1.13q7.94,3.69 7.85,12.49 -0.25,23.72 0.25,43.09a10.52,10.52 0,0 0,3.45 7.89,8.43 8.43,0 0,0 13.05,-2.88 13.45,13.45 0,0 0,1 -5.33q-0.1,-20.39 0,-39.88c0,-6.48 2.17,-13.84 9,-15.7a24,24 0,0 1,6 -1.08q5.76,0 11.39,0.07a10.06,10.06 0,0 0,8.7 -3.85c2.38,-3.09 2.06,-7.7 2,-11.44q-0.24,-50.9 0,-100.2 0,-8.13 0.52,-16.54a0.48,0.48 0,0 0,-0.45 -0.51h-161a0.48,0.48 0,0 0,-0.49 0.48h0q0,59.14 -0.07,118.94c0,5.08 0.71,9.07 5.52,11.79a12.21,12.21 0,0 0,6.63 1.36C192.72,349.13 198.89,348.68 204.46,350.63Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M256.14,241.06a1.83,1.83 0,0 0,-2.08 0.34A19.08,19.08 0,0 0,249.4 249a2.42,2.42 0,0 1,-3 1.54l-0.14,-0.05c-1.93,-0.76 -4.88,-1.53 -6.39,-3a1,1 0,0 1,-0.29 -0.94,14.06 14.06,0 0,1 1.4,-3.83c4.31,-8 12.47,-16.89 21.57,-9.18A28.37,28.37 0,0 1,270.78 245a1.7,1.7 0,0 1,-1 2.45l-5.18,2.23a1.87,1.87 0,0 1,-2.66 -0.93C260.65,246.47 258.61,242.27 256.14,241.06Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M244,262.69c-7.5,-3.81 -17.85,-8.76 -25.87,-8.09a2.54,2.54 0,0 0,-2.53 2.4,3.7 3.7,0 0,0 3.23,4.21c9.07,1.09 12.52,11.27 5.94,17.65q-5,4.83 -11.39,1.84c-4.56,-2.14 -6.08,-6.84 -5.19,-11.62a8,8 0,0 0,-0.25 -4.07c-1.1,-3.27 -2.32,-6.6 -2.12,-10.08 0.91,-15.73 21.76,-10.55 30.71,-7.3a136.77,136.77 0,0 1,18.21 8.14,0.79 0.79,0 0,0 0.84,0 98.9,98.9 0,0 1,22.7 -10.19,40.62 40.62,0 0,1 15.52,-2.07c3.62,0.3 9.33,2.47 10.17,6.6a24.68,24.68 0,0 1,-2.5 16.87c-8.27,14.21 -22.24,27.08 -35.09,35.66 -5.22,3.49 -10.51,7.38 -16,10.29 -9.88,5.27 -22.24,10.35 -33.21,9.79 -16.32,-0.85 -11.45,-19 -5.94,-27.34a77.72,77.72 0,0 1,9.36 -11.74c7.3,-7.39 14.69,-14.37 23.42,-20.14a0.45,0.45 0,0 0,0.14 -0.62A0.55,0.55 0,0 0,244 262.69ZM252.39,295.58a1.36,1.36 0,0 1,-0.44 1.57,65 65,0 0,1 -6.55,4.29 2.69,2.69 0,0 1,-3.07 -0.08,124 124,0 0,1 -12.82,-10.07 0.93,0.93 0,0 0,-1.29 0c-4,4 -12.35,13 -12.18,18.91a2.06,2.06 0,0 0,1.92 2,26.58 26.58,0 0,0 11.29,-1.58 121.66,121.66 0,0 0,24.36 -12.43,212.63 212.63,0 0,0 25.07,-19.73c6,-5.5 14,-13.41 16,-21.4 1.65,-6.65 -13.58,-1.58 -16.06,-0.51q-6,2.61 -12.34,5.71a0.54,0.54 0,0 0,-0.25 0.71,0.64 0.64,0 0,0 0.19,0.21 137.63,137.63 0,0 1,12.46 9.29,2 2,0 0,1 0.3,3.15 21.39,21.39 0,0 1,-6 5.14,2.06 2.06,0 0,1 -2.34,-0.21 134.52,134.52 0,0 0,-14.92 -10.77,0.78 0.78,0 0,0 -0.9,0 157.9,157.9 0,0 0,-17.7 13.43,0.33 0.33,0 0,0 0,0.45l0.06,0.05q7.53,5.38 14.56,10.95A2.16,2.16 0,0 1,252.39 295.58Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M247.42,276.94L249.39,274.98A8.83,8.83 90.2,0 1,261.88 275.02L263.88,277.04A8.83,8.83 90.2,0 1,263.83 289.53L261.86,291.49A8.83,8.83 90.2,0 1,249.37 291.44L247.37,289.43A8.83,8.83 90.2,0 1,247.42 276.94z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M293.62,306.14q-7.56,0 -10.69,-7c-2.69,-6 2.2,-12.22 7.77,-13.69 5.05,-1.33 10,2.3 11.84,6.81 1.06,2.66 0.27,5.62 0.93,8.44 1.56,6.67 3.08,11.44 0,17 -2.57,4.74 -11.66,4.92 -16.4,4.11a89.73,89.73 0,0 1,-28.29 -10.15,1.73 1.73,0 0,1 -0.69,-2.34 1.78,1.78 0,0 1,0.61 -0.64l6.94,-4.3a2.45,2.45 0,0 1,2.4 -0.11c7.44,3.73 16.71,8.08 24.95,7.42a2.06,2.06 0,0 0,2.13 -2.28c0,-0.63 0,-1.25 0,-1.88A1.32,1.32 0,0 0,293.62 306.14Z\"\n        android:fillColor=\"#3ddc84\"/>\n    <path\n        android:pathData=\"M249.66,317.34c1.05,3 4.84,11.72 9.08,5.69a30.07,30.07 0,0 0,3.14 -5.77,2.34 2.34,0 0,1 3.54,-1.39l4.16,1.88a2.53,2.53 0,0 1,1.44 3.69q-3.48,8.22 -9.42,12.37c-9.59,6.69 -18.44,-4.92 -21.61,-12.47a1.86,1.86 0,0 1,0.8 -2.55,21.29 21.29,0 0,1 6.63,-2.68A1.92,1.92 0,0 1,249.66 317.34Z\"\n        android:fillColor=\"#3ddc84\"/>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/info_circle_filled.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:pathData=\"M12,2c5.523,0 10,4.477 10,10a10,10 0,0 1,-19.995 0.324l-0.005,-0.324l0.004,-0.28c0.148,-5.393 4.566,-9.72 9.996,-9.72zM12,11h-1l-0.117,0.007a1,1 0,0 0,0 1.986l0.117,0.007v3l0.007,0.117a1,1 0,0 0,0.876 0.876l0.117,0.007h1l0.117,-0.007a1,1 0,0 0,0.876 -0.876l0.007,-0.117l-0.007,-0.117a1,1 0,0 0,-0.764 -0.857l-0.112,-0.02l-0.117,-0.006v-3l-0.007,-0.117a1,1 0,0 0,-0.876 -0.876l-0.117,-0.007zM12.01,8l-0.127,0.007a1,1 0,0 0,0 1.986l0.117,0.007l0.127,-0.007a1,1 0,0 0,0 -1.986l-0.117,-0.007z\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"0\"\n        android:fillColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/launcher_splash.xml",
    "content": "<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@color/ic_launcher_background\" />\n    <item android:drawable=\"@drawable/ic_launcher_foreground\" />\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/package_import.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:pathData=\"M12,21l-8,-4.5v-9l8,-4.5l8,4.5v4.5\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M12,12l8,-4.5\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M12,12v9\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M12,12l-8,-4.5\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M22,18h-7\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M18,15l-3,3l3,3\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/play_circle.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"m380,660 l280,-180 -280,-180v360ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880ZM480,800q134,0 227,-93t93,-227q0,-134 -93,-227t-227,-93q-134,0 -227,93t-93,227q0,134 93,227t227,93ZM480,480Z\"\n      android:fillColor=\"#1f1f1f\"\n      android:strokeColor=\"#ffffffff\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/settings.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:pathData=\"M10.325,4.317c0.426,-1.756 2.924,-1.756 3.35,0a1.724,1.724 0,0 0,2.573 1.066c1.543,-0.94 3.31,0.826 2.37,2.37a1.724,1.724 0,0 0,1.065 2.572c1.756,0.426 1.756,2.924 0,3.35a1.724,1.724 0,0 0,-1.066 2.573c0.94,1.543 -0.826,3.31 -2.37,2.37a1.724,1.724 0,0 0,-2.572 1.065c-0.426,1.756 -2.924,1.756 -3.35,0a1.724,1.724 0,0 0,-2.573 -1.066c-1.543,0.94 -3.31,-0.826 -2.37,-2.37a1.724,1.724 0,0 0,-1.065 -2.572c-1.756,-0.426 -1.756,-2.924 0,-3.35a1.724,1.724 0,0 0,1.066 -2.573c-0.94,-1.543 0.826,-3.31 2.37,-2.37c1,0.608 2.296,0.07 2.572,-1.065z\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M9,12a3,3 0,1 0,6 0a3,3 0,0 0,-6 0\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/telegram.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"1024\"\n    android:viewportHeight=\"1024\">\n    <path\n        android:fillColor=\"#ffff\"\n        android:pathData=\"M769.45,245.76c21.08,-7.47 42.28,-15.36 65.19,-15.36 27.05,0.04 39.94,11.73 40.32,38.83 0.68,44.03 -8.66,87.17 -13.99,130.69 -2.99,24.32 -45.27,285.95 -64.77,392.19 -4.05,22.06 -7.04,44.37 -16.38,65.15 -15.15,33.66 -36.1,43.14 -71.21,31.7 -15.96,-5.21 -29.99,-13.99 -43.78,-23.34 -66.99,-45.27 -211.67,-142.98 -216.7,-146.99 -31.15,-24.87 -36.95,-45.4 -5.42,-78.59 34.86,-36.69 132.44,-124.37 143.15,-134.83a956.84,956.84 0,0 0,84.91 -83.03c5.85,-6.4 12.76,-13.4 5.21,-22.27 -7.34,-8.62 -15.79,-3.84 -23.17,0.73a2884.91,2884.91 0,0 0,-135.42 89.3c-53.72,35.71 -108.46,70.02 -160.77,107.65 -42.67,30.68 -86.74,41.26 -137.47,26.07 -37.89,-11.31 -76.12,-21.5 -113.15,-35.41 -13.87,-5.16 -30.29,-10.45 -30.98,-28.5 -0.6,-16.85 14.12,-24.45 26.79,-31.15 44.16,-23.34 310.61,-136.83 383.62,-166.91 94.55,-38.95 187.61,-81.71 284.03,-115.93z\" />\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/trash.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:pathData=\"M4,7l16,0\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M10,11l0,6\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M14,11l0,6\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M5,7l1,12a2,2 0,0 0,2 2h8a2,2 0,0 0,2 -2l1,-12\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M9,7v-3a1,1 0,0 1,1 -1h4a1,1 0,0 1,1 1v3\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/weblate.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"100dp\"\n    android:height=\"74dp\"\n    android:viewportWidth=\"100\"\n    android:viewportHeight=\"74\">\n    <path\n        android:pathData=\"M63.62,55.8a10.73,10.73 0,0 1,-4.24 -0.89c-3.06,-1.33 -5.75,-3.85 -7.94,-7.25a36.01,36.01 0,0 0,1.69 -3.43c2.2,-5.12 3.25,-10.73 3.33,-16.3a7.55,7.55 0,0 1,-0.03 -0.33l-0.01,-0.29c-0,-2.18 -0.34,-4.39 -1.09,-6.45 -0.87,-2.37 -2.24,-4.75 -4.43,-5.67a2.97,2.97 0,0 0,-1.23 -0.23c-2.75,-5.14 -2.84,-10.07 0,-14.77l0.15,0c3.35,0.04 6.67,1.07 9.51,2.88 7.74,4.92 11.59,14.5 11.68,23.91 0,0.11 0,0.22 -0,0.33h0.04c-0.01,9.94 -2.4,20.03 -7.44,28.49zM46.47,71.41c-7.22,2.97 -15.61,2.81 -22.77,-0.51 -8.24,-3.82 -14.53,-11.26 -18.41,-19.74 -6.63,-14.51 -6.78,-31.86 -0.49,-46.59 4.72,1.89 8.92,-1.12 8.92,-1.12s-0.01,4.63 4.47,6.95c-4.6,10.78 -4.49,23.58 0.12,34.09 2.22,5.05 5.61,9.76 10.31,12.42 1.68,0.95 3.52,1.56 5.42,1.79l0.02,0.03c3.35,5.22 7.57,9.58 12.41,12.68z\"\n        android:fillType=\"nonZero\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:startX=\"-1.49\"\n                android:startY=\"28.42\"\n                android:endX=\"48.03\"\n                android:endY=\"28.42\"\n                android:type=\"linear\">\n                <item android:offset=\"0\" android:color=\"#FF00D2E6\"/>\n                <item android:offset=\"1\" android:color=\"#FF2ECCAA\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:pathData=\"M63.62,55.81a10.73,10.73 0,0 1,-4.24 -0.89c-3.06,-1.33 -5.75,-3.85 -7.94,-7.25a36,36 0,0 0,1.69 -3.43,38.89 38.89,0 0,0 1.68,-4.75c1.06,-3.75 15.19,1.01 13.04,7.18a50.18,50.18 0,0 1,-4.23 9.14zM46.47,71.41c-7.22,2.97 -15.61,2.81 -22.77,-0.51 -8.24,-3.82 0.22,-16.65 4.92,-13.99a14.57,14.57 0,0 0,5.41 1.79l0.02,0.04c3.35,5.22 7.56,9.58 12.41,12.68z\"\n        android:strokeAlpha=\"0.7\"\n        android:fillType=\"evenOdd\"\n        android:fillAlpha=\"0.7\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:startX=\"24.88\"\n                android:startY=\"58.82\"\n                android:endX=\"58.55\"\n                android:endY=\"47.58\"\n                android:type=\"linear\">\n                <item android:offset=\"0\" android:color=\"#00000000\"/>\n                <item android:offset=\"0.51\" android:color=\"#FF000000\"/>\n                <item android:offset=\"1\" android:color=\"#00000000\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:pathData=\"M28.38,27.31a8.15,8.15 0,0 1,-0 -0.33c0.09,-9.41 3.94,-18.99 11.68,-23.91 2.84,-1.81 6.16,-2.84 9.51,-2.88h0.15v14.77a2.97,2.97 0,0 0,-1.23 0.23c-2.19,0.93 -3.57,3.3 -4.43,5.67 -0.75,2.06 -1.08,4.27 -1.09,6.45l-0.01,0.28a7.55,7.55 0,0 1,-0.03 0.33c0.08,5.57 1.13,11.18 3.33,16.3 2.47,5.74 6.39,11.01 11.93,13.42 4.18,1.82 8.81,1.39 12.59,-0.75 4.7,-2.66 8.09,-7.37 10.31,-12.42 4.61,-10.5 4.72,-23.31 0.12,-34.09C85.69,8.08 85.68,3.45 85.68,3.45s4.2,3.01 8.92,1.12c6.29,14.73 6.14,32.08 -0.49,46.59 -3.88,8.48 -10.17,15.92 -18.41,19.74 -7.33,3.4 -15.95,3.49 -23.3,0.29 -6.59,-2.87 -11.96,-8.05 -15.82,-14.07 -5.59,-8.72 -8.24,-19.34 -8.25,-29.8h0.04z\"\n        android:fillType=\"nonZero\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:startX=\"100.89\"\n                android:startY=\"29.66\"\n                android:endX=\"51.44\"\n                android:endY=\"29.66\"\n                android:type=\"linear\">\n                <item android:offset=\"0\" android:color=\"#FF1FA385\"/>\n                <item android:offset=\"1\" android:color=\"#FF2ECCAA\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/webui.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:pathData=\"M3,12a9,9 0,1 0,18 0a9,9 0,0 0,-18 0\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M3.6,9h16.8\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M3.6,15h16.8\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M11.5,3a17,17 0,0 0,0 18\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n    <path\n        android:pathData=\"M12.5,3a17,17 0,0 1,0 18\"\n        android:strokeLineJoin=\"round\"\n        android:strokeWidth=\"2\"\n        android:fillColor=\"#00000000\"\n        android:strokeColor=\"#ffff\"\n        android:strokeLineCap=\"round\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_launcher_monochrome\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/resources.properties",
    "content": "unqualifiedResLocale=en"
  },
  {
    "path": "app/src/main/res/values/arrays.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string-array name=\"languages\">\n        <item>@string/system_default</item>\n        <item>Deutsch</item>\n        <item>English</item>\n        <item>Español</item>\n        <item>Filipino</item>\n        <item>Français</item>\n        <item>Indonesia</item>\n        <item>Italiano</item>\n        <item>Jawa</item>\n        <item>Norsk bokmål</item>\n        <item>Polski</item>\n        <item>Português</item>\n        <item>Português (Brasil)</item>\n        <item>Română</item>\n        <item>Tiếng Việt</item>\n        <item>Türkçe</item>\n        <item>Ελληνικά</item>\n        <item>Русский</item>\n        <item>Українська</item>\n        <item>الْعَرَبيّة</item>\n        <item>বাংলা</item>\n        <item>සිංහල</item>\n        <item>ไทย</item>\n        <item>日本語</item>\n        <item>简体中文</item>\n        <item>繁體中文</item>\n    </string-array>\n\n    <string-array name=\"languages_values\">\n        <item>default</item>\n        <item>de</item>\n        <item>en</item>\n        <item>es</item>\n        <item>fil</item>\n        <item>fr</item>\n        <item>in</item>\n        <item>it</item>\n        <item>jv</item>\n        <item>nb-NO</item>\n        <item>pl</item>\n        <item>pt</item>\n        <item>pt-BR</item>\n        <item>ro</item>\n        <item>vi</item>\n        <item>tr</item>\n        <item>el</item>\n        <item>ru</item>\n        <item>uk</item>\n        <item>ar</item>\n        <item>bn</item>\n        <item>si</item>\n        <item>th</item>\n        <item>ja</item>\n        <item>zh-CN</item>\n        <item>zh-TW</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_launcher_background\">#081B11</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n\n    <string name=\"home\">Home</string>\n\n    <string name=\"search\">Search</string>\n    <string name=\"search_apps\">Search Apps</string>\n    <string name=\"search_modules\">Search modules</string>\n    <string name=\"back\">Back</string>\n    <string name=\"learn_more\">Learn more</string>\n\n    <string name=\"success\">Success</string>\n    <string name=\"failure\">Failure</string>\n\n    <string name=\"patch_warnning\">Installation comes with risks. Please ensure your data is backed up.</string>\n    <string name=\"patch\">Patch</string>\n\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n\n    <string name=\"reboot\">Reboot</string>\n    <string name=\"settings\">Settings</string>\n    <string name=\"reboot_recovery\">Reboot to Recovery</string>\n    <string name=\"reboot_bootloader\">Reboot to Bootloader</string>\n    <string name=\"reboot_download\">Reboot to Download</string>\n    <string name=\"reboot_edl\">Reboot to EDL</string>\n    <string name=\"about\">About</string>\n    <string name=\"settings_app_language\">Language</string>\n    <string name=\"system_default\">System default</string>\n    <string name=\"settings_global_namespace_mode\">Global namespace mode</string>\n    <string name=\"settings_global_namespace_mode_summary\">All root sessions use the global mount namespace</string>\n    <string name=\"settings_clear_super_key_dialog\">Do you really want to proceed?</string>\n\n    <string name=\"settings_check_update\">Check for updates</string>\n    <string name=\"settings_check_update_summary\">Automatically check for updates when opening the app</string>\n\n    <string name=\"home_learn_apatch\">Learn APatch</string>\n    <string name=\"home_click_to_learn_apatch\">Learn about the features of APatch and how to use</string>\n\n    <string name=\"about_source_code\"><![CDATA[<p>View source code at %1$s<p/>Join our %2$s channel<p/>Join our %3$s group]]></string>\n    <string name=\"send_log\">Send logs</string>\n    <string name=\"save_log\">Save logs</string>\n    <string name=\"log_saved\">Logs saved</string>\n    <string name=\"safe_mode\">Safe mode</string>\n\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"clear_super_key\">Clear SuperKey</string>\n    <string name=\"patch_set_superkey\">Set SuperKey</string>\n    <string name=\"home_patch_set_key_desc\">Only credential for KernelPatch</string>\n    <string name=\"home_patch_next_step\">Next step</string>\n\n    <string name=\"home_not_installed\">Not installed</string>\n    <string name=\"home_install_unknown\">Not installed or authenticated</string>\n    <string name=\"home_install_unknown_summary\">Click to install</string>\n    <string name=\"home_click_to_install\">Click to install</string>\n    <string name=\"home_working\">Working 😋</string>\n\n    <string name=\"home_installing\">Installing</string>\n    <string name=\"home_need_update\">New version available</string>\n    <string name=\"kpatch_version\">Version: %s</string>\n    <string name=\"apatch_version\">Version: %s</string>\n    <string name=\"apatch_version_update\">Version: %s -&gt; %s</string>\n    <string name=\"kpatch_version_update\">Version: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_auth_key_title\">Enter SuperKey</string>\n    <string name=\"home_auth_key_desc\">Start after certification</string>\n    <string name=\"home_kpatch_info_title\">Info</string>\n\n    <string name=\"home_ap_cando_install\">Install</string>\n    <string name=\"home_ap_cando_update\">Update</string>\n    <string name=\"home_ap_cando_uninstall\">Uninstall</string>\n    <string name=\"home_ap_cando_reboot\">Reboot</string>\n\n    <string name=\"patch_title\">Patch</string>\n\n    <string name=\"patch_config_title\">Patches</string>\n    <string name=\"patch_mode_bootimg_patch\">Mode: Patch</string>\n    <string name=\"patch_mode_patch_and_install\">Mode: Patch and install</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mode: Install to inactive slot (After OTA)</string>\n    <string name=\"patch_mode_uninstall_patch\">Mode: Uninstall KPatch</string>\n    <string name=\"patch_select_bootimg_btn\">Select boot</string>\n    <string name=\"patch_embed_kpm_btn\">Embed KPM</string>\n    <string name=\"patch_start_patch_btn\">Start</string>\n    <string name=\"patch_start_unpatch_btn\">UnPatch</string>\n    <string name=\"patch_item_error\">!!ERROR!!</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_bootimg_slot\">Slot:</string>\n    <string name=\"patch_item_bootimg_dev\">Device:</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Version:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Time:</string>\n    <string name=\"patch_item_kpimg_config\">Config:</string>\n    <string name=\"patch_item_new_extra_kpm\">Embed new</string>\n    <string name=\"patch_item_existed_extra_kpm\">Existed</string>\n    <string name=\"patch_item_extra_name\">Name:</string>\n    <string name=\"patch_item_extra_version\">Version:</string>\n    <string name=\"patch_item_extra_author\">Author:</string>\n    <string name=\"patch_item_extra_kpm_license\">License:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Description:</string>\n    <string name=\"patch_item_extra_args\">Args:</string>\n    <string name=\"patch_item_extra_event\">Event:</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"patch_item_set_skey_label\">The SuperKey should be 8-63 characters long and include numbers and letters, but no special characters.</string>\n\n    <string name=\"home_kernel\">Kernel version</string>\n    <string name=\"home_manager_version\">Manager version</string>\n    <string name=\"home_fingerprint\">Fingerprint</string>\n\n    <string name=\"home_selinux_status\">SELinux status</string>\n    <string name=\"home_selinux_status_disabled\">Disabled</string>\n    <string name=\"home_selinux_status_enforcing\">Enforcing</string>\n    <string name=\"home_selinux_status_permissive\">Permissive</string>\n    <string name=\"home_selinux_status_unknown\">Unknown</string>\n\n    <string name=\"home_device_info\">Device</string>\n    <string name=\"home_system_version\">System version</string>\n    <string name=\"home_kpatch_version\">KernelPatch version</string>\n    <string name=\"home_su_path\">Executable su</string>\n    <string name=\"home_apatch_version\">APatch version</string>\n\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch not installed</string>\n    <string name=\"kpm_add_kpm\">Add KPM</string>\n    <string name=\"kpm_load\">Load</string>\n    <string name=\"kpm_install\">Install</string>\n    <string name=\"kpm_embed\">Embed</string>\n    <string name=\"kpm_load_toast_succ\">Load succeed</string>\n    <string name=\"kpm_load_toast_failed\">Load failed</string>\n    <string name=\"kpm_unload_confirm\">Unload %s module?</string>\n    <string name=\"kpm_unload\">Unload</string>\n    <string name=\"kpm_control\">Control</string>\n    <string name=\"kpm_apm_empty\">No module loaded</string>\n    <string name=\"kpm_version\">Version</string>\n    <string name=\"kpm_license\">License</string>\n    <string name=\"kpm_author\">Author</string>\n    <string name=\"kpm_desc\">Desc</string>\n    <string name=\"kpm_args\">Args</string>\n\n    <string name=\"su_title\">Superuser</string>\n    <string name=\"su_selinux_via_hook\">Bypass via hook</string>\n    <string name=\"su_pkg_excluded_label\">Exclude</string>\n    <string name=\"su_pkg_excluded_setting_title\">Exclude modifications</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Enabling this option will allow APatch to restore any files modified by the modules of this app.</string>\n    <string name=\"su_show_system_apps\">Show system apps</string>\n    <string name=\"su_hide_system_apps\">Hide system apps</string>\n    <string name=\"su_refresh\">Refresh</string>\n\n    <string name=\"apm\">APModule</string>\n    <string name=\"apm_not_installed\">AndroidPatch not installed</string>\n    <string name=\"apm_failed_to_enable\">Failed to enable module: %s</string>\n    <string name=\"apm_failed_to_disable\">Failed to disable module: %s</string>\n    <string name=\"apm_empty\">No module installed</string>\n    <string name=\"apm_remove\">Remove</string>\n    <string name=\"apm_install\">Install</string>\n    <string name=\"apm_uninstall_confirm\">Uninstall the %s module?</string>\n    <string name=\"metamodule_uninstall_confirm\">\"Are you sure you want to uninstall module %s? This action will affect all modules, and certain features provided by the metamodule (such as mounting) will no longer work.  \"</string>\n    <string name=\"apm_uninstall_success\">%s uninstalled</string>\n    <string name=\"apm_uninstall_failed\">Failed to uninstall: %s</string>\n    <string name=\"apm_version\">Version</string>\n    <string name=\"apm_author\">Author</string>\n    <string name=\"apm_desc\">Desc</string>\n    <string name=\"apm_overlay_fs_not_available\">Modules are unavailable as OverlayFS is disabled by the kernel!</string>\n    <string name=\"apm_magisk_conflict\">Modules are unavailable due to a conflict with Magisk!</string>\n    <string name=\"apm_reboot_to_apply\">Reboot to take effect</string>\n    <string name=\"apm_changelog\">Changelog</string>\n    <string name=\"apm_update\">Update</string>\n    <string name=\"apm_downloading\">Downloading module: %s</string>\n    <string name=\"apm_start_downloading\">Start downloading: %s</string>\n    <string name=\"apm_new_version_available\">New version %s is available, click to upgrade.</string>\n\n    <string name=\"warning_of_meta_module_title\">Require Meta module</string>\n    <string name=\"warning_of_meta_module_summary\">This module want to mount /system, meta module will handle that. Otherwise, it might not work.</string>\n    <string name=\"meta_module_disabled\">module not mounted, because metamodule disabled</string>\n    <string name=\"meta_module_removed\">module not mounted, because metamodule being delete</string>\n    <string name=\"no_meta_module_installed\">module not mounted, because metamodule not installed</string>\n\n    <string name=\"hide_apatch_manager\">Hide APatch Manager</string>\n    <string name=\"hide_apatch_manager_summary\">Install a proxy app with a random package ID and custom app label</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">New manager name</string>\n    <string name=\"hide_apatch_dialog_summary\">It will be used as the new app label shown in launcher</string>\n    <string name=\"hide_apatch_manager_failure\">Failed to hide. Please report the bug!</string>\n\n    <string name=\"setting_reset_su_path\">Reset su path</string>\n    <string name=\"setting_reset_su_new_path\">New full path</string>\n\n    <string name=\"apm_webui_open\">Open</string>\n    <string name=\"apm_action\">Action</string>\n    <string name=\"enable_web_debugging\">Enable WebView debugging</string>\n    <string name=\"enable_web_debugging_summary\">Can be used to debug WebUI. Please enable only when needed.</string>\n\n    <string name=\"settings_donot_store_superkey\">Don\\'t store SuperKey in local</string>\n    <string name=\"settings_donot_store_superkey_summary\">Authenticate the SuperKey every time the manager starts</string>\n\n    <string name=\"home_new_apatch_found\">New version %s is available, click to upgrade.</string>\n\n    <string name=\"mode_select_page_title\">Install</string>\n    <string name=\"mode_select_page_patch_and_install\">Patch and install</string>\n    <string name=\"mode_select_page_select_file\">Select a boot image to patch</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Install to inactive slot (After OTA)</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Your device will be **FORCED** to boot to the current inactive slot after a reboot!\\nOnly use this option after OTA is done.\\nContinue?</string>\n\n    <string name=\"home_dialog_auth_fail_title\">Authentication failed</string>\n    <string name=\"home_dialog_auth_fail_content\">Unable to authenticate the SuperKey, therefore APatch cannot work properly.\\nHere are some possible reasons for authentication failure:\\n1. You didn\\'t patch the boot.img with KernelPatch.\\n2. The patched boot.img wasn\\'t flashed.\\n3. The SuperKey is wrong or contains special characters.\\n4. Your device doesn\\'t support APatch and KernelPatch.\\n\\nPlease check and try again. If there are still issues, you can always ask questions on the official repository\\'s issues page.</string>\n\n    <string name=\"home_more_menu_feedback_or_suggestion\">Feedback or suggestion</string>\n    <string name=\"home_more_menu_about\">About</string>\n\n    <string name=\"home_dialog_uninstall_title\">Uninstall</string>\n\n    <string name=\"home_dialog_uninstall_ap_only\">Remove AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Uninstall all</string>\n\n    <string name=\"kpm_control_dialog_title\">Control KPModule</string>\n    <string name=\"kpm_control_dialog_content\">Input control parameters:</string>\n    <string name=\"kpm_control_paramters\">Parameters</string>\n    <string name=\"kpm_control_outMsg\">Message</string>\n    <string name=\"kpm_control_ok\">Operation succeeded!</string>\n    <string name=\"kpm_control_failed\">Operation failed!</string>\n\n    <string name=\"settings_night_mode_follow_sys\">Follow system\\'s dark theme</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Automatically switch to dark theme based on system settings</string>\n\n    <string name=\"settings_night_theme_enabled\">Enable dark theme</string>\n\n    <string name=\"settings_use_system_color_theme\">System color theme</string>\n    <string name=\"settings_use_system_color_theme_summary\">Use a color theme generated by the system based on the current wallpaper</string>\n\n    <string name=\"settings_custom_color_theme\">Color theme</string>\n    <string name=\"amber_theme\">Amber</string>\n    <string name=\"blue_grey_theme\">Blue grey</string>\n    <string name=\"blue_theme\">Blue</string>\n    <string name=\"brown_theme\">Brown</string>\n    <string name=\"cyan_theme\">Cyan</string>\n    <string name=\"deep_orange_theme\">Deep orange</string>\n    <string name=\"deep_purple_theme\">Deep purple</string>\n    <string name=\"green_theme\">Green</string>\n    <string name=\"indigo_theme\">Indigo</string>\n    <string name=\"light_blue_theme\">Light blue</string>\n    <string name=\"light_green_theme\">Light green</string>\n    <string name=\"lime_theme\">Lime</string>\n    <string name=\"orange_theme\">Orange</string>\n    <string name=\"pink_theme\">Pink</string>\n    <string name=\"purple_theme\">Purple</string>\n    <string name=\"red_theme\">Red</string>\n    <string name=\"sakura_theme\">Sakura</string>\n    <string name=\"teal_theme\">Teal</string>\n    <string name=\"yellow_theme\">Yellow</string>\n    <string name=\"about_app_version\">Version %1$s</string>\n    <string name=\"about_app_desc\">Kernel root solution with only a stripped kernel image, providing the ability of mounting system module and hooking kernel function.</string>\n    <string name=\"about_github\" translatable=\"false\">GitHub</string>\n    <string name=\"about_weblate\" translatable=\"false\">Weblate</string>\n    <string name=\"about_telegram_channel\">Telegram channel</string>\n    <string name=\"about_telegram_group\">Telegram group</string>\n    <string name=\"about_powered_by\">Powered by %1$s</string>\n    <string name=\"crash_handle_title\">App crashed…</string>\n    <string name=\"crash_handle_copy\">Copy crash log</string>\n    <string name=\"crash_handle_copied\">Crash log copied to clipboard.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <style name=\"Theme.APatch\" parent=\"Theme.AppCompat.DayNight.NoActionBar\">\n        <item name=\"android:windowLayoutInDisplayCutoutMode\" tools:targetApi=\"o_mr1\">shortEdges</item>\n    </style>\n\n    <style name=\"Theme.Splash\" parent=\"Theme.SplashScreen\">\n        <item name=\"windowSplashScreenAnimatedIcon\">@mipmap/ic_launcher</item>\n        <item name=\"postSplashScreenTheme\">@style/Theme.APatch</item>\n    </style>\n\n    <style name=\"Theme.APatch.WebUI\" parent=\"Theme.APatch\">\n        <item name=\"android:windowLightStatusBar\">true</item>\n        <item name=\"android:windowLightNavigationBar\" tools:targetApi=\"o_mr1\">true</item>\n    </style>\n\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ab/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"su_pkg_excluded_setting_summary\">\\t</string>\n    <string name=\"about_app_version\">%1$s</string>\n    <string name=\"about_app_desc\">…\\t\\t…“”” </string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-apc/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">صفحة الرئيسية</string>\n    <string name=\"patch_warnning\">التثبيت يأتي أحيانا بمخاطر. يرجى التأكد من عمل نسخ احتياطي لبياناتك.</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">Android Patch</string>\n    <string name=\"reboot\">إعادة التشغيل</string>\n    <string name=\"settings\">الإعدادات</string>\n    <string name=\"reboot_recovery\">إعادة تشغيل إلي وضع الاسترداد</string>\n    <string name=\"reboot_bootloader\">إعادة تشغيل إلى محمل الإقلاع</string>\n    <string name=\"reboot_download\">إعادة تشغيل إلى وضع التنزيل</string>\n    <string name=\"reboot_edl\">إعادة تشغيل إلى EDL</string>\n    <string name=\"about\">حول التطبيق</string>\n    <string name=\"home_learn_apatch\">تعلم APatch</string>\n    <string name=\"home_click_to_learn_apatch\">تعرف على ميزات AndroidPatch وكيفية استخدامه</string>\n    <string name=\"about_source_code\"><![CDATA[<p> عرض كود المصدر على %1$s<p/> انضم إلى قناتنا %2$s انضم إلى مجموعتنا %3$s]]></string>\n    <string name=\"send_log\">أرسل السجلات</string>\n    <string name=\"safe_mode\">الوضع الآمن</string>\n    <string name=\"super_key\">المفتاح الخارق</string>\n    <string name=\"clear_super_key\">محو المفتاح الخارق</string>\n    <string name=\"patch_set_superkey\">ضع المفتاح الخارق</string>\n    <string name=\"home_patch_set_key_desc\">اعتماد فقط لـKernelPatch</string>\n    <string name=\"home_click_to_install\">اضغط للتثبيت</string>\n    <string name=\"home_working\">يعمل</string>\n    <string name=\"home_installing\">يتم التثبيت</string>\n    <string name=\"home_patch_next_step\">الخطوة التالية</string>\n    <string name=\"kpatch_version\">الإصدار: %s</string>\n    <string name=\"home_not_installed\">لم يتم التثبيت</string>\n    <string name=\"home_install_unknown\">غير مثبت أو مصادق عليه</string>\n    <string name=\"home_need_update\">اصدار جديد متوفر</string>\n    <string name=\"apatch_version\">الإصدار: %s</string>\n    <string name=\"apatch_version_update\">الإصدار: %s -&gt; %s</string>\n    <string name=\"home_auth_key_desc\">البدء بعد التوثيق</string>\n    <string name=\"home_su_path\">مستخدم خارق قابل للتنفيذ</string>\n    <string name=\"home_apatch_version\">إصدار APatch</string>\n    <string name=\"home_auth_key_title\">ادخل المفتاح الخارق</string>\n    <string name=\"home_ap_cando_install\">تثبيت</string>\n    <string name=\"home_ap_cando_update\">تحديث</string>\n    <string name=\"home_ap_cando_uninstall\">إلغاء التثبيت</string>\n    <string name=\"home_kernel\">النواة</string>\n    <string name=\"patch_title\">باتش</string>\n    <string name=\"home_manager_version\">إصدار البرنامج</string>\n    <string name=\"kpm_unload\">إلغاء التحميل</string>\n    <string name=\"kpm_apm_empty\">لم يتم تحميل أي إضافة</string>\n    <string name=\"home_selinux_status_unknown\">غير معروف</string>\n    <string name=\"su_title\">المستخدم الخارق</string>\n    <string name=\"su_pkg_excluded_label\">استثني</string>\n    <string name=\"kpm_load\">تحميل</string>\n    <string name=\"su_selinux_via_hook\">التجاوز عن طريق الخطاف</string>\n    <string name=\"kpm\">إضافة KP</string>\n    <string name=\"home_fingerprint\">البصمة</string>\n    <string name=\"home_selinux_status\">حالة SELinux</string>\n    <string name=\"home_selinux_status_disabled\">ملغى</string>\n    <string name=\"home_selinux_status_enforcing\">إجبار</string>\n    <string name=\"home_selinux_status_permissive\">تساهل</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch غير مثبت</string>\n    <string name=\"kpm_load_toast_succ\">تم التحميل بنجاح</string>\n    <string name=\"kpm_load_toast_failed\">فشل التحميل</string>\n    <string name=\"kpm_unload_confirm\">إلغاء تحميل \\\"%s\\\" الإضافة?</string>\n    <string name=\"kpm_version\">الاصدار</string>\n    <string name=\"kpm_license\">الترخيص</string>\n    <string name=\"kpm_author\">المؤلِّف</string>\n    <string name=\"kpm_desc\">Desc</string>\n    <string name=\"kpm_args\">الحجج</string>\n    <string name=\"su_pkg_excluded_setting_title\">استثناء التعديلات</string>\n    <string name=\"su_pkg_excluded_setting_summary\">هذا الخيار سيسمح لـAPache باستعادة أي ملف معدل بواسطة هذا التطبيق.</string>\n    <string name=\"su_show_system_apps\">إظهار تطبيقات النظام</string>\n    <string name=\"su_hide_system_apps\">إخفاء تطبيقات النظام</string>\n    <string name=\"su_refresh\">انعاش</string>\n    <string name=\"apm_not_installed\">AndroidPatch غير مثبت</string>\n    <string name=\"apm_install\">تثبيت</string>\n    <string name=\"apm_uninstall_confirm\">الغاء تثبيت إضافة \\\"%s\\\"؟</string>\n    <string name=\"apm_uninstall_success\">تم الغاء التثبيت %s</string>\n    <string name=\"apm_uninstall_failed\">لا يمكن الغاء تثبيت %s</string>\n    <string name=\"apm_overlay_fs_not_available\">الإضافات غير متاحة نظرًا لتعطيل نظام OverlayFS بواسطة النواة.</string>\n    <string name=\"apm_magisk_conflict\">الإضافات غير متاحة بسبب التعارض مع ماجيسك.</string>\n    <string name=\"apm_reboot_to_apply\">أعد التشغيل ليصبح ساري المفعول</string>\n    <string name=\"system_default\">النظام الافتراضي</string>\n    <string name=\"settings_app_language\">الغة</string>\n    <string name=\"apm\">إضافة AP</string>\n    <string name=\"apm_failed_to_enable\">غير قادر على تشغيل الإضافة \\\"%s\\\"</string>\n    <string name=\"apm_author\">المؤلف</string>\n    <string name=\"apm_changelog\">سجل التغييرات</string>\n    <string name=\"apm_update\">تحديث</string>\n    <string name=\"apm_remove\">إزالة</string>\n    <string name=\"apm_version\">الاصدار</string>\n    <string name=\"apm_start_downloading\">بدء التنزيل %s</string>\n    <string name=\"apm_new_version_available\">اضغط لتثبيت الإصدار الجديد %s.</string>\n    <string name=\"apm_failed_to_disable\">لم يمكن إيقاف إضافة \\\"%s</string>\n    <string name=\"apm_empty\">لم يتم تثبيت أي إضافة</string>\n    <string name=\"apm_desc\">Desc</string>\n    <string name=\"apm_downloading\">تنزيل إضافة %s…</string>\n    <string name=\"patch\">باتش</string>\n    <string name=\"settings_global_namespace_mode_summary\">جميع مساحات الروت تستخدم مساحة الاسم العامة للتثبيت</string>\n    <string name=\"settings_global_namespace_mode\">وضع APatchمساحة الاسم العام</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_extra_name\">الاسم:</string>\n    <string name=\"patch_item_set_skey_label\">يجب أن يكون طول المفتاح الخارق ٧~٦٣ علامة ويتضمن كلاً من الأرقام والحروف بلا علامات مميزة</string>\n    <string name=\"settings_clear_super_key_dialog\">هل تريد حقًا المتابعة؟</string>\n    <string name=\"kpatch_version_update\">الإصدار: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">معلومات</string>\n    <string name=\"home_ap_cando_reboot\">إعادة تشغيل</string>\n    <string name=\"patch_config_title\">باتشات</string>\n    <string name=\"patch_mode_bootimg_patch\">الوضع: باتش</string>\n    <string name=\"patch_mode_uninstall_patch\">الوضع: إلغاء تثبيت KPatch</string>\n    <string name=\"patch_select_bootimg_btn\">حدد صورة التمهيد</string>\n    <string name=\"patch_embed_kpm_btn\">تضمين KPM</string>\n    <string name=\"patch_start_patch_btn\">البدء</string>\n    <string name=\"patch_start_unpatch_btn\">ألغاء الباتش</string>\n    <string name=\"patch_item_error\">!!خطأ!!</string>\n    <string name=\"patch_item_bootimg\">صورة الإقلاع</string>\n    <string name=\"patch_item_bootimg_slot\">الفتحة:</string>\n    <string name=\"patch_item_bootimg_dev\">الجهاز:</string>\n    <string name=\"patch_item_kernel\">النواة</string>\n    <string name=\"patch_item_kpimg_version\">الإصدار:</string>\n    <string name=\"patch_item_kpimg_comile_time\">الوقت:</string>\n    <string name=\"patch_item_kpimg_config\">التكوين:</string>\n    <string name=\"patch_item_new_extra_kpm\">تضمين جديد</string>\n    <string name=\"patch_item_existed_extra_kpm\">موجود</string>\n    <string name=\"patch_item_extra_version\">الإصدار:</string>\n    <string name=\"patch_item_extra_author\">المؤلف:</string>\n    <string name=\"patch_item_extra_kpm_license\">الترخيص:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">الوصف:</string>\n    <string name=\"patch_item_extra_args\">الحجج:</string>\n    <string name=\"patch_item_extra_event\">الحدث:</string>\n    <string name=\"patch_item_skey\">المفتاح الخارق</string>\n    <string name=\"hide_apatch_manager\">إخفاء مدير APatch</string>\n    <string name=\"kpm_embed\">تضمين</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">اسم المدير الجديد</string>\n    <string name=\"kpm_add_kpm\">إضافة KPM</string>\n    <string name=\"kpm_install\">تثبيت</string>\n    <string name=\"hide_apatch_manager_summary\">قم بتثبيت تطبيق مدير جديد بمعرف عشوائي وتصنيف مخصص</string>\n    <string name=\"hide_apatch_dialog_summary\">سيتم استخدامه كتسمية التطبيق الجديدة الموضحة في المشغل</string>\n    <string name=\"hide_apatch_manager_failure\">فشل الإخفاء، يرجى الإبلاغ عن الخطأ!</string>\n    <string name=\"setting_reset_su_new_path\">مسار كامل جديد</string>\n    <string name=\"setting_reset_su_path\">إعادة تعيين مسار su</string>\n    <string name=\"success\">ناجحة</string>\n    <string name=\"failure\">فشل</string>\n    <string name=\"mode_select_page_title\">تثبيت</string>\n    <string name=\"settings_check_update\">تحقق للحصول على التحديثات</string>\n    <string name=\"settings_check_update_summary\">التحقق تلقائيًا من وجود تحديثات عند فتح التطبيق</string>\n    <string name=\"home_install_unknown_summary\">اضغط للتثبيت</string>\n    <string name=\"home_device_info\">الجهاز</string>\n    <string name=\"home_system_version\">إصدار النظام</string>\n    <string name=\"home_kpatch_version\">إصدار KernelPatch</string>\n    <string name=\"settings_donot_store_superkey\">لا تقم بتخزين المفتاح الخارق محلياً</string>\n    <string name=\"settings_donot_store_superkey_summary\">قم بتوثيق المفتاح الخارق في كل مرة يتم تفعيل التطبيق</string>\n    <string name=\"home_new_apatch_found\">إصدار جديد متوفر: %s، اضغط هنا للتحديث</string>\n    <string name=\"mode_select_page_patch_and_install\">تعديل و تثبيت</string>\n    <string name=\"mode_select_page_select_file\">اختر صورة تهميد لـAPatch</string>\n    <string name=\"home_dialog_auth_fail_title\">فشلت المصادقة</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">التعليقات أو الاقتراحات</string>\n    <string name=\"home_more_menu_about\">حول</string>\n    <string name=\"home_dialog_uninstall_title\">إلغاء تثبيت</string>\n    <string name=\"home_dialog_uninstall_ap_only\">إزالة AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">إلغاء تثبيت الكل</string>\n    <string name=\"mode_select_page_install_inactive_slot\">تثبيت على الفتحة غير النشطة (بعد التحديث عبر الهواء OTA)</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">**سيتم إجبار جهازك** على التمهيد إلى الفتحة غير النشطة الحالية بعد إعادة التشغيل!\n\\nاستخدم هذا الخيار فقط بعد انتهاء التحديث الهوائي.\n\\nهل تريد المتابعة؟</string>\n    <string name=\"home_dialog_auth_fail_content\">غير قادر على مصادقة المفتاح الخارق، وبالتالي لا يمكن لـ APatch العمل بشكل صحيح. \\nفيما يلي بعض الأسباب المحتملة لفشل المصادقة: \\n1. لم تقم بتصحيح صورة التمهيد باستخدام KernelPatch. \\n2. لم يتم تثبيت صورة التمهيد المصححة. \\n3. مفتاح خارق خطأ. \\n4. جهازك لا يدعم APatch وKernelPatch. \\n \\nيرجى التحقق والمحاولة مرة أخرى. إذا كانت لا تزال هناك مشكلات، فيمكنك دائمًا طرح الأسئلة على صفحة المشكلات الخاصة بالمستودع الرسمي.</string>\n    <string name=\"patch_mode_patch_and_install\">الوضع: باتش وتثبيت</string>\n    <string name=\"patch_mode_install_to_next_slot\">الوضع: تثبيت في الفتحة التالية (بعد OTA)</string>\n    <string name=\"apm_webui_open\">فتح</string>\n    <string name=\"enable_web_debugging\">تمكين تصحيح أخطاء عارض الويب</string>\n    <string name=\"enable_web_debugging_summary\">يمكن استخدامه لتصحيح أخطاء واجهة الويب، يرجى تمكينه فقط عند الحاجة.</string>\n    <string name=\"kpm_control\">تحكم</string>\n    <string name=\"kpm_control_dialog_content\">أدخل معلمات التحكم:</string>\n    <string name=\"brown_theme\">مظهر بني</string>\n    <string name=\"cyan_theme\">‌‌‍مظهر سماوي</string>\n    <string name=\"indigo_theme\">مظهر نيلي</string>\n    <string name=\"lime_theme\">مظهر ليموني</string>\n    <string name=\"pink_theme\">مظهر وردي</string>\n    <string name=\"sakura_theme\">مظهر وردي</string>\n    <string name=\"teal_theme\">مظهر تركوازي</string>\n    <string name=\"yellow_theme\">مظهر أصفر</string>\n    <string name=\"about_telegram_channel\">قناة تيليجرام</string>\n    <string name=\"about_app_desc\">حل روت Kernel مع صورة kernel مجردة فقط، مما يوفر إمكانية تركيب وحدة النظام وربط وظيفة Kernel.</string>\n    <string name=\"about_telegram_group\">مجموعة تيليجرام</string>\n    <string name=\"about_powered_by\">مدعوم بواسطة %1$s</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">التبديل إلى السمة الداكنة تلقائيًا بناءً على إعدادات النظام</string>\n    <string name=\"kpm_control_dialog_title\">التحكم بـKPModule</string>\n    <string name=\"kpm_control_outMsg\">رسالة</string>\n    <string name=\"kpm_control_ok\">نجحت العملية!</string>\n    <string name=\"settings_use_system_color_theme\">مظهر لون النظام</string>\n    <string name=\"amber_theme\">مظهر Amber</string>\n    <string name=\"light_blue_theme\">مظهر أزرق فاتح</string>\n    <string name=\"kpm_control_paramters\">معلمات</string>\n    <string name=\"kpm_control_failed\">فشلت العملية!</string>\n    <string name=\"settings_night_mode_follow_sys\">اتبع المظهر الداكن للنظام</string>\n    <string name=\"settings_night_theme_enabled\">تمكين المظهر الداكن</string>\n    <string name=\"settings_use_system_color_theme_summary\">استخدام لون الموضوع الذي يولده النظام استنادا إلى ورق الحائط الحالي</string>\n    <string name=\"settings_custom_color_theme\">لون الحلة</string>\n    <string name=\"blue_grey_theme\">مظهر BlueGrey</string>\n    <string name=\"blue_theme\">أزرق</string>\n    <string name=\"deep_orange_theme\">مظهر برتقالي غامق</string>\n    <string name=\"deep_purple_theme\">مظهر بنفسجي غامق</string>\n    <string name=\"green_theme\">مظهر أخضر</string>\n    <string name=\"light_green_theme\">مظهر أخضر فاتح</string>\n    <string name=\"orange_theme\">مظهر برتقالي</string>\n    <string name=\"purple_theme\">مظهر بنفسجي</string>\n    <string name=\"red_theme\">مظهر أحمر</string>\n    <string name=\"about_app_version\">إصدار %1$s</string>\n    <string name=\"save_log\">‮‬حفظ السجلات</string>\n    <string name=\"apm_action\">الإجراء</string>\n    <string name=\"log_saved\">تم حفظ السجل</string>\n    <string name=\"crash_handle_title\">لقد تحطمت.</string>\n    <string name=\"crash_handle_copy\">نسخ سجل الأعطال</string>\n    <string name=\"crash_handle_copied\">تم نسخ سجل الأعطال إلى الحافظة.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-arq/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "app/src/main/res/values-az/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">Ana səhifə</string>\n    <string name=\"patch_warnning\">Quraşdırma risklərlə gəlir. Zəhmət olmasa, məlumatlarınızın yedəkləndiyindən əmin olun.</string>\n    <string name=\"patch\">Yamaq</string>\n    <string name=\"reboot\">Yenidən başlat</string>\n    <string name=\"reboot_recovery\">Bərpa rejiminə yenidən başlat</string>\n    <string name=\"reboot_bootloader\">Önyükləyici rejiminə yenidən başlat</string>\n    <string name=\"reboot_download\">Yükləmə rejiminə yenidən başlat</string>\n    <string name=\"about\">Haqqında</string>\n    <string name=\"settings_app_language\">Dil</string>\n    <string name=\"home_learn_apatch\">APatch haqqında öyrənin</string>\n    <string name=\"about_source_code\">Mənbə koduna %1$s ünvanında baxın<br/>%2$s kanalımıza qoşulun.qrupumuza qoşulun.</string>\n    <string name=\"system_default\">Sistem defoltu</string>\n    <string name=\"send_log\">Günlükü göndərin</string>\n    <string name=\"safe_mode\">Təhlükəsiz rejim</string>\n    <string name=\"clear_super_key\">Açarı silin</string>\n    <string name=\"super_key\">SuperAçar</string>\n    <string name=\"patch_set_superkey\">SuperAçar təyin edin</string>\n    <string name=\"home_patch_set_key_desc\">Yalnız NüvəYamağı üçün etimadnamə</string>\n    <string name=\"home_patch_next_step\">Sonrakı addım</string>\n    <string name=\"home_not_installed\">Quraşdırılmayıb</string>\n    <string name=\"home_install_unknown\">Naməlum</string>\n    <string name=\"home_working\">İşləyir</string>\n    <string name=\"home_installing\">Quraşdırılır</string>\n    <string name=\"home_need_update\">Yeni versiya mövcuddur</string>\n    <string name=\"apatch_version\">Versiya:\n\\n%s</string>\n    <string name=\"apatch_version_update\">Versiya:\n\\n%s -&gt; %s</string>\n    <string name=\"home_su_path\">su: %s</string>\n    <string name=\"kpatch_version\">Versiya: %s</string>\n    <string name=\"kernel_patch\">NüvəYamağı</string>\n    <string name=\"android_patch\">AndroidYamağı</string>\n    <string name=\"home_apatch_version\">APatch: %s</string>\n    <string name=\"home_auth_key_title\">SuperAçarı daxil edin</string>\n    <string name=\"home_auth_key_desc\">Sertifikasiyadan sonra başlayın</string>\n    <string name=\"home_ap_cando_install\">Quraşdır</string>\n    <string name=\"home_ap_cando_uninstall\">Sil</string>\n    <string name=\"patch_title\">Yamaq</string>\n    <string name=\"home_kernel\">Nüvə</string>\n    <string name=\"home_fingerprint\">Barmaq izi</string>\n    <string name=\"home_selinux_status\">SELinux vəziyyəti</string>\n    <string name=\"home_selinux_status_disabled\">Sönülü</string>\n    <string name=\"home_selinux_status_enforcing\">Məcburi</string>\n    <string name=\"home_selinux_status_permissive\">Sərbəst</string>\n    <string name=\"home_selinux_status_unknown\">Naməlum</string>\n    <string name=\"kpm\">NYModulu</string>\n    <string name=\"kpm_load\">Yüklə</string>\n    <string name=\"kpm_load_toast_succ\">Yükləmə uğurlu oldu</string>\n    <string name=\"kpm_load_toast_failed\">Yükləmə uğursuz oldu</string>\n    <string name=\"kpm_unload_confirm\">\\\"%s\\\" modulunun yüklənməsini ləğv etmək istəyirsiniz mi?</string>\n    <string name=\"kpm_unload\">Ləğv et</string>\n    <string name=\"kpm_apm_empty\">Heç bir modul yüklənməyib</string>\n    <string name=\"kpm_license\">Lisans</string>\n    <string name=\"kpm_author\">Sahib</string>\n    <string name=\"kpm_desc\">Açıqlama</string>\n    <string name=\"kpm_args\">Arqumentlər</string>\n    <string name=\"su_title\">Superistifadəçi</string>\n    <string name=\"su_selinux_via_hook\">Çəngəl ilə yan keçin</string>\n    <string name=\"su_pkg_excluded_label\">istisna</string>\n    <string name=\"su_pkg_excluded_setting_title\">Dəyişiklikləri istisna edin</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Bu seçimin aktivləşdirilməsi APatch-ə bu proqram üçün modullar tərəfindən hər hansı dəyişdirilmiş faylları bərpa etməyə imkan verəcək.</string>\n    <string name=\"su_show_system_apps\">Sistem proqramlarını göstərin</string>\n    <string name=\"su_hide_system_apps\">Sistem proqramlarını gizlədin</string>\n    <string name=\"su_refresh\">Yeniləyin</string>\n    <string name=\"apm\">AYModulu</string>\n    <string name=\"apm_failed_to_enable\">\\\"%s\\\" modulunu yandırmaq mümkün olmadı</string>\n    <string name=\"apm_failed_to_disable\">\\\"%s\\\" modulunu söndürmək mümkün olmadı</string>\n    <string name=\"apm_empty\">Heç bir modul quraşdırılmayıb</string>\n    <string name=\"apm_remove\">Sil</string>\n    <string name=\"apm_uninstall_confirm\">\\\"%s\\\" modulunu silmək istəyirsiniz mi?</string>\n    <string name=\"apm_uninstall_success\">%s silindi</string>\n    <string name=\"apm_uninstall_failed\">%s modulunu silmək mümkün olmadı</string>\n    <string name=\"apm_version\">Versiya</string>\n    <string name=\"apm_author\">Sahib</string>\n    <string name=\"apm_desc\">Açıqlama</string>\n    <string name=\"apm_magisk_conflict\">Magisk ilə ziddiyyətə görə modullar əlçatan deyil!</string>\n    <string name=\"home_ap_cando_update\">Güncəllə</string>\n    <string name=\"apm_reboot_to_apply\">Effektiv olmağı üçün yenidən başladın</string>\n    <string name=\"apm_changelog\">Dəyişikliklər jurnalı</string>\n    <string name=\"apm_update\">Güncəllə</string>\n    <string name=\"apm_downloading\">\\\"%s\\\" modulu endirilir…</string>\n    <string name=\"apm_start_downloading\">%s endirilməsi başladıldı</string>\n    <string name=\"apm_new_version_available\">Yeni versiyanı quraşdırmaq üçün klikləyin, %s.</string>\n    <string name=\"reboot_edl\">Təcili yükləmə rejiminə yenidən başlat</string>\n    <string name=\"home_click_to_install\">Quraşdırmaq üçün toxunun</string>\n    <string name=\"settings\">Ayarlar</string>\n    <string name=\"home_click_to_learn_apatch\">APatch-in xüsusiyyətləri və necə istifadə olunacağını öyrənin</string>\n    <string name=\"home_manager_version\">Menecer versiyası</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch quraşdırılmayıb</string>\n    <string name=\"kpm_version\">Versiya</string>\n    <string name=\"apm_install\">Quraşdır</string>\n    <string name=\"apm_not_installed\">AndroidYamağı quraşdırılmayıb</string>\n    <string name=\"apm_overlay_fs_not_available\">OverlayFS nüvə tərəfindən deaktiv edildiyi üçün modullar əlçatan deyil.</string>\n    <string name=\"settings_global_namespace_mode\">Global namespace mode</string>\n    <string name=\"settings_global_namespace_mode_summary\">Bütün kök sessiyaları qlobal bağlama adməkanından istifadə edir</string>\n    <string name=\"settings_clear_super_key_dialog\">Həqiqətən davam etmək istəyirsən?</string>\n    <string name=\"settings_check_update\">Yeniləməni yoxlayın</string>\n    <string name=\"settings_check_update_summary\">Proqramı açarkən avtomatik olaraq yeniləmələri yoxlayın</string>\n    <string name=\"home_install_unknown_summary\">Quraşdırmaq üçün kliklə</string>\n    <string name=\"kpatch_version_update\">Versiya: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">Məlumat</string>\n    <string name=\"patch_config_title\">Yamalar</string>\n    <string name=\"patch_mode_bootimg_patch\">Mod: Yamala</string>\n    <string name=\"patch_mode_patch_and_install\">Mode: Yamala və quraşdır</string>\n    <string name=\"patch_embed_kpm_btn\">KPM-i göm</string>\n    <string name=\"patch_start_patch_btn\">Başla</string>\n    <string name=\"patch_start_unpatch_btn\">\"Yamanı Deaktiv edin \"</string>\n    <string name=\"patch_item_bootimg_slot\">yuva:</string>\n    <string name=\"patch_item_bootimg_dev\">cihaz:</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">versiya:</string>\n    <string name=\"patch_item_kpimg_comile_time\">zaman:</string>\n    <string name=\"patch_item_kpimg_config\">konfiqurasiya:</string>\n    <string name=\"patch_item_new_extra_kpm\">Yenisini göm</string>\n    <string name=\"patch_item_extra_event\">Hadisə:</string>\n    <string name=\"patch_item_skey\">Super Açar</string>\n    <string name=\"kpm_control\">Kontrol</string>\n    <string name=\"save_log\">Qeydləri yaddaşda saxla</string>\n    <string name=\"home_ap_cando_reboot\">Yenidən başlat</string>\n    <string name=\"patch_mode_uninstall_patch\">Mod: KPatch-i silin</string>\n    <string name=\"patch_select_bootimg_btn\">Boot-u seç</string>\n    <string name=\"patch_item_error\">!!XƏTA!!</string>\n    <string name=\"patch_item_bootimg\">Önyüklənəbilir görüntü</string>\n    <string name=\"patch_item_existed_extra_kpm\">Mövcud</string>\n    <string name=\"patch_item_extra_name\">ad:</string>\n    <string name=\"patch_item_extra_version\">versiya:</string>\n    <string name=\"patch_item_extra_author\">müəllif:</string>\n    <string name=\"patch_item_extra_kpm_license\">lisans:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">açıqlama:</string>\n    <string name=\"patch_item_extra_args\">arqumentlər:</string>\n    <string name=\"patch_item_set_skey_label\">Super açarın uzunluğu ən azı 8 vəya 63 uzunluğunda simvol olmalıdır və həm rəqəmlər, həm də hərflərdən ibarət olmalıdır özəl simvollar istifadə edilməməlidir</string>\n    <string name=\"home_device_info\">Cihaz</string>\n    <string name=\"home_system_version\">Sistem versiyası</string>\n    <string name=\"home_kpatch_version\">KernelYama versiyası</string>\n    <string name=\"kpm_add_kpm\">KPM əlavə et</string>\n    <string name=\"kpm_install\">Quraşdır</string>\n    <string name=\"kpm_embed\">Göm</string>\n    <string name=\"success\">Uğurlu</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mod: Növbəti yuvaya quraşdırın (OTA-dan sonra)</string>\n    <string name=\"failure\">Uğursuz oldu</string>\n    <string name=\"hide_apatch_manager_summary\">Təsadüfi paket ID-si və fərdi tətbiq etiketi ilə yeni menecer tətbiqini quraşdırın</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Yeni Menecer Adı</string>\n    <string name=\"hide_apatch_manager_failure\">Gizlətmək alınmadı, lütfən, proqram açığını bildirin!</string>\n    <string name=\"enable_web_debugging_summary\">WebUI-ni sazlamaq üçün istifadə edilə bilər, zəhmət olmasa, yalnız lazım olduqda aktivləşdirin.</string>\n    <string name=\"setting_reset_su_new_path\">yeni tam yol</string>\n    <string name=\"enable_web_debugging\">Webgörüntələmə Xəta Çeşidləməyi aktivləşdirin</string>\n    <string name=\"settings_donot_store_superkey\">Super açarı local cihazda saxlamayın</string>\n    <string name=\"home_new_apatch_found\">Yeni versiya mövcuddur: %s, Güncəlləmək üçün mənə klikləyin</string>\n    <string name=\"settings_donot_store_superkey_summary\">Menecer hər dəfə açılanda super açarı təsdiq edin</string>\n    <string name=\"mode_select_page_title\">Quraşdır</string>\n    <string name=\"mode_select_page_select_file\">Yamaq üçün boot image-i seçin</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Qeyri-aktiv Yuvaya quraşdırın (OTA-dan sonra)</string>\n    <string name=\"mode_select_page_patch_and_install\">Yamala və quraşdır</string>\n    <string name=\"home_dialog_auth_fail_title\">Doğrulama uğursuz oldu</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Cihazınız yenidən işə salındıqdan sonra cari qeyri-aktiv yuvaya yükləməyə **MƏCBUR EDİLƏCƏK**!\n\\nBu seçimi yalnız OTA tamamlandıqdan sonra istifadə edin.\n\\nDavam edilsinmi?</string>\n    <string name=\"hide_apatch_dialog_summary\">Başlatıcıda göstərilən yeni tətbiq etiketi kimi istifadə olunacaq</string>\n    <string name=\"setting_reset_su_path\">Su yolunu sıfırla</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Geri bildirmə və ya təklif</string>\n    <string name=\"home_more_menu_about\">Haqqında</string>\n    <string name=\"home_dialog_uninstall_title\">Sil</string>\n    <string name=\"home_dialog_uninstall_ap_only\">AndroidYamasını silin</string>\n    <string name=\"home_dialog_uninstall_all\">Hamısını Silin</string>\n    <string name=\"kpm_control_dialog_title\">KPModulu kontrol et</string>\n    <string name=\"kpm_control_failed\">Əməliyyat uğursuz oldu!</string>\n    <string name=\"settings_night_mode_follow_sys\">Sistemin Qaranlıq Temasını izləyin</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Sistem ayarı ilə avtomatik olaraq qaranlıq temaya keçin</string>\n    <string name=\"settings_night_theme_enabled\">Qaranlıq Temanı aktiv et</string>\n    <string name=\"settings_use_system_color_theme\">Sistem Rəng Teması</string>\n    <string name=\"settings_use_system_color_theme_summary\">Cari divar kağızı ilə sistem tərəfindən yaradılan rəng temasını istifadə edin</string>\n    <string name=\"settings_custom_color_theme\">Rəng Teması</string>\n    <string name=\"amber_theme\">Amber Teması</string>\n    <string name=\"blue_grey_theme\">MaviBoz Teması</string>\n    <string name=\"blue_theme\">Mavi Teması</string>\n    <string name=\"brown_theme\">Qəhvəyi Tema</string>\n    <string name=\"cyan_theme\">Cyan Teması</string>\n    <string name=\"deep_orange_theme\">Tünd Narıncı Teması</string>\n    <string name=\"deep_purple_theme\">Tünd Bənövşəyi Teması</string>\n    <string name=\"green_theme\">Yaşıl Tema</string>\n    <string name=\"light_blue_theme\">Açıq Mavi Teması</string>\n    <string name=\"light_green_theme\">Açıq Yaşıl Teması</string>\n    <string name=\"lime_theme\">Lime Tema</string>\n    <string name=\"orange_theme\">Narıncı Teması</string>\n    <string name=\"purple_theme\">Bənövşəyi Tema</string>\n    <string name=\"red_theme\">Qırmızı Tema</string>\n    <string name=\"sakura_theme\">Sakura Teması</string>\n    <string name=\"teal_theme\">Teal Tema</string>\n    <string name=\"yellow_theme\">Sarı Tema</string>\n    <string name=\"about_app_version\">Versiya %1$s</string>\n    <string name=\"apm_webui_open\">Aç</string>\n    <string name=\"home_dialog_auth_fail_content\">Super açarın doğrulanması mümkün deyil, buna görə də APAtch düzgün işləyə bilməz. \\nDoğrulama uğursuzluğunun bəzi mümkün səbəbləri bunlardır: \\n1. Siz boot ­görüntüsü KernelPatch ilə yamalamamısınız. \\n2. Yamalı boot görüntüsü flashlanmadı. \\n3. Super açar səhvdir. \\n4. Cihazınız APatch və KernelPatch-i dəstəkləmir. \\n \\nZəhmət olmasa yoxlayın və yenidən cəhd edin. Hələ də problemlər varsa, siz həmişə rəsmi repozitoriyanın problem səhifəsində sual verə bilərsiniz.</string>\n    <string name=\"kpm_control_outMsg\">Mesajlar</string>\n    <string name=\"kpm_control_paramters\">Parametrlər</string>\n    <string name=\"kpm_control_dialog_content\">Giriş nəzarət parametrləri:</string>\n    <string name=\"kpm_control_ok\">Əməliyyat uğurla başa çatdı!</string>\n    <string name=\"indigo_theme\">Indigo Teması</string>\n    <string name=\"pink_theme\">Çəhrayı Tema</string>\n    <string name=\"about_telegram_channel\">Telegram Kanalı</string>\n    <string name=\"about_telegram_group\">Telegram Qrupu</string>\n    <string name=\"about_powered_by\">%1$s tərəfindən gücləndirildi</string>\n    <string name=\"hide_apatch_manager\">Gizli APatch Meneceri</string>\n    <string name=\"log_saved\">Qeydlər yaddaşda saxlandı</string>\n    <string name=\"apm_action\">Fəaliyyət</string>\n    <string name=\"about_app_desc\">Yalnızca sadələşdirilmiş kernel təsviri ilə kernel root həlli – sistem modullarını qoşmaq və kernel funksiyalarını ələ keçirmək imkanını təmin edir.</string>\n    <string name=\"crash_handle_title\">Program çöktü…</string>\n    <string name=\"crash_handle_copy\">Çöküntü qeydini kopyala</string>\n    <string name=\"crash_handle_copied\">Clipboarda çöküntü qeydi kopyalandı.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">হোম</string>\n    <string name=\"kernel_patch\">কার্নেলপ্যাচ</string>\n    <string name=\"android_patch\">অ্যান্ড্রয়েডপ্যাচ</string>\n    <string name=\"reboot\">রিবুট করুন</string>\n    <string name=\"reboot_bootloader\">বুটলোডারে যান</string>\n    <string name=\"reboot_download\">ডাউনলোড মোডে রিবুট করুন</string>\n    <string name=\"about\">বিস্তারিত</string>\n    <string name=\"about_source_code\"><![CDATA[<p>সোর্স কোড দেখুন%1$s<p/>আমাদের জয়েন করুন%2$s চ্যানেল<p/>আমাদের জয়েন করুন%3$s গ্রুপ]]></string>\n    <string name=\"safe_mode\">সেফ মোড</string>\n    <string name=\"super_key\">সুপারকি</string>\n    <string name=\"home_patch_set_key_desc\">কারনেলপ্যাচের এর জন্য শুধুমাত্র শংসাপত্র</string>\n    <string name=\"home_install_unknown\">ইনস্টল করা বা অনুমদিত করা নেই</string>\n    <string name=\"home_working\">কাজ করতেছে 🤭</string>\n    <string name=\"apatch_version\">সংস্করণ %s</string>\n    <string name=\"apatch_version_update\">সংস্করণ %s → %s</string>\n    <string name=\"home_su_path\">এক্সিকিউটেবল su</string>\n    <string name=\"home_apatch_version\">APatch সংস্করণ</string>\n    <string name=\"home_auth_key_title\">সুপারকি প্রবেশ করুন</string>\n    <string name=\"home_ap_cando_update\">হালনাগাদ</string>\n    <string name=\"home_ap_cando_uninstall\">আনইনস্টল করুন</string>\n    <string name=\"patch_warnning\">ইনস্টলেশন ঝুঁকিপূর্ণ, অনুগ্রহ করে নিশ্চিত করুন যে আপনার ডেটা ব্যাকআপ করা আছে।</string>\n    <string name=\"settings\">সেটিংস</string>\n    <string name=\"reboot_recovery\">রিকভারিতে রিবুট করুন</string>\n    <string name=\"home_learn_apatch\">এপ্যাচ সম্পর্কে জানুন</string>\n    <string name=\"send_log\">লগ পাঠান</string>\n    <string name=\"reboot_edl\">EDL এ রিবুট করুন</string>\n    <string name=\"home_click_to_learn_apatch\">অ্যান্ড্রয়েড প্যাচের বৈশিষ্ট্য এবং কীভাবে ব্যবহার করবেন সে সম্পর্কে জানুন</string>\n    <string name=\"patch_set_superkey\">সুপারকি সেট করুন</string>\n    <string name=\"home_patch_next_step\">পরবর্তী ধাপ</string>\n    <string name=\"home_click_to_install\">ইনস্টল করতে ক্লিক করুন</string>\n    <string name=\"home_auth_key_desc\">প্রত্যয়িতকরণের পরে কাজ শুরু করুন</string>\n    <string name=\"home_installing\">ইনস্টলরত</string>\n    <string name=\"home_need_update\">নতুন সংস্করণ উপলভ্য</string>\n    <string name=\"kpatch_version\">সংস্করণ : %s</string>\n    <string name=\"home_not_installed\">ইন্সটল করা নেই</string>\n    <string name=\"home_ap_cando_install\">ইনস্টল করুন</string>\n    <string name=\"patch_title\">প্যাচ</string>\n    <string name=\"home_selinux_status_permissive\">অনুমতিপূর্ন</string>\n    <string name=\"home_selinux_status_enforcing\">কার্যকর করা</string>\n    <string name=\"kpm_args\">আর্গুমেন্টস</string>\n    <string name=\"su_title\">সুপারইউজার</string>\n    <string name=\"kpm_desc\">বিবরণ</string>\n    <string name=\"su_refresh\">রিফ্রেশ</string>\n    <string name=\"apm_failed_to_disable\">\\\"%s\\\" মডিউল বন্ধ করা যায়নি</string>\n    <string name=\"apm_empty\">কোন মডিউল ইনস্টল করা নেই</string>\n    <string name=\"apm_remove\">বাদ দিন</string>\n    <string name=\"apm_failed_to_enable\">মডিউল \\\"%s\\\" চালু করা যায়নি</string>\n    <string name=\"apm_uninstall_confirm\">আপনি কি নিশ্চিত মডিউল %s আনইনস্টল করতে চান?</string>\n    <string name=\"apm_uninstall_success\">%s আনইনস্টল করা হয়েছে</string>\n    <string name=\"home_manager_version\">ম্যানেজার ভার্সন</string>\n    <string name=\"home_fingerprint\">আঙুলের ছাপ</string>\n    <string name=\"home_selinux_status\">SELinux অবস্থা</string>\n    <string name=\"home_selinux_status_disabled\">বন্ধ করুন</string>\n    <string name=\"home_selinux_status_unknown\">অজানা</string>\n    <string name=\"kpm\">KP মডিউল</string>\n    <string name=\"kpm_load\">লোড করুন</string>\n    <string name=\"kpm_unload_confirm\">আপনি কি নিশ্চিত আপনি মডিউল %s আনলোড করতে চান?</string>\n    <string name=\"kpm_unload\">আনলোড</string>\n    <string name=\"kpm_author\">লেখক</string>\n    <string name=\"su_selinux_via_hook\">Hook এর মাধ্যমে বাইপাস করুন</string>\n    <string name=\"su_hide_system_apps\">সিস্টেম অ্যাপ লুকান</string>\n    <string name=\"apm\">AP মডিউল</string>\n    <string name=\"apm_uninstall_failed\">%s আনইনস্টল করা যায়নি</string>\n    <string name=\"apm_author\">লেখক</string>\n    <string name=\"apm_desc\">বিবরণ</string>\n    <string name=\"apm_reboot_to_apply\">কার্যকর করতে রিবুট করুন</string>\n    <string name=\"apm_changelog\">চেঞ্জলগ</string>\n    <string name=\"apm_update\">আপডেট</string>\n    <string name=\"apm_downloading\">\\\"%s\\\" মডিউল ডাউনলোড হচ্ছে…</string>\n    <string name=\"home_kernel\">কার্নেল সংস্ককরণ</string>\n    <string name=\"kpm_kp_not_installed\">কার্নেল প্যাচ ইনস্টল করা নেই</string>\n    <string name=\"kpm_load_toast_failed\">লোড ব্যর্থ হয়েছে</string>\n    <string name=\"kpm_load_toast_succ\">লোড সফল</string>\n    <string name=\"su_pkg_excluded_setting_summary\">এই অপশনটি দ্বারা APatch App এর ভিতরে মডিউল দ্বারা পরিবর্তন হওয়া ফাইল পুনরুদ্ধার করতে পারবে।</string>\n    <string name=\"su_show_system_apps\">সিস্টেম অ্যাপ দেখাও</string>\n    <string name=\"kpm_apm_empty\">কোনো মডিউল লোড করা হয়নি</string>\n    <string name=\"apm_overlay_fs_not_available\">কার্নেল দ্বারা OverlayFS বন্ধ হওয়ার কারণে মডিউলগুলি পাওয়া যায়নি!</string>\n    <string name=\"apm_magisk_conflict\">মডিউলগুলো পাওয়া যায়নি কারণ Magisk এর ভিতর ও একই মডিউল আছে যা সাংঘর্ষিক!</string>\n    <string name=\"apm_new_version_available\">নতুন ভার্সনটি ইনস্টল করতে ক্লিক করুন, %s।</string>\n    <string name=\"su_pkg_excluded_setting_title\">পরিবর্তন যা আছে তা বাদ দিন</string>\n    <string name=\"apm_start_downloading\">%s ডাউনলোড শুরু করুন</string>\n    <string name=\"kpm_version\">সংস্করণ</string>\n    <string name=\"kpm_license\">লাইসেন্স</string>\n    <string name=\"apm_version\">সংস্করণ</string>\n    <string name=\"su_pkg_excluded_label\">বাদ</string>\n    <string name=\"apm_install\">ইনস্টল করুন</string>\n    <string name=\"settings_app_language\">ভাষা</string>\n    <string name=\"system_default\">সিস্টেম ডিফল্ট</string>\n    <string name=\"settings_global_namespace_mode\">গ্লোবাল নেমস্পেস মোড</string>\n    <string name=\"settings_global_namespace_mode_summary\">সব রুট সেশনগুলো গ্লোবাল নেমস্পেসে ব্যবহার করবে</string>\n    <string name=\"settings_clear_super_key_dialog\">আপনি কি সত্যিই চালিয়ে যেতে চান?</string>\n    <string name=\"settings_check_update\">হালনাগাদ চেক করুন</string>\n    <string name=\"settings_check_update_summary\">অ্যাপ খোলার সময় স্বয়ংক্রিয়ভাবে হালনাগাদ চেক করুন</string>\n    <string name=\"kpatch_shadow_path_title\">কেপ্যাচ</string>\n    <string name=\"kpatch_version_update\">সংস্করণ %s → %s</string>\n    <string name=\"clear_super_key\">সুপার_কি মুছুন</string>\n    <string name=\"home_install_unknown_summary\">ইন্সটল করতে ক্লিক করুন</string>\n    <string name=\"home_kpatch_info_title\">তথ্য</string>\n    <string name=\"patch_config_title\">প্যাচসমূহ</string>\n    <string name=\"save_log\">লগ সেভ করুন</string>\n    <string name=\"home_ap_cando_reboot\">রিবুট করুন</string>\n    <string name=\"success\">সাফল্য</string>\n    <string name=\"failure\">ব্যর্থ হয়েছে</string>\n    <string name=\"patch\">প্যাচ</string>\n    <string name=\"patch_item_kpimg_comile_time\">সময়:</string>\n    <string name=\"patch_item_extra_kpm_license\">লাইসেন্স:</string>\n    <string name=\"patch_start_patch_btn\">চালু করুন</string>\n    <string name=\"patch_item_extra_kpm_desciption\">বর্ণনা:</string>\n    <string name=\"patch_item_extra_name\">নাম:</string>\n    <string name=\"patch_item_extra_version\">সংস্করণ:</string>\n    <string name=\"patch_item_extra_author\">লেখক:</string>\n    <string name=\"patch_item_extra_args\">আর্গুমেন্টস:</string>\n    <string name=\"patch_item_kpimg_version\">সংস্করন:</string>\n    <string name=\"patch_item_bootimg_dev\">ডিভাইস:</string>\n    <string name=\"patch_item_extra_event\">ঘটনা:</string>\n    <string name=\"patch_item_skey\">সুপার কি</string>\n    <string name=\"patch_item_set_skey_label\">সুপার পাসওয়ার্ড কমপক্ষে ৮-৬৪ অক্ষর হবে, অক্ষর এবং সংখ্যা দুটো দিয়েই বানাতে হবে পাসওয়ার্ড। কোন চিহ্ন দিয়ে পাসওয়ার্ড বানানো যাবেনা।</string>\n    <string name=\"home_kpatch_version\">কার্নেলপ্যাচ সংস্করণ</string>\n    <string name=\"kpm_add_kpm\">KPM যোগ করুন</string>\n    <string name=\"kpm_install\">ইন্সটল</string>\n    <string name=\"apm_not_installed\">এন্ড্রয়েড প্যাচ ইন্সটল হয়নি</string>\n    <string name=\"home_device_info\">ডিভাইস</string>\n    <string name=\"home_system_version\">সিস্টেমের সংস্করণ</string>\n    <string name=\"patch_item_kpimg_config\">কনফিগ:</string>\n    <string name=\"patch_item_new_extra_kpm\">নতুন করে বসান</string>\n    <string name=\"patch_item_existed_extra_kpm\">বিদ্যমান</string>\n    <string name=\"patch_item_kernel\">কার্নেল</string>\n    <string name=\"kpm_embed\">বসান</string>\n    <string name=\"kpm_control\">নিয়ন্ত্রন</string>\n    <string name=\"hide_apatch_manager\">APatch ম্যানেজারকে লুকান</string>\n    <string name=\"hide_apatch_manager_summary\">রেন্ডম প্যাকেজ আইডি এবং কাস্টম অ্যাপ লেবেল সহ নতুন প্রক্সি অ্যাপ ইনস্টল করুন</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">নতুন ম্যানেজারের নাম</string>\n    <string name=\"hide_apatch_dialog_summary\">এটি লঞ্চারে দেখানো নতুন অ্যাপ লেবেল হিসেবে ব্যবহার করা হবে</string>\n    <string name=\"hide_apatch_manager_failure\">লুকাতে ব্যর্থ হয়েছে, দয়া করে এই সমস্যা অভিযোগ করুন!</string>\n    <string name=\"setting_reset_su_path\">su path কে পুনরায় চালু করুন</string>\n    <string name=\"setting_reset_su_new_path\">নতুন full path</string>\n    <string name=\"enable_web_debugging\">ওয়েবভিউ ডিবাগিং চালু করুন</string>\n    <string name=\"mode_select_page_title\">ইন্সটল</string>\n    <string name=\"mode_select_page_patch_and_install\">প্যাচ এবং ইন্সটল</string>\n    <string name=\"settings_donot_store_superkey_summary\">প্রতিবার ম্যানেজার চালু করার সময় সুপার কি দিন</string>\n    <string name=\"home_new_apatch_found\">আপডেট সংস্করণ এসে গেছে %s, আপগ্রেড করতে এখানে ক্লিক করুন।</string>\n    <string name=\"mode_select_page_install_inactive_slot\">নিষ্ক্রিয় স্লটে ইনস্টল করুন (OTA এর পরে)</string>\n    <string name=\"home_dialog_auth_fail_title\">প্রমান করতে ব্যর্থ হয়েছে</string>\n    <string name=\"enable_web_debugging_summary\">WebUI ডিবাগ করতে ব্যবহার করা যেতে পারে, অনুগ্রহ করে শুধুমাত্র প্রয়োজন হলেই চালু করুন।</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">ফিডব্যাক অথবা পরামর্শ</string>\n    <string name=\"settings_donot_store_superkey\">ফোন এর সিষ্টেমে সুপার কী সংরক্ষণ করবেন না</string>\n    <string name=\"home_dialog_uninstall_ap_only\">এন্ড্রয়েডপ্যাচ দূর করুন</string>\n    <string name=\"settings_custom_color_theme\">কালার থিম</string>\n    <string name=\"amber_theme\">অ্যাম্বার থিম</string>\n    <string name=\"apm_action\">ব্যবস্থা</string>\n    <string name=\"home_dialog_uninstall_all\">সকল কিছু আনইন্সটল করুন</string>\n    <string name=\"kpm_control_dialog_title\">KPমডিউল নিয়ন্ত্রন</string>\n    <string name=\"kpm_control_dialog_content\">ইনপুট নিয়ন্ত্রণ প্যারামিটার:</string>\n    <string name=\"kpm_control_paramters\">প্যারামিটার</string>\n    <string name=\"kpm_control_outMsg\">বার্তা</string>\n    <string name=\"kpm_control_ok\">অপারেশন সফল!</string>\n    <string name=\"kpm_control_failed\">অপারেশন ব্যর্থ!</string>\n    <string name=\"settings_night_mode_follow_sys\">সিস্টেমের ডার্ক থিম অনুসরণ করুন</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">অটোমেটিক ভাবে সিষ্টেম এর সেটিং ফলো করে ডার্ক থিম সেটিং করুন</string>\n    <string name=\"settings_night_theme_enabled\">ডার্ক থিম চালু করুন</string>\n    <string name=\"settings_use_system_color_theme\">সিস্টেম কালার থিম</string>\n    <string name=\"settings_use_system_color_theme_summary\">বর্তমান ওয়ালপেপার এর কালার দ্বারা সিস্টেমে তৈরি হওয়া কালার থিম ব্যবহার করুন</string>\n    <string name=\"blue_grey_theme\">নীল ধূসর</string>\n    <string name=\"blue_theme\">নীল</string>\n    <string name=\"brown_theme\">বাদামী</string>\n    <string name=\"cyan_theme\">নীলাভ সবুজ</string>\n    <string name=\"deep_orange_theme\">গাড় কমলা</string>\n    <string name=\"apm_webui_open\">খুলুন</string>\n    <string name=\"home_more_menu_about\">বিস্তারিত</string>\n    <string name=\"home_dialog_uninstall_title\">আনইনস্টল করুন</string>\n    <string name=\"patch_item_kpimg\">KPইমেজ</string>\n    <string name=\"patch_mode_patch_and_install\">মোড: প্যাচ এবং ইনস্টল</string>\n    <string name=\"patch_item_bootimg\">বুট ইমেজ</string>\n    <string name=\"patch_select_bootimg_btn\">বুট সিলেক্ট করুন</string>\n    <string name=\"patch_mode_install_to_next_slot\">মোড: ইনএক্টিভ সল্টে ইন্সটল করুন( OTA এর পরে)</string>\n    <string name=\"patch_mode_bootimg_patch\">মুড: প্যাচ</string>\n    <string name=\"patch_mode_uninstall_patch\">মোড: আনইন্সটল KPatch</string>\n    <string name=\"patch_embed_kpm_btn\">যুক্ত করা KPM</string>\n    <string name=\"patch_start_unpatch_btn\">আনপ্যাচ করুন</string>\n    <string name=\"patch_item_error\">!!ভুল হচ্ছে!!</string>\n    <string name=\"patch_item_bootimg_slot\">স্লট:</string>\n    <string name=\"log_saved\">লগ সেভ হয়েছে</string>\n    <string name=\"teal_theme\">সবুজ নীল</string>\n    <string name=\"light_green_theme\">হালকা সবুজ</string>\n    <string name=\"lime_theme\">হলুদ সবুজ</string>\n    <string name=\"orange_theme\">কমলা</string>\n    <string name=\"pink_theme\">গেলাপি</string>\n    <string name=\"purple_theme\">বেগুনি</string>\n    <string name=\"about_telegram_group\">টেলিগ্রাম গ্রুপ</string>\n    <string name=\"about_powered_by\">দ্বারা চালিত %1$s</string>\n    <string name=\"about_app_desc\">Kernel রুট সমাধান যা শুধু একটা খোলা Kernel image, যা সিস্টেম মডিউলকে মাউন্ট এবং Kernel ফাংশনকে হুক করার সক্ষমতা প্রদান করে।</string>\n    <string name=\"home_dialog_auth_fail_content\">সুপার কি যাচাই করা যায়নি,তাই Apatch সঠিক ভাবে কাজ করতে পারবেনা\\nযেইসব কারনে এই সমস্যা হতে পারে:\\n১. আপনি boot.img কে KernelPatch দিয়ে Patch করেননি\\n২.Patch করা Boot.img ফ্লাশ করা হয়নি\\n৩.ভুল সুপার কি ব্যাবহার করেছেন বা সুপার কি এর মধ্যে অক্ষর ছাড়াও অন্য বিশেষ ক্যারেক্টার ছিলো\\n৪.আপনার ডিভাইস Apatch এবং KernelPatch সাপোর্ট করেনা\\n\\nদয়া করে আবার সব কিছু চেক করুন, যদি এর পরও সমস্যা হয়, আপনি সব সময় অফিশিয়াল রিপোজিটোরি পেইজে প্রশ্ন করতে পারবেন।</string>\n    <string name=\"crash_handle_copied\">ক্রাশ লগ ক্লিপ বোর্ডে কপি হয়েছে।</string>\n    <string name=\"crash_handle_title\">এপ ক্রাশ করেছে…</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">আপনার ডিভাইস একটি রিবুট এর পর বর্তমান নিষ্ক্রিয় সল্ট এ খুলে যাবে\\nএই অপশনটি শুধু ব্যাবহার করুন OTA আপডেট হয়ে গেলে\\nচালিয়ে যান?</string>\n    <string name=\"green_theme\">সবুজ</string>\n    <string name=\"indigo_theme\">বেগুনি নীল</string>\n    <string name=\"light_blue_theme\">হালকা নীল</string>\n    <string name=\"red_theme\">লাল</string>\n    <string name=\"yellow_theme\">হলুদ</string>\n    <string name=\"about_telegram_channel\">টেলিগ্রাম চ্যানেল</string>\n    <string name=\"mode_select_page_select_file\">প্যাচ করার জন্য বুট ইমেজ সিলেক্ট করুন</string>\n    <string name=\"about_app_version\">সংস্করণ %1$s</string>\n    <string name=\"deep_purple_theme\">গাড় বেগুনি</string>\n    <string name=\"crash_handle_copy\">ক্রাশ এর লগ কপি করুন</string>\n    <string name=\"sakura_theme\">সাকুরা</string>\n    <string name=\"settings_lite_mode\">লাইট মোড চালু করুন</string>\n    <string name=\"settings_lite_mode_mode_summary\">APModule ফাংশনগুলি সক্রিয় করার পরে ক্ষতির সম্মুখীন হতে পারে, কিন্তু মাঝে মধ্যে এটি কার্যকরভাবে সনাক্তকরণ এড়াতে পারে, রিবুট প্রয়োজন।</string>\n    <string name=\"settings_force_overlayfs_mode\">জোর পুর্বক OverlayFS ব্যাবহার করুন</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">OverlayFS ব্যাবহার করে APModules মাউন্ট করুন ম্যাজিক মাউন্ট এর পরিবর্তে যদি কার্নেল এটা সাপোর্ট করে, রিবুট আবশ্যক।</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-ca/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"home\">Inici</string>\n    <string name=\"failure\">Ha fallat</string>\n    <string name=\"patch_warnning\">La instal·lació suposa un risc. Si us plau assegura\\'t de tenir una còpia de seguretat de les teves dades.</string>\n    <string name=\"patch\">Pegat</string>\n    <string name=\"android_patch\">Pegat de l\\'Android</string>\n    <string name=\"settings\">Configuració</string>\n    <string name=\"reboot_bootloader\">Reinicialitza al gestor d\\'arrencada (Bootloader)</string>\n    <string name=\"reboot_recovery\">Reinicialitza al mode recuperació (Recovery)</string>\n    <string name=\"reboot_edl\">Reinicialitza al mode de descàrrega d\\'emergència (EDL)</string>\n    <string name=\"settings_app_language\">Llengua</string>\n    <string name=\"settings_global_namespace_mode\">Mode d\\'espai de noms global</string>\n    <string name=\"settings_check_update\">Cerca actualitzacions</string>\n    <string name=\"home_learn_apatch\">Aprèn APatch</string>\n    <string name=\"home_click_to_learn_apatch\">Obteniu informació sobre les funcions d\\'APatch i com utilitzar-lo</string>\n    <string name=\"home_install_unknown\">No instal·lat ni autenticat</string>\n    <string name=\"home_working\">Treballant 😋</string>\n    <string name=\"apatch_version\">Versió: %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_auth_key_title\">Insereix SuperClau</string>\n    <string name=\"home_ap_cando_update\">Actualitzar</string>\n    <string name=\"home_ap_cando_uninstall\">Desinstal·lar</string>\n    <string name=\"home_ap_cando_reboot\">Reinicialitza</string>\n    <string name=\"success\">Èxit</string>\n    <string name=\"kernel_patch\">Actualització del nucli</string>\n    <string name=\"reboot_download\">Reinicialitza al mode descàrrega</string>\n    <string name=\"reboot\">Reinicia</string>\n    <string name=\"send_log\">Envia els registres</string>\n    <string name=\"settings_global_namespace_mode_summary\">Totes les sessions arrel utilitzen l\\'espai de noms de muntatge global</string>\n    <string name=\"settings_clear_super_key_dialog\">Realment voleu continuar?</string>\n    <string name=\"settings_check_update_summary\">Comprova automàticament si hi ha actualitzacions en obrir l\\'aplicació</string>\n    <string name=\"about\">Sobre</string>\n    <string name=\"about_source_code\">&lt;p&gt;Veure el codi font a %1$s&lt;p/&gt; Uneix-te al nostre %2$s canal&lt;p/&gt;Uneix-te al nostre %3$s grup</string>\n    <string name=\"save_log\">Desa els registres</string>\n    <string name=\"system_default\">Opció per defecte del sistema</string>\n    <string name=\"clear_super_key\">Elimina SuperClau</string>\n    <string name=\"super_key\">SuperClau</string>\n    <string name=\"home_patch_next_step\">Següent pas</string>\n    <string name=\"safe_mode\">Mode segur</string>\n    <string name=\"patch_set_superkey\">Estableix SuperClau</string>\n    <string name=\"home_not_installed\">No instal·lada</string>\n    <string name=\"home_click_to_install\">Clica per instal·lar</string>\n    <string name=\"home_install_unknown_summary\">Clica per instal·lar</string>\n    <string name=\"kpatch_version\">Versió: %s</string>\n    <string name=\"kpatch_version_update\">Versió: %s -&gt; %s</string>\n    <string name=\"home_kpatch_info_title\">Informació</string>\n    <string name=\"home_auth_key_desc\">Comença després de la certificació</string>\n    <string name=\"home_ap_cando_install\">Instal·lar</string>\n    <string name=\"patch_title\">Pegat</string>\n    <string name=\"home_patch_set_key_desc\">Només credencial per KernelPatch</string>\n    <string name=\"apatch_version_update\">Versió: %s -&gt; %s</string>\n    <string name=\"patch_config_title\">Pegat</string>\n    <string name=\"patch_mode_bootimg_patch\">Mode: Pegat</string>\n    <string name=\"patch_mode_patch_and_install\">Mode: Aplicar pegat i instal·lar</string>\n    <string name=\"home_installing\">Instal·lant</string>\n    <string name=\"home_need_update\">Hi ha una nova versió disponible</string>\n    <string name=\"log_saved\">Registre desat</string>\n    <string name=\"patch_item_error\">ERROR!!</string>\n    <string name=\"patch_item_bootimg_slot\">slot:</string>\n    <string name=\"patch_item_bootimg_dev\">dispositiu:</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_extra_kpm_license\">Llicència:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Descripció:</string>\n    <string name=\"kpm_unload\">Deshabilitar</string>\n    <string name=\"kpm_control\">Control</string>\n    <string name=\"kpm_apm_empty\">No hi ha mòduls carregats</string>\n    <string name=\"su_title\">Superusuari</string>\n    <string name=\"su_pkg_excluded_label\">excloure</string>\n    <string name=\"su_pkg_excluded_setting_title\">Excloure modificacions</string>\n    <string name=\"su_show_system_apps\">Mostrar aplicacions del sistema</string>\n    <string name=\"apm_empty\">Cap mòdul instal·lat</string>\n    <string name=\"apm_version\">Versió</string>\n    <string name=\"patch_item_kpimg_comile_time\">Hora:</string>\n    <string name=\"patch_item_kpimg_version\">Versió:</string>\n    <string name=\"patch_item_kpimg_config\">Config:</string>\n    <string name=\"home_fingerprint\">Empremta del dispositiu</string>\n    <string name=\"home_device_info\">Dispositiu</string>\n    <string name=\"home_system_version\">Versió del sistema</string>\n    <string name=\"home_selinux_status_unknown\">Desconegut</string>\n    <string name=\"kpm_load\">Carregar</string>\n    <string name=\"kpm_add_kpm\">Afegir KPM</string>\n    <string name=\"kpm_install\">Instal·lar</string>\n    <string name=\"patch_start_patch_btn\">Començar</string>\n    <string name=\"patch_embed_kpm_btn\">Integrar KPM</string>\n    <string name=\"patch_item_new_extra_kpm\">Insereix nou</string>\n    <string name=\"patch_item_extra_author\">Autor:</string>\n    <string name=\"patch_item_extra_version\">Versió:</string>\n    <string name=\"patch_item_extra_name\">Nom:</string>\n    <string name=\"home_kernel\">Kernel</string>\n    <string name=\"home_selinux_status_disabled\">Deshabilitat</string>\n    <string name=\"home_apatch_version\">Versió de APatch</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch no instal·lat</string>\n    <string name=\"kpm_embed\">Inserir</string>\n    <string name=\"home_kpatch_version\">Versió de KernelPatch</string>\n    <string name=\"kpm_version\">Versió</string>\n    <string name=\"kpm_license\">Llicència</string>\n    <string name=\"kpm_desc\">Descripció</string>\n    <string name=\"kpm_author\">Autor</string>\n    <string name=\"su_refresh\">Actualitzar</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"apm_not_installed\">AndroidPatch no instal·lat</string>\n    <string name=\"su_hide_system_apps\">Amagar aplicacions del sistema</string>\n    <string name=\"apm_install\">Instal·lar</string>\n    <string name=\"apm_desc\">Descripció</string>\n    <string name=\"apm_author\">Autor</string>\n    <string name=\"patch_item_skey\">Super Key</string>\n    <string name=\"patch_select_bootimg_btn\">Selecciona el mode d\\'arrencada</string>\n    <string name=\"patch_start_unpatch_btn\">Desfer pegat</string>\n    <string name=\"patch_mode_uninstall_patch\">Mode: Desinstal·lar KPatch</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mode: Instal·lar a la ranura inactiva (després de l\\'OTA)</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-cs/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"patch_warnning\">Při instalaci může dojít k problémům. Ujistěte se prosím, že vaše data jsou zálohována.</string>\n    <string name=\"reboot_bootloader\">Restartovat do: Zavaděč</string>\n    <string name=\"reboot_recovery\">Restartovat do: Obnova</string>\n    <string name=\"reboot_edl\">Restartovat do: EDL</string>\n    <string name=\"about\">O projektu</string>\n    <string name=\"settings_app_language\">Jazyk</string>\n    <string name=\"home_working\">Funguje 😋</string>\n    <string name=\"home_ap_cando_install\">Instalovat</string>\n    <string name=\"home_ap_cando_uninstall\">Odinstalovat</string>\n    <string name=\"home_ap_cando_reboot\">Restartovat</string>\n    <string name=\"patch_title\">Záplata</string>\n    <string name=\"patch_config_title\">Záplaty</string>\n    <string name=\"patch_mode_bootimg_patch\">Režim: Záplata</string>\n    <string name=\"patch_mode_install_to_next_slot\">Režim: Instalace do dalšího slotu (po OTA)</string>\n    <string name=\"patch_mode_patch_and_install\">Režim: Záplata a instalace</string>\n    <string name=\"patch_mode_uninstall_patch\">Režim: Odinstalovat KPatch</string>\n    <string name=\"patch_select_bootimg_btn\">Vybrat boot</string>\n    <string name=\"patch_embed_kpm_btn\">Vložit KPM</string>\n    <string name=\"patch_start_patch_btn\">Spustit</string>\n    <string name=\"reboot_download\">Restartovat do: Stahování</string>\n    <string name=\"reboot\">Restartovat</string>\n    <string name=\"settings\">Nastavení</string>\n    <string name=\"home_click_to_learn_apatch\">Zjistit více o funkcích APatch a jak je používat</string>\n    <string name=\"home_ap_cando_update\">Aktualizovat</string>\n    <string name=\"home\">Domů</string>\n    <string name=\"success\">Úspěch</string>\n    <string name=\"failure\">Selhání</string>\n    <string name=\"patch\">Záplata</string>\n    <string name=\"system_default\">Systém (výchozí)</string>\n    <string name=\"settings_global_namespace_mode\">Režim globálního jmenného prostoru</string>\n    <string name=\"settings_global_namespace_mode_summary\">Všechny kořenové relace používají připojený globální jmenný prostor</string>\n    <string name=\"settings_clear_super_key_dialog\">Opravdu chcete pokračovat?</string>\n    <string name=\"patch_item_new_extra_kpm\">Vložit nový</string>\n    <string name=\"purple_theme\">Fialové</string>\n    <string name=\"settings_check_update\">Zkontrolovat aktualizace</string>\n    <string name=\"patch_item_kpimg_version\">Verze:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Čas:</string>\n    <string name=\"patch_item_kpimg_config\">Konfigurace:</string>\n    <string name=\"send_log\">Odeslat protokoly</string>\n    <string name=\"safe_mode\">Nouzový režim</string>\n    <string name=\"clear_super_key\">Vymazat SuperKlíč</string>\n    <string name=\"patch_set_superkey\">Nastavit SuperKlíč</string>\n    <string name=\"home_not_installed\">Nenainstalováno</string>\n    <string name=\"home_install_unknown\">Není nainstalováno nebo ověřeno</string>\n    <string name=\"home_need_update\">Dostupná nová verze</string>\n    <string name=\"home_installing\">Instaluje se</string>\n    <string name=\"home_click_to_install\">Kliknutím nainstalovat</string>\n    <string name=\"apatch_version\">Verze: %s</string>\n    <string name=\"apatch_version_update\">Verze: %s -&gt; %s</string>\n    <string name=\"patch_item_bootimg_dev\">zařízení:</string>\n    <string name=\"settings_check_update_summary\">Automaticky kontrolovat aktualizace při otevření aplikace</string>\n    <string name=\"save_log\">Uložit protokoly</string>\n    <string name=\"log_saved\">Protokoly uloženy</string>\n    <string name=\"super_key\">SuperKlíč</string>\n    <string name=\"home_patch_next_step\">Další krok</string>\n    <string name=\"kpatch_version\">Verze: %s</string>\n    <string name=\"kpatch_version_update\">Verze: %s -&gt; %s</string>\n    <string name=\"home_install_unknown_summary\">Kliknutím nainstalovat</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Zobrazit zdrojový kód na %1$s<p/> Připojit se k našemu kanálu %2$s<p/> Připojit se k naší skupině %3$s]]></string>\n    <string name=\"home_learn_apatch\">Prozkoumat APatch</string>\n    <string name=\"patch_start_unpatch_btn\">Odstranit záplatu</string>\n    <string name=\"apm_uninstall_success\">%s odinstalován</string>\n    <string name=\"apm_overlay_fs_not_available\">Moduly nejsou k dispozici, protože OverlayFS je zakázáno jádrem!</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">Informace</string>\n    <string name=\"home_auth_key_desc\">Spustit po ověření</string>\n    <string name=\"patch_item_error\">!!CHYBA!!</string>\n    <string name=\"patch_item_bootimg_slot\">slot:</string>\n    <string name=\"patch_item_extra_name\">Jméno:</string>\n    <string name=\"patch_item_extra_kpm_license\">Licence:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Popis:</string>\n    <string name=\"patch_item_extra_args\">Parametry:</string>\n    <string name=\"patch_item_extra_event\">Událost:</string>\n    <string name=\"patch_item_skey\">SuperKlíč</string>\n    <string name=\"home_fingerprint\">Otisk zařízení</string>\n    <string name=\"home_selinux_status\">Stav SELinuxu</string>\n    <string name=\"home_selinux_status_unknown\">Neznámý</string>\n    <string name=\"home_selinux_status_enforcing\">Vynucený</string>\n    <string name=\"home_selinux_status_disabled\">Vypnutý</string>\n    <string name=\"home_device_info\">Zařízení</string>\n    <string name=\"home_system_version\">Verze systému</string>\n    <string name=\"home_su_path\">Spustitelný su</string>\n    <string name=\"home_apatch_version\">Verze APatch</string>\n    <string name=\"kpm\">KPModul</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch není nainstalován</string>\n    <string name=\"kpm_load\">Načíst</string>\n    <string name=\"kpm_install\">Instalovat</string>\n    <string name=\"kpm_embed\">Vložit</string>\n    <string name=\"kpm_unload_confirm\">Vyjmout modul \\\"%s\\\"?</string>\n    <string name=\"kpm_control\">Ovládání</string>\n    <string name=\"kpm_version\">Verze</string>\n    <string name=\"kpm_license\">Licence</string>\n    <string name=\"kpm_author\">Autor</string>\n    <string name=\"kpm_desc\">Popis</string>\n    <string name=\"su_pkg_excluded_label\">vyloučit</string>\n    <string name=\"su_pkg_excluded_setting_title\">Vyloučit úpravy</string>\n    <string name=\"su_hide_system_apps\">Skrýt systémové aplikace</string>\n    <string name=\"su_refresh\">Оbnovit</string>\n    <string name=\"apm\">APModul</string>\n    <string name=\"apm_failed_to_enable\">Nelze zapnout modul \\\"%s\\\"</string>\n    <string name=\"apm_downloading\">Stahování modulu \\\"%s\\\"…</string>\n    <string name=\"hide_apatch_dialog_summary\">Nový název bude zobrazen ve spouštěči</string>\n    <string name=\"setting_reset_su_path\">Obnovit cestu su</string>\n    <string name=\"setting_reset_su_new_path\">Nová úplná cesta</string>\n    <string name=\"settings_donot_store_superkey_summary\">Při každém spuštění manažera bude vyžadován SuperKlíč</string>\n    <string name=\"home_auth_key_title\">Zadejte SuperKlíč</string>\n    <string name=\"home_patch_set_key_desc\">Pouze pro ověření KernelPatch</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Zapnutí způsobí to, že APatch použije pro tuto aplikaci soubory, které nejsou upraveny moduly.</string>\n    <string name=\"su_show_system_apps\">Zobrazit systémové aplikace</string>\n    <string name=\"hide_apatch_manager_summary\">Instalovat nového manažera s náhodným ID balíčku a vlastním názvem</string>\n    <string name=\"hide_apatch_manager_failure\">Skrytí se nezdařilo, prosím nahlaste chybu!</string>\n    <string name=\"apm_not_installed\">AndroidPatch není nainstalován</string>\n    <string name=\"apm_desc\">Popis</string>\n    <string name=\"apm_reboot_to_apply\">Restartujte, aby se projevil účinek</string>\n    <string name=\"apm_start_downloading\">Stahování %s</string>\n    <string name=\"apm_new_version_available\">Je k dispozici nová verze: %s, kliknutím aktualizovat.</string>\n    <string name=\"home_kernel\">Jádro</string>\n    <string name=\"patch_item_kernel\">Jádro</string>\n    <string name=\"patch_item_extra_author\">Autor:</string>\n    <string name=\"patch_item_existed_extra_kpm\">Existuje</string>\n    <string name=\"patch_item_extra_version\">Verze:</string>\n    <string name=\"patch_item_set_skey_label\">Délka SuperKlíče by měla být alespoň 8 znaků a měla by obsahovat čísla a písmena, ale bez speciálních znaků.</string>\n    <string name=\"home_manager_version\">Verze manažera</string>\n    <string name=\"home_selinux_status_permissive\">Tolerantní (povolený s protokolováním)</string>\n    <string name=\"home_kpatch_version\">Verze KernelPatch</string>\n    <string name=\"kpm_add_kpm\">Přidat KPM</string>\n    <string name=\"kpm_load_toast_succ\">Načtení dokončeno</string>\n    <string name=\"kpm_load_toast_failed\">Načtení selhalo</string>\n    <string name=\"kpm_unload\">Vyjmout</string>\n    <string name=\"kpm_apm_empty\">Žádný modul není načten</string>\n    <string name=\"kpm_args\">Parametry</string>\n    <string name=\"su_title\">SuperUživatel</string>\n    <string name=\"su_selinux_via_hook\">obejít přes háček</string>\n    <string name=\"enable_web_debugging\">Povolit ladění WebView</string>\n    <string name=\"settings_donot_store_superkey\">Neukládat SuperKlíč v zařízení</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"apm_uninstall_failed\">Nelze odinstalovat %s</string>\n    <string name=\"enable_web_debugging_summary\">Může být použito k ladění WebUI. Prosím, tuto možnost povolte pouze v případě potřeby.</string>\n    <string name=\"apm_empty\">Není nainstalován žádný modul</string>\n    <string name=\"apm_uninstall_confirm\">Odinstalovat modul \\\"%s?</string>\n    <string name=\"apm_magisk_conflict\">Moduly nejsou k dispozici kvůli konfliktu s Magiskem!</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nový název manažera</string>\n    <string name=\"apm_failed_to_disable\">Nelze vypnout modul \\\"%s\\\"</string>\n    <string name=\"hide_apatch_manager\">Skrýt manažera APatch</string>\n    <string name=\"apm_version\">Verze</string>\n    <string name=\"apm_changelog\">Seznam změn</string>\n    <string name=\"apm_update\">Aktualizovat</string>\n    <string name=\"apm_webui_open\">Otevřít</string>\n    <string name=\"apm_remove\">Odstranit</string>\n    <string name=\"apm_install\">Instalovat</string>\n    <string name=\"apm_author\">Autor</string>\n    <string name=\"apm_action\">Akce</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"home_more_menu_about\">O projektu</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"home_new_apatch_found\">Je k dispozici nová verze: %s, kliknutím aktualizovat.</string>\n    <string name=\"mode_select_page_select_file\">Vybrat a záplatovat bootovací obraz</string>\n    <string name=\"kpm_control_dialog_title\">Ovládání KPModulu</string>\n    <string name=\"home_dialog_auth_fail_content\">Nelze ověřit SuperKlíč, proto APatch nemůže správně fungovat.\\nZde jsou některé možné důvody selhání:\\n1. Bootovací obraz nebyl opraven pomocí KernelPatch.\\n2. Opravený bootovací obraz nebyl flashován.\\n3. SuperKlíč je špatný.\\n4. Vaše zařízení nepodporuje APatch a KernelPatch.\\n\\nZkontrolujte prosím a zkuste to znovu. Pokud problémy přetrvávají, můžete se zeptat na stránce s problémy oficiálního úložiště.</string>\n    <string name=\"mode_select_page_patch_and_install\">Záplatovat a nainstalovat</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Vaše zařízení bude po restartu **NUCENĚ** startovat do neaktivního slotu!\\nTuto možnost použijte až po dokončení OTA.\\nPokračovat?</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Instalovat do neaktivního slotu (po OTA)</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Odebrat AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Odinstalovat vše</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Zpětná vazba nebo návrhy</string>\n    <string name=\"home_dialog_auth_fail_title\">Ověření selhalo</string>\n    <string name=\"home_dialog_uninstall_title\">Odinstalovat</string>\n    <string name=\"mode_select_page_title\">Instalovat</string>\n    <string name=\"settings_use_system_color_theme\">Systémové barevné téma</string>\n    <string name=\"blue_theme\">Modré</string>\n    <string name=\"lime_theme\">Limetkové</string>\n    <string name=\"sakura_theme\">Sakurové</string>\n    <string name=\"kpm_control_dialog_content\">Zadejte ovládací parametry:</string>\n    <string name=\"kpm_control_paramters\">Parametry</string>\n    <string name=\"kpm_control_outMsg\">Zpráva</string>\n    <string name=\"kpm_control_ok\">Operace se zdařila!</string>\n    <string name=\"kpm_control_failed\">Operace selhala!</string>\n    <string name=\"settings_night_mode_follow_sys\">Následovat tmavé systémové téma</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Automaticky přepnout na tmavé téma se systémem</string>\n    <string name=\"settings_night_theme_enabled\">Povolit tmavé téma</string>\n    <string name=\"settings_use_system_color_theme_summary\">Použít barevné téma generované systémem z aktuální tapety</string>\n    <string name=\"amber_theme\">Jantarové</string>\n    <string name=\"blue_grey_theme\">Modrošedé</string>\n    <string name=\"brown_theme\">Hnědé</string>\n    <string name=\"cyan_theme\">Azurové</string>\n    <string name=\"deep_orange_theme\">Tmavě oranžové</string>\n    <string name=\"deep_purple_theme\">Tmavě fialové</string>\n    <string name=\"green_theme\">Zelené</string>\n    <string name=\"indigo_theme\">Indigové</string>\n    <string name=\"light_blue_theme\">Světle modré</string>\n    <string name=\"light_green_theme\">Světle zelené</string>\n    <string name=\"orange_theme\">Oranžové</string>\n    <string name=\"teal_theme\">Modrozelené</string>\n    <string name=\"yellow_theme\">Žluté</string>\n    <string name=\"settings_custom_color_theme\">Barevné téma</string>\n    <string name=\"pink_theme\">Růžové</string>\n    <string name=\"red_theme\">Červené</string>\n    <string name=\"about_app_version\">Verze %1$s</string>\n    <string name=\"about_app_desc\">Kernel Root je řešení pouze pro holý obraz jádra, který poskytuje možnost připojení systémového modulu a zaháčkování funkce jádra.</string>\n    <string name=\"about_telegram_channel\">Kanál na Telegramu</string>\n    <string name=\"about_telegram_group\">Skupina na Telegramu</string>\n    <string name=\"about_powered_by\">Běží na %1$s</string>\n    <string name=\"crash_handle_title\">Aplikace selhala…</string>\n    <string name=\"crash_handle_copy\">Kopírovat protokol o selhání</string>\n    <string name=\"crash_handle_copied\">Kopírovat protokol o selhání do schránky.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-da/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"home\">Hjem</string>\n    <string name=\"failure\">Fejl</string>\n    <string name=\"patch\">Patch</string>\n    <string name=\"success\">Success</string>\n    <string name=\"patch_warnning\">Installation kommer med risici. Sørg for, at dine data er sikkerhedskopieret.</string>\n    <string name=\"home_click_to_install\">Klik for at installere</string>\n    <string name=\"home_installing\">Installerer</string>\n    <string name=\"home_ap_cando_install\">Installer</string>\n    <string name=\"save_log\">Gem log</string>\n    <string name=\"settings_app_language\">Sprog</string>\n    <string name=\"settings_check_update_summary\">Check automatisk for opdateringer ved start af appen</string>\n    <string name=\"safe_mode\">Sikker modus</string>\n    <string name=\"home_install_unknown_summary\">Klik for at installere</string>\n    <string name=\"home_working\">Arbejder 😋</string>\n    <string name=\"home_patch_next_step\">Næste skridt</string>\n    <string name=\"send_log\">Send logs</string>\n    <string name=\"log_saved\">Log gemt</string>\n    <string name=\"home_need_update\">Ny version tilgængelig</string>\n    <string name=\"settings_clear_super_key_dialog\">Vil du virkelig fortsætte?</string>\n    <string name=\"home_not_installed\">Ikke installeret</string>\n    <string name=\"home_ap_cando_reboot\">Genstart</string>\n    <string name=\"settings\">Indstillinger</string>\n    <string name=\"reboot\">Genstart</string>\n    <string name=\"about\">Om</string>\n    <string name=\"settings_check_update\">Check opdatering</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home_click_to_learn_apatch\">Erfahre mehr über die Funktionen von APatch und wie man sie verwendet</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Quellcode anzeigen unter %1$s<p/>Trete unserem %2$s Kanel bei<p/>Trete unserer %3$s Gruppe bei]]></string>\n    <string name=\"home\">Startseite</string>\n    <string name=\"reboot\">Neustart</string>\n    <string name=\"settings\">Einstellungen</string>\n    <string name=\"home_install_unknown\">Unbekannt</string>\n    <string name=\"home_need_update\">Eine neue Version ist verfügbar</string>\n    <string name=\"apatch_version\">Version: %s</string>\n    <string name=\"home_ap_cando_install\">Installieren</string>\n    <string name=\"home_ap_cando_update\">Aktualisieren</string>\n    <string name=\"home_ap_cando_uninstall\">Deinstallieren</string>\n    <string name=\"home_kernel\">Kernelversion</string>\n    <string name=\"home_not_installed\">Nicht installiert</string>\n    <string name=\"home_fingerprint\">Fingerabdruck</string>\n    <string name=\"patch_warnning\">Die Installation ist mit Risiken verbunden. Bitte stellen Sie sicher, dass Ihre Daten gesichert sind.</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot_bootloader\">Neustart zum Bootloader</string>\n    <string name=\"home_learn_apatch\">Lerne APatch kennen</string>\n    <string name=\"home_patch_set_key_desc\">Nur Anmeldedaten für KernelPatch</string>\n    <string name=\"home_patch_next_step\">Nächster Schritt</string>\n    <string name=\"kpatch_version\">Version: %s</string>\n    <string name=\"apatch_version_update\">Version: %s -&gt; %s</string>\n    <string name=\"home_auth_key_desc\">Start nach Zertifizierung</string>\n    <string name=\"home_manager_version\">Manager Version</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Durch Aktivierung dieser Option kann APatch alle von den Modulen dieser App geänderten Dateien wiederherstellen.</string>\n    <string name=\"apm_failed_to_disable\">Das Modul \\\"%s\\\" konnte nicht deaktiviert werden</string>\n    <string name=\"home_selinux_status_disabled\">Deaktiviert</string>\n    <string name=\"apm_magisk_conflict\">Module sind aufgrund eines Konfliktes mit Magisk nicht verfügbar.</string>\n    <string name=\"apm_downloading\">Modul \\\"%s\\\" wird heruntergeladen…</string>\n    <string name=\"apm_start_downloading\">Download von %s starten</string>\n    <string name=\"kpm_unload_confirm\">Modul \\\"%s\\\" entladen?</string>\n    <string name=\"apm_failed_to_enable\">Das Modul \\\"%s\\\" konnte nicht eingeschaltet werden</string>\n    <string name=\"home_apatch_version\">APatch Version</string>\n    <string name=\"home_selinux_status\">SELinux-Status</string>\n    <string name=\"reboot_recovery\">Neustart zum Wiederherstellen</string>\n    <string name=\"reboot_download\">Neustart zum Herunterladen</string>\n    <string name=\"reboot_edl\">Neustart zur EDL</string>\n    <string name=\"about\">Über</string>\n    <string name=\"send_log\">Logs senden</string>\n    <string name=\"safe_mode\">Sicherer Modus</string>\n    <string name=\"home_click_to_install\">Klicke zum Installieren</string>\n    <string name=\"home_working\">Funktioniert</string>\n    <string name=\"home_su_path\">su: %s</string>\n    <string name=\"patch_title\">Patch</string>\n    <string name=\"su_pkg_excluded_label\">Absondern</string>\n    <string name=\"home_selinux_status_enforcing\">Erzwingt</string>\n    <string name=\"home_selinux_status_permissive\">Zulässig</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"clear_super_key\">Superschlüssel löschen</string>\n    <string name=\"patch_set_superkey\">Superschlüssel festlegen</string>\n    <string name=\"home_installing\">Installiert</string>\n    <string name=\"home_auth_key_title\">Superschlüssel eingeben</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"home_selinux_status_unknown\">Unbekannt</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch nicht installiert</string>\n    <string name=\"kpm_unload\">Entladen</string>\n    <string name=\"kpm_apm_empty\">Kein Modul geladen</string>\n    <string name=\"apm\">APModul</string>\n    <string name=\"apm_not_installed\">AndroidPatch nicht installiert</string>\n    <string name=\"apm_empty\">Kein Modul installiert</string>\n    <string name=\"apm_uninstall_confirm\">Modul \\\"%s\\\" deinstallieren?</string>\n    <string name=\"apm_overlay_fs_not_available\">Module sind nicht verfügbar, da OverlayFS vom Kernel deaktiviert ist!</string>\n    <string name=\"apm_reboot_to_apply\">Neustarten, um Änderungen zu speichern</string>\n    <string name=\"apm_new_version_available\">Neue Version %s ist verfügbar, klicken Sie zum Aktualisieren.</string>\n    <string name=\"apm_uninstall_success\">%s deinstalliert</string>\n    <string name=\"kpm_load\">Laden</string>\n    <string name=\"kpm_version\">Version</string>\n    <string name=\"kpm_license\">Lizenz</string>\n    <string name=\"kpm_author\">Autor</string>\n    <string name=\"su_title\">Superuser</string>\n    <string name=\"su_show_system_apps\">Systemanwendungen zeigen</string>\n    <string name=\"su_hide_system_apps\">System-Apps ausblenden</string>\n    <string name=\"apm_remove\">Entfernen</string>\n    <string name=\"apm_install\">Installieren</string>\n    <string name=\"apm_uninstall_failed\">Konnte %s nicht deinstallieren</string>\n    <string name=\"apm_version\">Version</string>\n    <string name=\"apm_update\">Aktualisieren</string>\n    <string name=\"apm_author\">Autor</string>\n    <string name=\"kpm_load_toast_succ\">Laden erfolgreich</string>\n    <string name=\"kpm_load_toast_failed\">Laden fehlgeschlagen</string>\n    <string name=\"kpm_desc\">Beschreibung</string>\n    <string name=\"kpm_args\">Argumente</string>\n    <string name=\"su_selinux_via_hook\">Umgehung über einhaken</string>\n    <string name=\"su_pkg_excluded_setting_title\">Änderungen ausschließen</string>\n    <string name=\"su_refresh\">Aktualisieren</string>\n    <string name=\"apm_desc\">Beschreibung</string>\n    <string name=\"apm_changelog\">Änderungsprotokoll</string>\n    <string name=\"settings_app_language\">Sprache</string>\n    <string name=\"system_default\">Systemstandard</string>\n    <string name=\"patch\">Patch</string>\n    <string name=\"settings_global_namespace_mode\">Globaler Namespace-Modus</string>\n    <string name=\"settings_global_namespace_mode_summary\">Alle Root-Sitzungen verwenden den globalen Mount-Namespace</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">Info</string>\n    <string name=\"settings_clear_super_key_dialog\">Wollen Sie wirklich fortfahren?</string>\n    <string name=\"kpatch_version_update\">Version: %s -&gt; %s</string>\n    <string name=\"patch_config_title\">Korrekturen</string>\n    <string name=\"patch_mode_bootimg_patch\">Modus: Korrektur</string>\n    <string name=\"patch_mode_uninstall_patch\">Modus: EntKorrektur</string>\n    <string name=\"home_ap_cando_reboot\">Neustart</string>\n    <string name=\"patch_select_bootimg_btn\">Wählen Sie Start</string>\n    <string name=\"patch_embed_kpm_btn\">Eingebettetes KPM</string>\n    <string name=\"patch_start_unpatch_btn\">EntKorrektur</string>\n    <string name=\"patch_item_bootimg\">Startbild</string>\n    <string name=\"patch_item_error\">!!Fehler!!</string>\n    <string name=\"patch_item_bootimg_slot\">Schacht:</string>\n    <string name=\"patch_item_bootimg_dev\">Gerät:</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Version:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Dauer:</string>\n    <string name=\"patch_item_kpimg_config\">Konfiguration:</string>\n    <string name=\"patch_item_new_extra_kpm\">Neues einbetten</string>\n    <string name=\"patch_item_extra_name\">Name:</string>\n    <string name=\"patch_item_extra_version\">Version:</string>\n    <string name=\"patch_item_extra_author\">Autor:</string>\n    <string name=\"patch_item_extra_kpm_license\">Lizenz:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Beschreibung:</string>\n    <string name=\"patch_item_extra_args\">Args:</string>\n    <string name=\"patch_item_extra_event\">Ereignis:</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"patch_start_patch_btn\">Starten</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_existed_extra_kpm\">existiert</string>\n    <string name=\"patch_item_set_skey_label\">Der SuperKey sollte 8 bis 63 Zeichen lang sein und Zahlen sowie Buchstaben enthalten, jedoch keine Sonderzeichen.</string>\n    <string name=\"settings_check_update\">Auf Updates prüfen</string>\n    <string name=\"home_install_unknown_summary\">Klicke zum Installieren</string>\n    <string name=\"patch_mode_patch_and_install\">Modus: Patchen und installieren</string>\n    <string name=\"enable_web_debugging\">WebView-Debugging aktivieren</string>\n    <string name=\"blue_grey_theme\">Blaugrau</string>\n    <string name=\"amber_theme\">Bernstein</string>\n    <string name=\"blue_theme\">Blau</string>\n    <string name=\"brown_theme\">Braun</string>\n    <string name=\"green_theme\">Grün</string>\n    <string name=\"about_telegram_group\">Telegram-Gruppe</string>\n    <string name=\"about_telegram_channel\">Telegram-Kanal</string>\n    <string name=\"settings_check_update_summary\">Beim Öffnen der App automatisch nach Updates suchen</string>\n    <string name=\"enable_web_debugging_summary\">Kann zum debuggen von WebUI benutzt werden. Bitte nur bei Bedarf aktivieren.</string>\n    <string name=\"apm_webui_open\">Öffnen</string>\n    <string name=\"failure\">Fehler</string>\n    <string name=\"success\">Erfolg</string>\n    <string name=\"home_device_info\">Gerät</string>\n    <string name=\"home_kpatch_version\">KernelPatch Version</string>\n    <string name=\"home_system_version\">Systemversion</string>\n    <string name=\"kpm_embed\">Einbetten</string>\n    <string name=\"kpm_control\">Steuerung</string>\n    <string name=\"kpm_add_kpm\">KPM hinzufügen</string>\n    <string name=\"kpm_install\">Installieren</string>\n    <string name=\"hide_apatch_manager\">APatch Manager ausblenden</string>\n    <string name=\"setting_reset_su_new_path\">Neuer vollständiger Pfad</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Neuer Name des Managers</string>\n    <string name=\"mode_select_page_patch_and_install\">Patchen und installieren</string>\n    <string name=\"mode_select_page_title\">Installieren</string>\n    <string name=\"mode_select_page_select_file\">Wählen Sie ein Boot-Image zum Patchen aus</string>\n    <string name=\"home_dialog_auth_fail_title\">Authentifizierung fehlgeschlagen</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Rückmeldung oder Anregung</string>\n    <string name=\"home_more_menu_about\">Über</string>\n    <string name=\"home_dialog_uninstall_title\">Deinstallieren</string>\n    <string name=\"home_dialog_uninstall_ap_only\">AndroidPatch entfernen</string>\n    <string name=\"kpm_control_dialog_title\">KPModule steuern</string>\n    <string name=\"kpm_control_paramters\">Parameter</string>\n    <string name=\"kpm_control_outMsg\">Nachricht</string>\n    <string name=\"kpm_control_failed\">Operation fehlgeschlagen!</string>\n    <string name=\"home_dialog_uninstall_all\">Alle deinstallieren</string>\n    <string name=\"kpm_control_ok\">Operation erfolgreich!</string>\n    <string name=\"settings_night_mode_follow_sys\">Dunklem Schema des Systems folgen</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Automatischer Wechsel zu einem dunklen Schema basierend auf den Systemeinstellungen</string>\n    <string name=\"settings_night_theme_enabled\">Dunkles Schema aktivieren</string>\n    <string name=\"settings_use_system_color_theme\">Systemfarbschema</string>\n    <string name=\"patch_mode_install_to_next_slot\">Modus: In inaktivem Slot installieren (Nach OTA)</string>\n    <string name=\"setting_reset_su_path\">su-Pfad zurücksetzen</string>\n    <string name=\"hide_apatch_manager_failure\">Verstecken fehlgeschlagen. Bitte melde den Fehler!</string>\n    <string name=\"settings_donot_store_superkey\">Superschlüssel nicht lokal speichern</string>\n    <string name=\"home_new_apatch_found\">Eine neue Version %s ist verfügbar, klicken Sie hier, um zu aktualisieren.</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Auf inaktiven Slot installieren (Nach OTA)</string>\n    <string name=\"hide_apatch_manager_summary\">Installieren Sie eine Proxy-App mit einer zufälligen Paket-ID und einer benutzerdefinierten App-Bezeichnung</string>\n    <string name=\"hide_apatch_dialog_summary\">Wird als App-Bezeichnung auf dem Home-Screen genutzt</string>\n    <string name=\"settings_donot_store_superkey_summary\">Authentifiziere den SuperKey jedes Mal, wenn der Manager gestartet wird.</string>\n    <string name=\"kpm_control_dialog_content\">Eingabekontrollparameter:</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Dein Gerät wird **GEZWUNGEN**, nach dem Neustart den inaktiven Slot zu nutzen!\n\\nNutze diese Funktion ausschließlich, wenn ein OTA-Update durchgeführt wurde.\n\\nFortfahren?</string>\n    <string name=\"settings_custom_color_theme\">Farbschema</string>\n    <string name=\"deep_orange_theme\">Tieforange</string>\n    <string name=\"cyan_theme\">Cyan</string>\n    <string name=\"deep_purple_theme\">Tiefviolett</string>\n    <string name=\"indigo_theme\">Indigo</string>\n    <string name=\"light_blue_theme\">Hellblau</string>\n    <string name=\"light_green_theme\">Hellgrün</string>\n    <string name=\"lime_theme\">Limone</string>\n    <string name=\"orange_theme\">Orange</string>\n    <string name=\"sakura_theme\">Sakura</string>\n    <string name=\"pink_theme\">Rosa</string>\n    <string name=\"purple_theme\">Lila</string>\n    <string name=\"teal_theme\">Türkisblau</string>\n    <string name=\"yellow_theme\">Gelb</string>\n    <string name=\"about_app_version\">Version %1$s</string>\n    <string name=\"about_powered_by\">Unterstützt durch %1$s</string>\n    <string name=\"red_theme\">Rot</string>\n    <string name=\"about_app_desc\">Kernel-Root-Lösung mit nur einem gestrippten Kernel-Image, das die Möglichkeit bietet, Systemmodule zu mounten und Kernel-Funktionen einzuhängen.</string>\n    <string name=\"settings_use_system_color_theme_summary\">Verwende ein Farbthema, das basierend aus dem aktuellen Hintergrund vom System erzeugt wird</string>\n    <string name=\"home_dialog_auth_fail_content\">Superschlüssel kann nicht authentifiziert werden, daher kann APatch nicht richtig funktionieren. \\nMögliche Gründe für Authentifizierungsfehler können sein: \\n1. Das boot.img wurde nicht mit dem KernelPatch gepatcht. \\n2. Das gepatchte boot.img wurde nicht geflasht. \\n3. Superschlüssel ist falsch, oder enthält Sonderzeichen. \\n4. Ihr Gerät unterstützt APatch und KernelPatch nicht. \\n \\nBitte überprüfen und nochmal versuchen. Wenn weiterhin Probleme auftreten, können Fragen auf der offiziellen Issues-Seite des Repository gestellt werden.</string>\n    <string name=\"save_log\">Logs speichern</string>\n    <string name=\"apm_action\">Aktion</string>\n    <string name=\"log_saved\">Protokoll gespeichert</string>\n    <string name=\"crash_handle_copy\">Absturzprotokoll kopieren</string>\n    <string name=\"crash_handle_copied\">Absturzprotokoll in die Zwischenablage kopiert.</string>\n    <string name=\"crash_handle_title\">App ist abgestürzt…</string>\n    <string name=\"settings_lite_mode\">Lite-Modus einschalten</string>\n    <string name=\"settings_lite_mode_mode_summary\">APModul-Funktionen können nach ihrer Aktivierung Fehler aufweisen, aber in einigen Fällen können sie immer noch effektiv die Erkennung vermeiden. Neustart erforderlich.</string>\n    <string name=\"settings_force_overlayfs_mode\">Verwendung von OverlayFS erzwingen</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Verwende, wenn Kernel-Unterstützung verfügbar ist, OverlayFS zum Einhängen von APModulen anstelle von Magic Mount. Neustart erforderlich.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-el/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"patch_warnning\">Η εγκατάσταση συνοδεύεται από κινδύνους. Βεβαιωθείτε ότι έχετε δημιουργήσει αντίγραφα ασφαλείας των δεδομένων σας.</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot\">Επανεκκίνηση</string>\n    <string name=\"settings\">Ρυθμίσεις</string>\n    <string name=\"reboot_bootloader\">Επανεκκίνηση στον Bootloader</string>\n    <string name=\"home\">Αρχική</string>\n    <string name=\"system_default\">Προεπιλογή συστήματος</string>\n    <string name=\"reboot_edl\">Επανεκκίνηση σε EDL</string>\n    <string name=\"reboot_recovery\">Επανεκκίνηση στο Recovery</string>\n    <string name=\"reboot_download\">Επανεκκίνηση για λήψη</string>\n    <string name=\"about\">Σχετικά με το</string>\n    <string name=\"home_learn_apatch\">Μάθετε το APatch</string>\n    <string name=\"home_click_to_learn_apatch\">Μάθετε για τα χαρακτηριστικά του APatch και πώς να το χρησιμοποιείτε</string>\n    <string name=\"settings_app_language\">Γλώσσα</string>\n    <string name=\"patch\">Επιδιόρθωση</string>\n    <string name=\"home_auth_key_title\">Εισαγάγετε το ΥπέρΚλειδί</string>\n    <string name=\"apm\">Ενότητα AP</string>\n    <string name=\"apm_install\">Εγκατάσταση</string>\n    <string name=\"apm_update\">Ενημέρωση</string>\n    <string name=\"home_need_update\">Νέα έκδοση διαθέσιμη</string>\n    <string name=\"home_working\">Λειτουργεί 😋</string>\n    <string name=\"patch_title\">Επιδιόρθωση</string>\n    <string name=\"kpatch_version\">Έκδοση: %s</string>\n    <string name=\"kpm_unload_confirm\">Ξεφόρτωση ενότητας \\\"%s\\\"?</string>\n    <string name=\"apatch_version\">Έκδοση: %s</string>\n    <string name=\"home_fingerprint\">Δακτυλικό αποτύπωμα</string>\n    <string name=\"su_title\">Υπερχρήστης</string>\n    <string name=\"apm_downloading\">Λήψη της ενότητας \\\"%s\\\"…</string>\n    <string name=\"su_hide_system_apps\">Απόκρυψη εφαρμογών συστήματος</string>\n    <string name=\"home_selinux_status_disabled\">Απενεργοποιημένο</string>\n    <string name=\"kpm_author\">Δημιουργός</string>\n    <string name=\"home_click_to_install\">Κλικ για εγκατάσταση</string>\n    <string name=\"home_ap_cando_install\">Εγκατάσταση</string>\n    <string name=\"apm_not_installed\">Το AndroidPatch δεν έχει εγκατασταθεί</string>\n    <string name=\"su_refresh\">Ανανέωση</string>\n    <string name=\"home_selinux_status\">Κατάσταση SELinux</string>\n    <string name=\"send_log\">Αποστολή αρχείων καταγραφής</string>\n    <string name=\"safe_mode\">Ασφαλής λειτουργία</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Προβολή πηγαίου κώδικα στο %1$s<p/>Εγγραφείτε στο κανάλι μας %2$s<p/>Εγγραφείτε στην ομάδα μας %3$s]]></string>\n    <string name=\"apm_uninstall_confirm\">Απεγκατάσταση ενότητας \\\"%s\\\"?</string>\n    <string name=\"apm_failed_to_disable\">Δεν ήταν δυνατή η απενεργοποίηση της ενότητας \\\"%s\\\"</string>\n    <string name=\"apm_empty\">Δεν υπάρχει εγκατεστημένη ενότητα</string>\n    <string name=\"apm_remove\">Αφαίρεση</string>\n    <string name=\"apm_desc\">Περιγραφή</string>\n    <string name=\"apm_reboot_to_apply\">Επανεκκίνηση για να τεθεί σε ισχύ</string>\n    <string name=\"apm_changelog\">Καταγραφή αλλαγών</string>\n    <string name=\"apm_overlay_fs_not_available\">Οι ενότητες δεν είναι διαθέσιμες καθώς το OverlayFS είναι απενεργοποιημένο από τον πυρήνα!</string>\n    <string name=\"apm_magisk_conflict\">Οι ενότητες δεν είναι διαθέσιμες λόγω διένεξης με το Magisk!</string>\n    <string name=\"apm_new_version_available\">Η νέα έκδοση %s είναι διαθέσιμη, κάντε κλικ για αναβάθμιση.</string>\n    <string name=\"apm_start_downloading\">Έναρξη λήψης %s</string>\n    <string name=\"super_key\">ΥπέρΚλειδί</string>\n    <string name=\"clear_super_key\">Εκκαθάριση ΥπέρΚλειδιού</string>\n    <string name=\"patch_set_superkey\">Ορισμός ΥπέρΚλειδιού</string>\n    <string name=\"home_patch_set_key_desc\">Μόνο διαπιστευτήρια για το KernelPatch</string>\n    <string name=\"home_patch_next_step\">Επόμενο βήμα</string>\n    <string name=\"home_not_installed\">Δεν έχει εγκατασταθεί</string>\n    <string name=\"home_install_unknown\">Δεν έχει εγκατασταθεί ή πιστοποιηθεί</string>\n    <string name=\"home_installing\">Γίνεται εγκατάσταση</string>\n    <string name=\"apatch_version_update\">Έκδοση: %s -&gt; %s</string>\n    <string name=\"home_su_path\">Εκτελέσιμο su</string>\n    <string name=\"home_auth_key_desc\">Έναρξη μετά την πιστοποίηση</string>\n    <string name=\"home_ap_cando_update\">Ενημέρωση</string>\n    <string name=\"home_kernel\">Έκδοση Πυρήνα</string>\n    <string name=\"home_manager_version\">Έκδοση διαχειριστή</string>\n    <string name=\"home_selinux_status_enforcing\">Επιβολή</string>\n    <string name=\"home_selinux_status_permissive\">Επιτρεπτικό</string>\n    <string name=\"home_selinux_status_unknown\">Άγνωστο</string>\n    <string name=\"kpm\">Ενότητα KP</string>\n    <string name=\"kpm_load\">Φόρτωση</string>\n    <string name=\"kpm_load_toast_failed\">Αποτυχία φόρτωσης</string>\n    <string name=\"kpm_unload\">Ξεφόρτωση</string>\n    <string name=\"kpm_version\">Έκδοση</string>\n    <string name=\"kpm_desc\">Περιγραφή</string>\n    <string name=\"kpm_args\">Επιχειρήματα</string>\n    <string name=\"su_pkg_excluded_label\">Αποκλεισμένο</string>\n    <string name=\"su_pkg_excluded_setting_title\">Εξαίρεση τροποποιήσεων</string>\n    <string name=\"apm_failed_to_enable\">Δεν ήταν δυνατή η ενεργοποίηση της ενότητας \\\"%s\\\"</string>\n    <string name=\"apm_uninstall_failed\">Δεν ήταν δυνατή η απεγκατάσταση του %s</string>\n    <string name=\"apm_version\">Έκδοση</string>\n    <string name=\"apm_author\">Δημιουργός</string>\n    <string name=\"home_ap_cando_uninstall\">Απεγκατάσταση</string>\n    <string name=\"home_apatch_version\">Έκδοση APatch</string>\n    <string name=\"kpm_kp_not_installed\">Το KernelPatch δεν έχει εγκατασταθεί</string>\n    <string name=\"kpm_load_toast_succ\">Επιτυχής φόρτωση</string>\n    <string name=\"kpm_apm_empty\">Δεν έχει φορτωθεί καμία ενότητα</string>\n    <string name=\"kpm_license\">Άδεια</string>\n    <string name=\"su_selinux_via_hook\">παράκαμψη μέσω γάντζου</string>\n    <string name=\"su_show_system_apps\">Εμφάνιση εφαρμογών συστήματος</string>\n    <string name=\"apm_uninstall_success\">%s απεγκαταστάθηκε</string>\n    <string name=\"success\">Επιτυχία</string>\n    <string name=\"failure\">Αποτυχία</string>\n    <string name=\"settings_clear_super_key_dialog\">Θέλετε πραγματικά να προχωρήσετε?</string>\n    <string name=\"settings_check_update\">Έλεγχος για ενημερώσεις</string>\n    <string name=\"settings_check_update_summary\">Αυτόματος έλεγχος για ενημερώσεις κατά το άνοιγμα της εφαρμογής</string>\n    <string name=\"save_log\">Αποθήκευση αρχείων καταγραφής</string>\n    <string name=\"deep_purple_theme\">Βαθύ μώβ</string>\n    <string name=\"green_theme\">Πράσινο</string>\n    <string name=\"indigo_theme\">Indigo</string>\n    <string name=\"light_blue_theme\">Γαλάζιο</string>\n    <string name=\"log_saved\">Τα αρχεία καταγραφής αποθηκεύτηκαν</string>\n    <string name=\"home_kpatch_version\">Έκδοση KernelPatch</string>\n    <string name=\"amber_theme\">Κεχριμπαρένιο</string>\n    <string name=\"blue_theme\">Μπλέ</string>\n    <string name=\"setting_reset_su_path\">Επαναφορά διαδρομής su</string>\n    <string name=\"pink_theme\">Ροζ</string>\n    <string name=\"purple_theme\">Μώβ</string>\n    <string name=\"crash_handle_title\">Η εφαρμογή κατέρρευσε…</string>\n    <string name=\"crash_handle_copy\">Αντιγραφή αρχείου καταγραφής σφαλμάτων</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Η ενεργοποίηση αυτής της επιλογής θα επιτρέψει στο APatch να επαναφέρει τυχόν αρχεία που έχουν τροποποιηθεί από τις λειτουργικές μονάδες αυτής της εφαρμογής.</string>\n    <string name=\"settings_custom_color_theme\">Χρώμα θέματος</string>\n    <string name=\"blue_grey_theme\">Μπλέ γκρί</string>\n    <string name=\"enable_web_debugging_summary\">Μπορεί να χρησιμοποιηθεί για εντοπισμό σφαλμάτων WebUI, Παρακαλώ ενεργοποιήσει μόνο όταν χρειάζεται.</string>\n    <string name=\"hide_apatch_manager_summary\">Εγκατάσταση μιας εφαρμογής proxy με τυχαίο αναγνωριστικό πακέτου και προσαρμοσμένη ετικέτα εφαρμογής</string>\n    <string name=\"home_dialog_auth_fail_content\">Δεν είναι δυνατός ο έλεγχος ταυτότητας του ΥπέρΚλειδιού, επομένως το APatch δεν μπορεί να λειτουργήσει σωστά.\\nΑκολουθούν ορισμένοι πιθανοί λόγοι για την αποτυχία του ελέγχου ταυτότητας:\\n1. Δεν επιδιορθώσατε το boot.img με το KernelPatch.\\n2. Το διορθωμένο boot.img δεν περάστηκε.\\n3. Το ΥπέρΚλειδί είναι λάθος ή περιέχει ειδικούς χαρακτήρες.\\n4. Η συσκευή σας δεν υποστηρίζει το APatch και KernelPatch.\\n\\nΕλέγξτε και δοκιμάστε ξανά. Εάν εξακολουθούν να υπάρχουν προβλήματα, μπορείτε πάντα να κάνετε ερωτήσεις στη σελίδα ζητημάτων του επίσημου αποθετηρίου.</string>\n    <string name=\"crash_handle_copied\">Το αρχείο καταγραφής σφαλμάτων αντιγράφηκε στο πρόχειρο.</string>\n    <string name=\"settings_global_namespace_mode\">Λειτουργία καθολικού χώρου ονομάτων</string>\n    <string name=\"settings_global_namespace_mode_summary\">Όλες οι συνεδρίες root χρησιμοποιούν τον χώρο ονομάτων καθολικής προσάρτησης</string>\n    <string name=\"home_install_unknown_summary\">Κλικ για εγκατάσταση</string>\n    <string name=\"kpatch_version_update\">Έκδοση: %s -&gt; %s</string>\n    <string name=\"patch_select_bootimg_btn\">Επιλογή boot</string>\n    <string name=\"patch_start_patch_btn\">Έναρξη</string>\n    <string name=\"patch_mode_uninstall_patch\">Λειτουργία: Απεγκατάσταση KPatch</string>\n    <string name=\"patch_embed_kpm_btn\">Ενσωμάτωση KPM</string>\n    <string name=\"patch_item_kernel\">Πυρήνας</string>\n    <string name=\"patch_item_kpimg_version\">Έκδοση:</string>\n    <string name=\"patch_item_new_extra_kpm\">Ενσωμάτωση νέου</string>\n    <string name=\"patch_item_existed_extra_kpm\">Υπήρχε</string>\n    <string name=\"patch_item_extra_name\">Όνομα:</string>\n    <string name=\"patch_item_extra_kpm_license\">Άδεια:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Περιγραφή:</string>\n    <string name=\"home_device_info\">Συσκευή</string>\n    <string name=\"home_system_version\">Έκδοση συστήματος</string>\n    <string name=\"kpm_add_kpm\">Προσθήκη KPM</string>\n    <string name=\"hide_apatch_manager\">Απόκρυψη Διαχειριστή APatch</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Νέο όνομα διαχειριστή</string>\n    <string name=\"hide_apatch_dialog_summary\">Θα χρησιμοποιηθεί ως η νέα ετικέτα εφαρμογής που εμφανίζεται στο πρόγραμμα εκκίνησης</string>\n    <string name=\"hide_apatch_manager_failure\">Αποτυχία απόκρυψης, Παρακαλώ αναφέρετε το σφάλμα!</string>\n    <string name=\"settings_donot_store_superkey\">Μη αποθήκευση ΥπέρΚλειδιού τοπικά</string>\n    <string name=\"enable_web_debugging\">Ενεργοποίηση εντοπισμού σφαλμάτων WebView</string>\n    <string name=\"mode_select_page_patch_and_install\">Επιδιόρθωση και Εγκατάσταση</string>\n    <string name=\"mode_select_page_select_file\">Επιλογή εικόνας boot για επιδιόρθωση</string>\n    <string name=\"home_new_apatch_found\">Νέα έκδοση %s είναι διαθέσιμη, κλικ για αναβάθμιση.</string>\n    <string name=\"mode_select_page_title\">Εγκατάσταση</string>\n    <string name=\"home_dialog_auth_fail_title\">Ο έλεγχος ταυτότητας απέτυχε</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"patch_item_kpimg_comile_time\">Ώρα:</string>\n    <string name=\"patch_item_error\">!!ΣΦΑΛΜΑ!!</string>\n    <string name=\"patch_item_kpimg_config\">Διαμόρφωση:</string>\n    <string name=\"patch_item_extra_version\">Έκδοση:</string>\n    <string name=\"kpm_install\">Εγκατάσταση</string>\n    <string name=\"kpm_embed\">Ενσωμάτωση</string>\n    <string name=\"apm_webui_open\">Άνοιγμα</string>\n    <string name=\"about_app_desc\">Λύση Kernel root με μόνο μια απογυμνωμένη εικόνα πυρήνα, παρέχοντας τη δυνατότητα προσάρτησης της μονάδας συστήματος και την λειτουργία αγκίστρωσης πυρήνα.</string>\n    <string name=\"home_kpatch_info_title\">Πληροφορίες</string>\n    <string name=\"patch_mode_bootimg_patch\">Λειτουργία: Επιδιόρθωση</string>\n    <string name=\"patch_mode_patch_and_install\">Λειτουργία: Επιδιόρθωση και εγκατάσταση</string>\n    <string name=\"patch_item_bootimg_dev\">συσκευή:</string>\n    <string name=\"patch_item_extra_event\">Συμβάν:</string>\n    <string name=\"patch_item_skey\">ΥπέρΚλειδί</string>\n    <string name=\"patch_item_set_skey_label\">Το ΥπέρΚλειδί πρέπει να έχει μήκος 8-63 χαρακτήρες και να περιλαμβάνει αριθμούς και γράμματα, αλλά όχι ειδικούς χαρακτήρες.</string>\n    <string name=\"patch_mode_install_to_next_slot\">Λειτουργία: Εγκατάσταση σε ανενεργή υποδοχή (Μετά από OTA)</string>\n    <string name=\"patch_item_bootimg_slot\">υποδοχή:</string>\n    <string name=\"home_ap_cando_reboot\">Επανεκκίνηση</string>\n    <string name=\"kpm_control\">Έλεγχος</string>\n    <string name=\"settings_donot_store_superkey_summary\">Έλεγχος ταυτότητας του ΥπέρΚλειδιού κάθε φορά που ξεκινά ο διαχειριστής</string>\n    <string name=\"setting_reset_su_new_path\">Νέα πλήρης διαδρομή</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Αφαίρεση AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Απεγκατάσταση όλων</string>\n    <string name=\"kpm_control_dialog_title\">Έλεγχος KPModule</string>\n    <string name=\"kpm_control_dialog_content\">Παράμετροι ελέγχου εισόδου:</string>\n    <string name=\"kpm_control_paramters\">Παράμετροι</string>\n    <string name=\"kpm_control_outMsg\">Μήνυμα</string>\n    <string name=\"kpm_control_ok\">Η λειτουργία πέτυχε!</string>\n    <string name=\"kpm_control_failed\">Η λειτουργία απέτυχε!</string>\n    <string name=\"settings_night_mode_follow_sys\">Ακολουθώντας το σκούρο θέμα συστήματος</string>\n    <string name=\"settings_use_system_color_theme\">Χρωματικό θέμα συστήματος</string>\n    <string name=\"settings_use_system_color_theme_summary\">Χρήση χρωματικού θέματος που δημιουργείται από το σύστημα με βάση την τρέχουσα ταπετσαρία</string>\n    <string name=\"light_green_theme\">Ανοιχτό Πράσινο</string>\n    <string name=\"red_theme\">Κόκκινο</string>\n    <string name=\"sakura_theme\">Σάκουρα</string>\n    <string name=\"teal_theme\">Γαλαζοπράσινο</string>\n    <string name=\"yellow_theme\">Κίτρινο</string>\n    <string name=\"about_app_version\">Έκδοση %1$s</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Ανατροφοδότηση ή πρόταση</string>\n    <string name=\"about_telegram_channel\">Κανάλι Telegram</string>\n    <string name=\"home_more_menu_about\">Σχετικά με</string>\n    <string name=\"home_dialog_uninstall_title\">Απεγκατάσταση</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Αυτόματη εναλλαγή σε σκούρο θέμα με βάση τις ρυθμίσεις συστήματος</string>\n    <string name=\"settings_night_theme_enabled\">Ενεργοποίηση σκούρου θέματος</string>\n    <string name=\"brown_theme\">Καφέ</string>\n    <string name=\"cyan_theme\">Κυανό</string>\n    <string name=\"deep_orange_theme\">Βαθύ πορτοκαλί</string>\n    <string name=\"lime_theme\">Lime</string>\n    <string name=\"orange_theme\">Πορτοκαλί</string>\n    <string name=\"apm_action\">Ενέργεια</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Εγκατάσταση σε ανενεργή υποδοχή (Μετά από OTA)</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Η συσκευή σας θα **ΑΝΑΓΚΑΣΤΕΙ** να εκκινηθεί στην τρέχουσα ανενεργή υποδοχή μετά από μια επανεκκίνηση!\\nΧρήση της επιλογής μόνο αφού ολοκληρωθεί το OTA.\\nΣυνέχεια;</string>\n    <string name=\"about_telegram_group\">Ομάδα Telegram</string>\n    <string name=\"about_powered_by\">Τροφοδοτείται από %1$s</string>\n    <string name=\"patch_start_unpatch_btn\">UnPatch</string>\n    <string name=\"patch_config_title\">Patches</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_extra_author\">Δημιουργός</string>\n    <string name=\"patch_item_extra_args\">Επιχειρήματα:</string>\n    <string name=\"settings_lite_mode\">Ενεργοποίηση λειτουργίας Lite</string>\n    <string name=\"settings_lite_mode_mode_summary\">Οι λειτουργίες του APModule ενδέχεται να παρουσιάσουν σφάλματα μετά την ενεργοποίηση τους, αλλά σε ορισμένες περιπτώσεις μπορούν να αποφύγουν αποτελεσματικά τον εντοπισμό. Απαιτείται επανεκκίνηση.</string>\n    <string name=\"settings_force_overlayfs_mode\">Επιβολή χρήσης OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Χρήση του OverlayFS για προσάρτηση του APModules αντί για το Magic Mount όταν είναι διαθέσιμη η υποστήριξη από τον πυρήνα. Απαιτείται επανεκκίνηση.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"apm\">APModule</string>\n    <string name=\"super_key\">Superclave</string>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"patch_warnning\">La instalación conlleva riesgos. Así que asegúrate de tener una copia de seguridad de tus datos.</string>\n    <string name=\"home\">Inicio</string>\n    <string name=\"reboot_download\">Reiniciar al modo «download»</string>\n    <string name=\"home_click_to_learn_apatch\">Aprende sobre las características de APatch y de cómo sacarles partido</string>\n    <string name=\"reboot_edl\">Reiniciar al modo EDL</string>\n    <string name=\"reboot_recovery\">Reiniciar al modo recuperación</string>\n    <string name=\"home_learn_apatch\">Más información sobre APatch</string>\n    <string name=\"about\">Acerca de</string>\n    <string name=\"reboot\">Reiniciar</string>\n    <string name=\"settings\">Ajustes</string>\n    <string name=\"reboot_bootloader\">Reiniciar al gestor de arranque</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Ver código fuente en %1$s<p/>Unirse a nuestro canal de %2$s<p/>Unirse a nuestro grupo de %3$s]]></string>\n    <string name=\"send_log\">Enviar registro de fallos</string>\n    <string name=\"kpatch_version\">Versión: %s</string>\n    <string name=\"home_patch_set_key_desc\">Clave única para KernelPatch</string>\n    <string name=\"home_install_unknown\">Sin instalar o autenticar</string>\n    <string name=\"home_installing\">Instalando</string>\n    <string name=\"apatch_version\">Versión: %s</string>\n    <string name=\"safe_mode\">Modo seguro</string>\n    <string name=\"home_click_to_install\">Haz clic para instalar</string>\n    <string name=\"home_need_update\">Hay una nueva versión disponible</string>\n    <string name=\"patch_set_superkey\">Definir superclave</string>\n    <string name=\"home_su_path\">Ejecutable «su»</string>\n    <string name=\"apatch_version_update\">Versión: %s → %s</string>\n    <string name=\"home_working\">Funcionando 😋</string>\n    <string name=\"home_patch_next_step\">Siguiente paso</string>\n    <string name=\"home_not_installed\">Sin instalar</string>\n    <string name=\"home_auth_key_desc\">Comenzar tras la certificación</string>\n    <string name=\"home_ap_cando_install\">Instalar</string>\n    <string name=\"home_auth_key_title\">Escribir superclave</string>\n    <string name=\"home_ap_cando_update\">Actualizar</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch no está instalado</string>\n    <string name=\"home_fingerprint\">Huella del dispositivo</string>\n    <string name=\"home_selinux_status_unknown\">Desconocido</string>\n    <string name=\"home_selinux_status_permissive\">Permisivo</string>\n    <string name=\"home_selinux_status\">Estado de SELinux</string>\n    <string name=\"home_selinux_status_disabled\">Desactivado</string>\n    <string name=\"kpm_load\">Cargar</string>\n    <string name=\"home_kernel\">Versión del kernel</string>\n    <string name=\"home_selinux_status_enforcing\">Obligatorio</string>\n    <string name=\"home_manager_version\">Versión de la aplicación</string>\n    <string name=\"patch_title\">Parchear</string>\n    <string name=\"kpm_load_toast_succ\">Cargado correctamente</string>\n    <string name=\"kpm_unload_confirm\">¿Desactivar el módulo «%s»?</string>\n    <string name=\"su_pkg_excluded_setting_title\">Excluir y evitar modificaciones</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Los archivos cambiados por los módulos serán invisibles para la aplicación al activar esta opción.</string>\n    <string name=\"su_pkg_excluded_label\">excluido</string>\n    <string name=\"su_title\">Superusuario</string>\n    <string name=\"kpm_desc\">Desc</string>\n    <string name=\"su_selinux_via_hook\">eludir mediante «hook»</string>\n    <string name=\"kpm_args\">Parám</string>\n    <string name=\"kpm_version\">Versión</string>\n    <string name=\"su_show_system_apps\">Mostrar aplicaciones del sistema</string>\n    <string name=\"kpm_author\">Autor</string>\n    <string name=\"kpm_load_toast_failed\">La carga ha fallado</string>\n    <string name=\"kpm_unload\">Desactivar</string>\n    <string name=\"kpm_license\">Licencia</string>\n    <string name=\"kpm_apm_empty\">No hay ningún módulo cargado</string>\n    <string name=\"apm_reboot_to_apply\">Es necesario reiniciar para que los cambios surtan efecto</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"apm_uninstall_success\">Se ha desinstalado %s</string>\n    <string name=\"apm_install\">Instalar</string>\n    <string name=\"apm_remove\">Quitar</string>\n    <string name=\"apm_uninstall_confirm\">¿Desinstalar el módulo «%s»?</string>\n    <string name=\"apm_version\">Versión</string>\n    <string name=\"apm_start_downloading\">Descargar %s</string>\n    <string name=\"home_ap_cando_uninstall\">Desinstalar</string>\n    <string name=\"apm_overlay_fs_not_available\">¡Los módulos no están disponibles ya que OverlayFS está desactivado por el kernel!</string>\n    <string name=\"su_refresh\">Actualizar</string>\n    <string name=\"apm_failed_to_disable\">No se pudo desactivar el módulo «%s»</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"home_apatch_version\">Versión de APatch</string>\n    <string name=\"apm_changelog\">Notas de cambios</string>\n    <string name=\"apm_uninstall_failed\">No se pudo desinstalar %s</string>\n    <string name=\"apm_failed_to_enable\">No se pudo activar el módulo «%s»</string>\n    <string name=\"apm_downloading\">Descargando el módulo «%s»…</string>\n    <string name=\"su_hide_system_apps\">Ocultar aplicaciones del sistema</string>\n    <string name=\"apm_magisk_conflict\">¡Los módulos no están disponibles debido a un conflicto con Magisk!</string>\n    <string name=\"apm_desc\">Descripción</string>\n    <string name=\"apm_new_version_available\">Hay una nueva versión (%s) disponible. Toca para actualizar.</string>\n    <string name=\"apm_empty\">No hay ningún módulo instalado</string>\n    <string name=\"apm_update\">Actualizar</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"apm_author\">Autor</string>\n    <string name=\"clear_super_key\">Borrar superclave</string>\n    <string name=\"apm_not_installed\">AndroidPatch no está instalado</string>\n    <string name=\"settings_app_language\">Idioma</string>\n    <string name=\"system_default\">Predeterminado del sistema</string>\n    <string name=\"patch\">Parchear</string>\n    <string name=\"settings_global_namespace_mode\">Modo de espacio de nombres global</string>\n    <string name=\"settings_global_namespace_mode_summary\">Todas las sesiones «root» utilizan el espacio de nombres de montaje global</string>\n    <string name=\"settings_clear_super_key_dialog\">¿Seguro que quieres continuar?</string>\n    <string name=\"kpatch_version_update\">Versión: %s → %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">Info</string>\n    <string name=\"home_ap_cando_reboot\">Reiniciar</string>\n    <string name=\"patch_config_title\">Parches</string>\n    <string name=\"patch_mode_bootimg_patch\">Modo: Parchear</string>\n    <string name=\"patch_mode_patch_and_install\">Modo: Parchear e instalar</string>\n    <string name=\"patch_mode_uninstall_patch\">Modo: Desinstalar KPatch</string>\n    <string name=\"patch_select_bootimg_btn\">Elige un archivo «boot»</string>\n    <string name=\"patch_embed_kpm_btn\">Insertar KPM</string>\n    <string name=\"patch_start_patch_btn\">Iniciar</string>\n    <string name=\"patch_start_unpatch_btn\">Quitar parches</string>\n    <string name=\"patch_item_bootimg\">boot.img</string>\n    <string name=\"patch_item_bootimg_dev\">dispositivo:</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Versión:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Hora:</string>\n    <string name=\"patch_item_kpimg_config\">Config:</string>\n    <string name=\"patch_item_new_extra_kpm\">Insertar nuevo</string>\n    <string name=\"patch_item_existed_extra_kpm\">Ya incluido:</string>\n    <string name=\"patch_item_extra_version\">Versión:</string>\n    <string name=\"patch_item_extra_author\">Autor:</string>\n    <string name=\"patch_item_extra_kpm_license\">Licencia:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Descripción:</string>\n    <string name=\"patch_item_extra_args\">Parám:</string>\n    <string name=\"patch_item_extra_event\">Evento:</string>\n    <string name=\"patch_item_skey\">Superclave</string>\n    <string name=\"patch_item_set_skey_label\">La superclave debe tener entre 8 y 63 caracteres e incluir números y letras, pero no caracteres especiales.</string>\n    <string name=\"patch_item_extra_name\">Nombre:</string>\n    <string name=\"patch_item_error\">¡ERROR!</string>\n    <string name=\"patch_item_bootimg_slot\">slot:</string>\n    <string name=\"hide_apatch_manager\">Ocultar APatch Manager</string>\n    <string name=\"kpm_embed\">Insertar</string>\n    <string name=\"success\">Hecho</string>\n    <string name=\"kpm_install\">Instalar</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nombre nuevo de APatch Manager</string>\n    <string name=\"hide_apatch_manager_summary\">Instala una nueva aplicación de APatch Manager con un ID aleatorio y una etiqueta personalizada</string>\n    <string name=\"hide_apatch_dialog_summary\">Será la nueva etiqueta que aparezca en el lanzador de aplicaciones</string>\n    <string name=\"hide_apatch_manager_failure\">No se pudo ocultar, informa a los desarrolladores del error.</string>\n    <string name=\"setting_reset_su_path\">Restablecer la ruta a «su»</string>\n    <string name=\"setting_reset_su_new_path\">Nueva ruta completa</string>\n    <string name=\"failure\">Fallido</string>\n    <string name=\"kpm_add_kpm\">Añadir KPM</string>\n    <string name=\"settings_check_update_summary\">Buscar actualizaciones automáticamente al abrir la aplicación</string>\n    <string name=\"settings_check_update\">Buscar actualizaciones</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Comentarios o sugerencias</string>\n    <string name=\"home_more_menu_about\">Acerca de</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Instalar en la partición («slot») inactiva (tras una actualización OTA)</string>\n    <string name=\"mode_select_page_select_file\">Elige una imagen de arranque «boot» que parchear</string>\n    <string name=\"home_dialog_auth_fail_title\">La autenticación ha fallado</string>\n    <string name=\"mode_select_page_title\">Instalar</string>\n    <string name=\"mode_select_page_patch_and_install\">Parchear e instalar</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Tu dispositivo se verá **OBLIGADO** a arrancar desde la partición («slot») que ahora está inactiva. \\nUtiliza esta opción solo cuando una actualización del sistema (OTA) haya terminado de instalarse, justo antes de tener que reiniciar. \\n¿Quieres continuar?</string>\n    <string name=\"enable_web_debugging\">Habilitar depuración de WebView</string>\n    <string name=\"home_install_unknown_summary\">Haz clic para instalar</string>\n    <string name=\"home_device_info\">Dispositivo</string>\n    <string name=\"home_system_version\">Versión del sistema</string>\n    <string name=\"home_kpatch_version\">Versión de KernelPatch</string>\n    <string name=\"home_dialog_uninstall_title\">Desinstalar</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Quitar AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Desinstalarlo todo</string>\n    <string name=\"home_dialog_auth_fail_content\">Parece que la superclave no da resultado, por lo que APatch no funcionará correctamente. \\nA continuación se muestran algunas posibles causas de este error de autenticación: \\n1. No has parcheado el «boot.img» original con KernelPatch. \\n2. No has flasheado (vía «fastboot flash») dicho «boot.img» ya parcheado. \\n3. La superclave que has elegido no es correcta o contiene caracteres especiales.\\n4. Tu dispositivo no es compatible con APatch o KernelPatch. \\n \\nRepásalo todo e inténtalo de nuevo. Si sigue habiendo problemas siempre puedes hacer preguntas en inglés en la pestaña «issues» del repositorio oficial.</string>\n    <string name=\"apm_webui_open\">Abrir</string>\n    <string name=\"enable_web_debugging_summary\">Se puede utilizar para depurar WebUI, actívalo solo si se necesita de verdad.</string>\n    <string name=\"settings_donot_store_superkey\">No guardar la superclave de forma local</string>\n    <string name=\"patch_mode_install_to_next_slot\">Modo: Instalar en el «slot» inactivo (tras OTA)</string>\n    <string name=\"settings_donot_store_superkey_summary\">Pedir que se escriba la superclave al abrir APatch Manager</string>\n    <string name=\"home_new_apatch_found\">Nueva versión disponible: %s, toca para actualizar.</string>\n    <string name=\"settings_use_system_color_theme\">Utilizar colores del sistema</string>\n    <string name=\"kpm_control_dialog_title\">Control de KPModule</string>\n    <string name=\"settings_use_system_color_theme_summary\">Utiliza un esquema de colores generado por el sistema basado en el fondo de pantalla actual</string>\n    <string name=\"settings_custom_color_theme\">Esquema de colores</string>\n    <string name=\"deep_orange_theme\">Naranja oscuro</string>\n    <string name=\"deep_purple_theme\">Morado oscuro</string>\n    <string name=\"green_theme\">Verde</string>\n    <string name=\"indigo_theme\">Índigo</string>\n    <string name=\"light_blue_theme\">Azul claro</string>\n    <string name=\"light_green_theme\">Verde claro</string>\n    <string name=\"lime_theme\">Lima</string>\n    <string name=\"orange_theme\">Naranja</string>\n    <string name=\"pink_theme\">Rosa</string>\n    <string name=\"purple_theme\">Púrpura</string>\n    <string name=\"red_theme\">Rojo</string>\n    <string name=\"sakura_theme\">Flor de cerezo</string>\n    <string name=\"teal_theme\">Verde azulado</string>\n    <string name=\"yellow_theme\">Amarillo</string>\n    <string name=\"about_app_version\">Versión %1$s</string>\n    <string name=\"about_powered_by\">Funciona con %1$s</string>\n    <string name=\"kpm_control_ok\">¡Operación realizada!</string>\n    <string name=\"settings_night_mode_follow_sys\">Seguir el tema oscuro del sistema</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Cambia automáticamente al tema oscuro en función de los ajustes del sistema</string>\n    <string name=\"settings_night_theme_enabled\">Utilizar tema oscuro</string>\n    <string name=\"kpm_control_dialog_content\">Escribe los parámetros de control:</string>\n    <string name=\"kpm_control_failed\">¡La operación ha fallado!</string>\n    <string name=\"amber_theme\">Ámbar</string>\n    <string name=\"blue_grey_theme\">Gris azulado</string>\n    <string name=\"kpm_control_outMsg\">Mensaje</string>\n    <string name=\"blue_theme\">Azul</string>\n    <string name=\"brown_theme\">Marrón</string>\n    <string name=\"cyan_theme\">Cian</string>\n    <string name=\"about_app_desc\">Solución «root» dentro del propio «kernel» (o núcleo de Linux) que funciona sin la necesidad de tener el código fuente original del kernel de tu dispositivo, o de tener que recompilarlo. Permite montar módulos del sistema y sustituir funciones del kernel.</string>\n    <string name=\"about_telegram_channel\">Canal de Telegram</string>\n    <string name=\"about_telegram_group\">Grupo de Telegram</string>\n    <string name=\"kpm_control\">Control</string>\n    <string name=\"kpm_control_paramters\">Parámetros</string>\n    <string name=\"save_log\">Guardar registro de fallos</string>\n    <string name=\"apm_action\">Acción</string>\n    <string name=\"log_saved\">Registros guardados</string>\n    <string name=\"crash_handle_copy\">Copiar registro de fallos</string>\n    <string name=\"crash_handle_title\">La aplicación ha fallado…</string>\n    <string name=\"crash_handle_copied\">Se copió el registro de fallos al portapapeles.</string>\n    <string name=\"settings_lite_mode\">Activar el modo ligero</string>\n    <string name=\"settings_lite_mode_mode_summary\">Puede que no todas las funciones de los APModules funcionen en este modo, pero se evitan posibles detecciones. Es necesario reiniciar para que surta efecto.</string>\n    <string name=\"settings_force_overlayfs_mode\">Forzar el uso de OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Si el kernel lo admite, se utilizará OverlayFS para montar las carpetas de los APModules en vez de Magic Mount. Es necesario reiniciar para que surta efecto.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-fa/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"home\">خانه</string>\n    <string name=\"success\">موفق</string>\n    <string name=\"failure\">ناموفق</string>\n    <string name=\"reboot_recovery\">راه اندازی به ریکاوری</string>\n    <string name=\"reboot_download\">راه اندازی به دانلود مود</string>\n    <string name=\"reboot_edl\">راه اندازی به EDL</string>\n    <string name=\"about\">درباره</string>\n    <string name=\"system_default\">تنظیمات پیشفرض سیستم</string>\n    <string name=\"settings_global_namespace_mode\">حالت نام جهانی</string>\n    <string name=\"settings_clear_super_key_dialog\">آیا واقعا میخواهید ادامه دهید؟</string>\n    <string name=\"settings_check_update\">برسی نسخه به روز</string>\n    <string name=\"home_click_to_learn_apatch\">با ویژگی های APatch و نحو استفاده آن آشنا شوید</string>\n    <string name=\"home_learn_apatch\">با APatch آشنا شو</string>\n    <string name=\"send_log\">ارسال گزارشات</string>\n    <string name=\"save_log\">ذخیره گزارشات</string>\n    <string name=\"safe_mode\">حالت امن</string>\n    <string name=\"super_key\">ابر کلید</string>\n    <string name=\"patch_warnning\">نصب با خطر همراه است! لطفاً مطمئن شوید که از اطلاعات شما نسخه پشتیبان تهیه شده است.</string>\n    <string name=\"settings_app_language\">زبان</string>\n    <string name=\"reboot\">راه اندازی مجدد</string>\n    <string name=\"settings\">تنظیمات</string>\n    <string name=\"patch\">پچ</string>\n    <string name=\"kernel_patch\">پچ کردن کرنل</string>\n    <string name=\"reboot_bootloader\">راه اندازی به بوتلودر</string>\n    <string name=\"android_patch\">پچ کردن اندروید</string>\n    <string name=\"settings_check_update_summary\">هنگام باز کردن برنامه، به طور خودکار نسخه به روز را برسی کن</string>\n    <string name=\"home_not_installed\">نصب نشده</string>\n    <string name=\"home_need_update\">نسخه جدید موجود است</string>\n    <string name=\"log_saved\">گزارشات ذخیره شد</string>\n    <string name=\"home_ap_cando_reboot\">راه اندازی مجدد</string>\n    <string name=\"patch_item_kernel\">هسته</string>\n    <string name=\"home_kernel\">هسته</string>\n    <string name=\"home_kpatch_info_title\">درباره</string>\n    <string name=\"home_ap_cando_install\">نصب</string>\n    <string name=\"home_ap_cando_uninstall\">لغو نصب</string>\n    <string name=\"patch_title\">پچ</string>\n    <string name=\"patch_start_patch_btn\">آغاز</string>\n    <string name=\"patch_item_kpimg_version\">نسخه:</string>\n    <string name=\"patch_item_kpimg_comile_time\">مدت‌زمان:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">شرح:</string>\n    <string name=\"home_fingerprint\">اثر انگشت</string>\n    <string name=\"home_selinux_status_disabled\">غیرفعال</string>\n    <string name=\"home_selinux_status_enforcing\">اجرا کردن</string>\n    <string name=\"home_selinux_status_permissive\">مجاز</string>\n    <string name=\"home_selinux_status_unknown\">ناشناخته</string>\n    <string name=\"home_device_info\">دستگاه</string>\n    <string name=\"home_system_version\">نسخه سیستم</string>\n    <string name=\"patch_item_extra_name\">نام:</string>\n    <string name=\"patch_item_extra_version\">نسخه:</string>\n    <string name=\"patch_item_extra_author\">نویسنده:</string>\n    <string name=\"home_auth_key_title\">واردکردن ابر کلید</string>\n    <string name=\"apatch_version_update\">نسخه: %s -&gt; %s</string>\n    <string name=\"home_install_unknown_summary\">برای نصب کلیک کنید</string>\n    <string name=\"home_click_to_install\">برای نصب کلیک کنید</string>\n    <string name=\"home_working\">در‌حال‌کار 😋</string>\n    <string name=\"home_installing\">نصب کردن</string>\n    <string name=\"kpatch_version\">نسخه: %s</string>\n    <string name=\"apatch_version\">نسخه: %s</string>\n    <string name=\"kpatch_version_update\">نسخه: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">پچk</string>\n    <string name=\"home_ap_cando_update\">به روز رسانی</string>\n    <string name=\"patch_config_title\">پچ ها</string>\n    <string name=\"patch_mode_bootimg_patch\">حالت: پچ</string>\n    <string name=\"patch_start_unpatch_btn\">لغو پچ</string>\n    <string name=\"patch_item_bootimg\">ایمیج بوت</string>\n    <string name=\"patch_item_kpimg\">ایمیج هسته</string>\n    <string name=\"patch_item_kpimg_config\">پیکربندی:</string>\n    <string name=\"patch_item_new_extra_kpm\">جاسازی جدید</string>\n    <string name=\"patch_item_extra_args\">دستورات:</string>\n    <string name=\"patch_item_skey\">ابر کلید</string>\n    <string name=\"settings_global_namespace_mode_summary\">همه جلسات ریشه از فضای نام نصب جهانی استفاده می کنند</string>\n    <string name=\"about_source_code\"><![CDATA[<p>مشاهده کد منبع در %1$s<p/>به کانال %2$s ما بپیوندید<p/>به گروه %3$s ما بپیوندید]]></string>\n    <string name=\"clear_super_key\">حذف ابر کلید</string>\n    <string name=\"patch_set_superkey\">تنظیم ابر کلید</string>\n    <string name=\"patch_embed_kpm_btn\">قراردادن KPM</string>\n    <string name=\"patch_mode_install_to_next_slot\">حالت: نصب در اسلات بعدی (بعد از OTA)</string>\n    <string name=\"patch_mode_uninstall_patch\">حالت: حذف نصب KPatch</string>\n    <string name=\"patch_select_bootimg_btn\">انتخاب بوت</string>\n    <string name=\"patch_item_extra_kpm_license\">مجوز:</string>\n    <string name=\"home_manager_version\">مدیر نسخه</string>\n    <string name=\"home_install_unknown\">نصب نشده یا معتبر</string>\n    <string name=\"home_patch_set_key_desc\">فقط اعتبار برای KernelPatch</string>\n    <string name=\"home_auth_key_desc\">شروع بعد از صدور گواهینامه</string>\n    <string name=\"home_patch_next_step\">گام بعد</string>\n    <string name=\"patch_item_error\">!!! اوه!!!</string>\n    <string name=\"patch_item_bootimg_slot\">اسلات:</string>\n    <string name=\"patch_item_bootimg_dev\">دستگاه:</string>\n    <string name=\"patch_item_existed_extra_kpm\">موجود</string>\n    <string name=\"patch_item_extra_event\">رویداد:</string>\n    <string name=\"patch_item_set_skey_label\">طول ابر کلید باید 8تا36 کاراکتر باشد و شامل عدد و حروف بدون کاراکتر های خاص باشد.</string>\n    <string name=\"home_selinux_status\">وضعیت SELinux</string>\n    <string name=\"patch_mode_patch_and_install\">حالت: پچ و نصب</string>\n    <string name=\"kpm_args\">دستورات</string>\n    <string name=\"su_title\">ابر کاربر</string>\n    <string name=\"home_su_path\">ابر کلید اجرایی</string>\n    <string name=\"home_kpatch_version\">نسخه پچ هسته</string>\n    <string name=\"kpm_load\">بارگذاری</string>\n    <string name=\"kpm\">ماژول KP</string>\n    <string name=\"kpm_kp_not_installed\">وصله هسته نصب نشده است</string>\n    <string name=\"kpm_embed\">جاسازی</string>\n    <string name=\"kpm_load_toast_succ\">با موفقیت بارگذاری شد</string>\n    <string name=\"kpm_load_toast_failed\">بارگذاری نا موفق بود</string>\n    <string name=\"kpm_unload_confirm\">بارگذاری ماژول \\\"%s\\\" لغو‌شود؟</string>\n    <string name=\"kpm_unload\">لغو‌بارگذاری</string>\n    <string name=\"kpm_control\">کنترل</string>\n    <string name=\"kpm_desc\">شرح</string>\n    <string name=\"su_selinux_via_hook\">دور زدن از طریق قلاب</string>\n    <string name=\"su_pkg_excluded_setting_title\">تغییرات صرف نظر شده</string>\n    <string name=\"su_pkg_excluded_setting_summary\">فعال کردن این گزینه به APatch اجازه خواهد داد تا فایل‌های تغییر یافته توسط ماژول‌های این برنامه را بازیابی کند.</string>\n    <string name=\"su_hide_system_apps\">مخفی کردن برنامه‌های سیستمی</string>\n    <string name=\"home_apatch_version\">نسخه APatch</string>\n    <string name=\"kpm_add_kpm\">اضافه کردن KPM</string>\n    <string name=\"kpm_apm_empty\">هیچ ماژول بارگیری نشده</string>\n    <string name=\"kpm_install\">نصب</string>\n    <string name=\"kpm_version\">نسخه</string>\n    <string name=\"kpm_license\">پروانه</string>\n    <string name=\"kpm_author\">مالک</string>\n    <string name=\"su_pkg_excluded_label\">مستثنی</string>\n    <string name=\"su_show_system_apps\">نمایش برنامه‌های سیستمی</string>\n    <string name=\"su_refresh\">تازه سازی</string>\n    <string name=\"apm\">ماژول AP</string>\n    <string name=\"apm_not_installed\">AndroidPatch نصب نشده</string>\n    <string name=\"apm_failed_to_enable\">فعالسازی ماژول \\\"%s\\\" ناموفق بود</string>\n    <string name=\"enable_web_debugging\">فعالسازی اشکال زدایی نمای وب</string>\n    <string name=\"enable_web_debugging_summary\">می تواند برای اشکال زدایی رابط کاربری وب استفاده شود. لطفا فقط وقتی لازم است فعال کنید.</string>\n    <string name=\"settings_donot_store_superkey_summary\">اعتبار سنجی ابر کلید با هر بار شروع مدیر</string>\n    <string name=\"mode_select_page_patch_and_install\">وصله و نصب</string>\n    <string name=\"cyan_theme\">فیروزه ای</string>\n    <string name=\"deep_orange_theme\">نارنجی تیره</string>\n    <string name=\"deep_purple_theme\">بنفش تیره</string>\n    <string name=\"green_theme\">سبز</string>\n    <string name=\"indigo_theme\">نیلی سیر</string>\n    <string name=\"light_blue_theme\">آبی روشن</string>\n    <string name=\"purple_theme\">بنفش</string>\n    <string name=\"red_theme\">قرمز</string>\n    <string name=\"sakura_theme\">شکوفه گیلاس</string>\n    <string name=\"teal_theme\">سبز دودی</string>\n    <string name=\"yellow_theme\">زرد</string>\n    <string name=\"about_telegram_group\">گروه تلگرام</string>\n    <string name=\"crash_handle_title\">برنامه کرش کرد…</string>\n    <string name=\"crash_handle_copied\">گزارش کرش به کلیپ بورد کپی شد.</string>\n    <string name=\"apm_author\">نویسنده</string>\n    <string name=\"apm_desc\">توضیحات</string>\n    <string name=\"mode_select_page_install_inactive_slot\">نصب در یک اسلات غیرفعال (بعد از OTA)</string>\n    <string name=\"home_dialog_auth_fail_title\">اعتبار سنجی نا موفق بود</string>\n    <string name=\"home_dialog_uninstall_title\">حذف نصب</string>\n    <string name=\"home_dialog_uninstall_ap_only\">حذف AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">حذف نصب همه</string>\n    <string name=\"kpm_control_dialog_content\">پارامتر های کنترل ورودی:</string>\n    <string name=\"settings_night_mode_follow_sys\">پیروی از تم تاریک سیستم</string>\n    <string name=\"about_telegram_channel\">کانال تلگرام</string>\n    <string name=\"crash_handle_copy\">کپی کردن گزارش کرش</string>\n    <string name=\"apm_failed_to_disable\">غیرفعالسازی ماژول \\\"%s\\\" ناموفق بود</string>\n    <string name=\"apm_empty\">ماژولی نصب نشده است</string>\n    <string name=\"apm_install\">نصب</string>\n    <string name=\"apm_uninstall_confirm\">ماژول \\\"%s\\\" حذف نصب شود؟</string>\n    <string name=\"apm_uninstall_success\">\\\"%s\\\" حذف نصب شد</string>\n    <string name=\"apm_remove\">حذف</string>\n    <string name=\"apm_uninstall_failed\">حذف نصب \\\"%s\\\" ناموفق بود</string>\n    <string name=\"apm_magisk_conflict\">ماژول ها به علت درگیری با Msgisk در دسترس نیستند!</string>\n    <string name=\"apm_changelog\">گزارش تغییرات</string>\n    <string name=\"apm_update\">بروزرسانی</string>\n    <string name=\"apm_downloading\">بارگیری ماژول \\\"%s\\\" …</string>\n    <string name=\"apm_new_version_available\">نسخه جدید %s در دسترس است، برای بروزرسانی کلیک کنید.</string>\n    <string name=\"hide_apatch_manager\">مخفی کردن مدیر APatch</string>\n    <string name=\"apm_reboot_to_apply\">برای اعمال مجددا راه اندازی کنید</string>\n    <string name=\"hide_apatch_manager_summary\">نصب یک برنامه مدیریت با یک شناسه تصادفی و برچسب سفارشی</string>\n    <string name=\"hide_apatch_manager_failure\">پنهان کردن ناموفق بود. لطفا ایراد را گزارش کنید!</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">نام مدیر جدید</string>\n    <string name=\"hide_apatch_dialog_summary\">به عنوان برچسب جدید برنامه برای نمایش در لانچر استفاده خواهد شد</string>\n    <string name=\"setting_reset_su_path\">تنظیم مجدد مسیر su</string>\n    <string name=\"apm_webui_open\">باز کردن</string>\n    <string name=\"apm_action\">اجرا</string>\n    <string name=\"mode_select_page_select_file\">یک نمونه بوت را برای وصله کردن انتخاب کنید</string>\n    <string name=\"home_new_apatch_found\">نسخه جدید %s در دسترس است، برای بروزرسانی کلیک کنید.</string>\n    <string name=\"home_more_menu_about\">درباره</string>\n    <string name=\"kpm_control_paramters\">پارامتر ها</string>\n    <string name=\"kpm_control_ok\">عملیات موفق بود!</string>\n    <string name=\"kpm_control_failed\">عملیات ناموفق بود!</string>\n    <string name=\"settings_night_theme_enabled\">فعالسازی تم تاریک</string>\n    <string name=\"settings_custom_color_theme\">تم رنگی</string>\n    <string name=\"amber_theme\">کهربایی</string>\n    <string name=\"blue_grey_theme\">آبی-خاکستری</string>\n    <string name=\"brown_theme\">قهوه ای</string>\n    <string name=\"light_green_theme\">سبز روشن</string>\n    <string name=\"lime_theme\">لیمویی</string>\n    <string name=\"orange_theme\">نارنجی</string>\n    <string name=\"pink_theme\">صورتی</string>\n    <string name=\"about_app_version\">نسخه %1$s</string>\n    <string name=\"apm_overlay_fs_not_available\">ماژول ها در دسترس نیستند زیرا OverlayFS توسط هسته غیرفعال شده است!</string>\n    <string name=\"mode_select_page_title\">نصب</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">بازخورد یا پیشنهاد</string>\n    <string name=\"apm_start_downloading\">شروع بارگیری %s</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">دستگاه شما بعد از راه اندازی مجدد **مجبور خواهد شد** در اسلات غیرفعال فعلی راه اندازی شود!\\nاز این گزینه فقط بعد از اتمام OTA استفاده کنید.\\nادامه؟</string>\n    <string name=\"apm_version\">نسخه</string>\n    <string name=\"blue_theme\">آبی</string>\n    <string name=\"settings_donot_store_superkey\">ابر کلید را به صورت محلی ذخیره نکنید</string>\n    <string name=\"setting_reset_su_new_path\">مسیر کامل جدید</string>\n    <string name=\"kpm_control_outMsg\">پیام</string>\n    <string name=\"settings_use_system_color_theme\">تم رنگی سیستم</string>\n    <string name=\"kpm_control_dialog_title\">کنترل KPModule</string>\n    <string name=\"home_dialog_auth_fail_content\">اعتبار سنجی ابر کلید ناموفق بود، بنابراین APatch نمی تواند به درستی کار کند. \\nدلایل احتمالی:\\n1. شما boot.img را به KernelPatch وصله نکردید.\\n2. وصله boot.img فلش نشده است.\\n3. ابر کلید اشتباه است یا حاوی کاراکترهای خاص است.\\n4. دستگاه شما از APatch و KernelPatch پشتیبانی نمی کند.\\n\\nلطفا بررسی کنید و دوباره امتحان کنید. اگر هنوز مشکلات وجود دارند، همیشه می توانید در صفحه مسائل مخزن رسمی سؤال بپرسید..</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">جابجایی خودکار به تم تاریک بر اساس تنظیمات سیستم</string>\n    <string name=\"settings_use_system_color_theme_summary\">استفاده از تم رنگی تولید شده بر اساس تصویر زمینه فعلی سیستم</string>\n    <string name=\"about_app_desc\">راه حل روت کرنل فقط با یک ایمیج جدا از کرنل،قابلیت نصب ماژول سیستم و قلاب کردن توابع کرنل را ارئه می دهد.</string>\n    <string name=\"about_powered_by\">قدرت گرفته از %1$s</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-fi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"settings\">Asetukset</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"reboot\">\"Käynnistä uudelleen \"</string>\n    <string name=\"reboot_recovery\">Käynnistä uudelleen palautukseen</string>\n    <string name=\"reboot_bootloader\">Käynnistä uudelleen käynnistyslataimeen</string>\n    <string name=\"reboot_download\">Käynnistä uudelleen ladataksesi</string>\n    <string name=\"reboot_edl\">Käynnistä uudelleen EDL:ään</string>\n    <string name=\"settings_global_namespace_mode\">Yleisesti pätevä nimiavaruustila</string>\n    <string name=\"about\">Tietoja</string>\n    <string name=\"home\">Koti</string>\n    <string name=\"patch_warnning\">Asennukseen liittyy riskejä. Varmista, että tietosi on varmuuskopioitu.</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"failure\">Epäonnistusminen</string>\n    <string name=\"system_default\">Järjestelmä oletus</string>\n    <string name=\"settings_app_language\">Kieli</string>\n    <string name=\"patch_set_superkey\">Aseta SuperKey</string>\n    <string name=\"home_ap_cando_update\">Päivitä</string>\n    <string name=\"patch\">Korjaus</string>\n    <string name=\"patch_item_set_skey_label\">SuperKeyn tulee olla 8–63 merkkiä pitkä ja sisältää numeroita ja kirjaimia, mutta ei erikoismerkkejä.</string>\n    <string name=\"clear_super_key\">Tyhjennä SuperKey</string>\n    <string name=\"home_device_info\">Laite</string>\n    <string name=\"patch_mode_patch_and_install\">Tila: Korjaa ja asenna</string>\n    <string name=\"apm_update\">Päivitä</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"home_su_path\">Suoritettava su</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Kuvaus:</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"success\">Menestys</string>\n    <string name=\"settings_global_namespace_mode_summary\">Kaikki juuriistunnot käyttävät yleisesti pätevää liitosnimiavaruutta</string>\n    <string name=\"settings_clear_super_key_dialog\">Haluatko todella edetä?</string>\n    <string name=\"settings_check_update\">Tarkista päivityksen varalta</string>\n    <string name=\"settings_check_update_summary\">Tarkista päivitysten varalta automaattisesti sovelluksen avaamisen yhteydessä</string>\n    <string name=\"home_learn_apatch\">Opettele APatch</string>\n    <string name=\"home_click_to_learn_apatch\">Tutustu APatchin ominaisuuksiin ja sen käyttöön</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Tarkastele lähdekoodia %1$s<p/>Liity %2$s-kanavallemme<p/>Liity %3$s-ryhmäämme]]>:ssa</string>\n    <string name=\"send_log\">Lähetä lokit</string>\n    <string name=\"save_log\">Tallenna lokit</string>\n    <string name=\"log_saved\">Lokit tallennettu</string>\n    <string name=\"safe_mode\">Vikasietotila</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"home_patch_set_key_desc\">Vain valtuustieto KernelPatchille</string>\n    <string name=\"home_patch_next_step\">Seuraava vaihe</string>\n    <string name=\"home_not_installed\">Ei asennettu</string>\n    <string name=\"home_install_unknown\">Ei asennettu tai todennettu</string>\n    <string name=\"home_install_unknown_summary\">Napauta asentaaksesi</string>\n    <string name=\"home_click_to_install\">Napauta asentaaksesi</string>\n    <string name=\"home_working\">Toimii 😋</string>\n    <string name=\"home_installing\">Asentaminen</string>\n    <string name=\"home_need_update\">Uusi versio saatavilla</string>\n    <string name=\"kpatch_version\">Versio: %s</string>\n    <string name=\"apatch_version\">Versio: %s</string>\n    <string name=\"apatch_version_update\">Versio: %s -&gt; %s</string>\n    <string name=\"kpatch_version_update\">Versio: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_auth_key_title\">Syötä SuperKey</string>\n    <string name=\"home_auth_key_desc\">Käynnistä sertifioinnin jälkeen</string>\n    <string name=\"home_kpatch_info_title\">Tiedot</string>\n    <string name=\"home_ap_cando_install\">Asenna</string>\n    <string name=\"home_ap_cando_uninstall\">Poista asennus</string>\n    <string name=\"home_ap_cando_reboot\">Käynnistä uudelleen</string>\n    <string name=\"patch_config_title\">Korjaukset</string>\n    <string name=\"patch_title\">Korjaus</string>\n    <string name=\"patch_mode_bootimg_patch\">Tila: Korjaus</string>\n    <string name=\"patch_mode_install_to_next_slot\">Tila: Asenna ei-aktiiviseen kiinnittimeen (OTA:n jälkeen)</string>\n    <string name=\"patch_mode_uninstall_patch\">Tila: Poista KPatchin asennus</string>\n    <string name=\"patch_select_bootimg_btn\">Valitse käynnistys</string>\n    <string name=\"patch_embed_kpm_btn\">Upota KPM</string>\n    <string name=\"patch_start_patch_btn\">Käynnistä</string>\n    <string name=\"patch_start_unpatch_btn\">Kumoa korjaus</string>\n    <string name=\"patch_item_error\">!!VIRHE!!</string>\n    <string name=\"patch_item_bootimg\">käynnistys</string>\n    <string name=\"patch_item_bootimg_slot\">kiinnitin:</string>\n    <string name=\"patch_item_bootimg_dev\">laite:</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Versio:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Aika:</string>\n    <string name=\"patch_item_kpimg_config\">Kokoonpano:</string>\n    <string name=\"patch_item_new_extra_kpm\">Upota uusi</string>\n    <string name=\"patch_item_existed_extra_kpm\">Olemassa</string>\n    <string name=\"patch_item_extra_name\">Nimi:</string>\n    <string name=\"patch_item_extra_version\">Versio:</string>\n    <string name=\"patch_item_extra_author\">Tekijä:</string>\n    <string name=\"patch_item_extra_kpm_license\">Lisenssi:</string>\n    <string name=\"patch_item_extra_args\">Args:</string>\n    <string name=\"patch_item_extra_event\">Tapahtuma:</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"home_kernel\">Kernel</string>\n    <string name=\"home_manager_version\">Hallintaversio</string>\n    <string name=\"home_fingerprint\">Sormenjälki</string>\n    <string name=\"home_selinux_status\">SELinuxin tila</string>\n    <string name=\"home_selinux_status_disabled\">Poistettu käytöstä</string>\n    <string name=\"home_selinux_status_enforcing\">Täytäntöönpano</string>\n    <string name=\"home_selinux_status_permissive\">Salliva</string>\n    <string name=\"home_selinux_status_unknown\">Tuntematon</string>\n    <string name=\"home_system_version\">Järjestelmäversio</string>\n    <string name=\"kpm_install\">Asenna</string>\n    <string name=\"kpm_embed\">Upota</string>\n    <string name=\"home_kpatch_version\">KernelPatch-versio</string>\n    <string name=\"home_apatch_version\">APatch-versio</string>\n    <string name=\"kpm_load_toast_succ\">Lataus onnistuu</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch ei asennettu</string>\n    <string name=\"kpm_add_kpm\">Lisää KPM</string>\n    <string name=\"kpm_load\">Lataa</string>\n    <string name=\"kpm_load_toast_failed\">Lataus epäonnistui</string>\n    <string name=\"kpm_unload_confirm\">Kumotaanko \\\"%s\\\"-moduulin lataus?</string>\n    <string name=\"kpm_unload\">Kumoa lataus</string>\n    <string name=\"kpm_control\">Hallinta</string>\n    <string name=\"kpm_apm_empty\">Ei ladattu moduulia</string>\n    <string name=\"kpm_version\">Versio</string>\n    <string name=\"kpm_license\">Lisenssi</string>\n    <string name=\"kpm_author\">Tekijä</string>\n    <string name=\"kpm_desc\">Kuvaus</string>\n    <string name=\"apm_desc\">Kuvaus</string>\n    <string name=\"apm_downloading\">Ladataan \\\"%s\\\" -moduulia…</string>\n    <string name=\"kpm_args\">Args</string>\n    <string name=\"hide_apatch_manager_summary\">Asenna uusi hallintasovellus satunnaisen tunnuksen ja mukautetun nimikkeen kanssa</string>\n    <string name=\"enable_web_debugging\">Ota WebView-viankorjaus käyttöön</string>\n    <string name=\"settings_donot_store_superkey_summary\">Todenna SuperKey aina, kun hallinta käynnistyy</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Laitteesi **pakottaa** käynnistymään nykyiseen ei-aktiiviseen kiinnittimeen uudelleenkäynnistyksen jälkeen!\\nKäytä tätä vaihtoehtoa vasta OTA:n jälkeen.\\nJatketaanko?</string>\n    <string name=\"kpm_control_outMsg\">Viesti</string>\n    <string name=\"home_dialog_auth_fail_content\">SuperKeyä ei voi todentaa, joten APatch ei voi toimia kunnolla.\\nTässä on joitain mahdollisia syitä todennuksen epäonnistumiseen:\\n1. Et korjannut boot.img:ia KernelPatchilla.\\n2. Korjattuun boot.img:iin flash-toimintaa ei ole sovellettu.\\n3. SuperKey on väärä tai sisältää erikoismerkkejä.\\n4. Laitteesi ei tue APatchia ja KernelPatchia.\\n\\nTarkista ja yritä uudelleen. Jos ongelmia ilmenee edelleen, voit aina esittää kysymyksiä virallisen tietovaraston ongelmasivulla.</string>\n    <string name=\"about_app_desc\">Kernel-juuriratkaisu, jossa on vain poistettu ytimen kuva, joka tarjoaa mahdollisuuden asentaa järjestelmämoduulia ja kiinnittää kernel-toiminnon.</string>\n    <string name=\"kpm_control_ok\">Toiminta onnistui!</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Vaihda automaattisesti tummaan teemaan järjestelmäasetusten mukaan</string>\n    <string name=\"purple_theme\">Violetti</string>\n    <string name=\"su_title\">Superkäyttäjä</string>\n    <string name=\"su_selinux_via_hook\">ohita koukun kautta</string>\n    <string name=\"su_pkg_excluded_label\">sulje pois</string>\n    <string name=\"su_pkg_excluded_setting_title\">Sulje pois muutokset</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Tämän vaihtoehdon ottaminen käyttöön antaa APatchille mahdollisuuden palauttaa kaikki tämän sovelluksen moduulien muokkaamat tiedostot.</string>\n    <string name=\"su_show_system_apps\">Näytä järjestelmäsovellukset</string>\n    <string name=\"su_hide_system_apps\">Piilota järjestelmäsovellukset</string>\n    <string name=\"su_refresh\">Virkistä</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"apm_not_installed\">AndroidPatch ei asennettu</string>\n    <string name=\"apm_failed_to_disable\">Moduulia \\\"%s\\\" ei voitu kytkeä pois päältä</string>\n    <string name=\"apm_failed_to_enable\">Moduulia \\\"%s\\\" ei voitu kytkeä päälle</string>\n    <string name=\"apm_empty\">Ei moduulia asennettu</string>\n    <string name=\"apm_remove\">Poista</string>\n    <string name=\"apm_install\">Asenna</string>\n    <string name=\"apm_uninstall_confirm\">Poistetaanko \\\"%s\\\"-moduulin asennus?</string>\n    <string name=\"apm_uninstall_success\">%s:n asennus poistettu</string>\n    <string name=\"apm_uninstall_failed\">%s:n asennusta ei voitu poistaa</string>\n    <string name=\"apm_version\">Versio</string>\n    <string name=\"apm_author\">Tekijä</string>\n    <string name=\"apm_overlay_fs_not_available\">Moduulit eivät ole saatavilla, koska Kernel on poistanut OverlayFS:n käytöstä!</string>\n    <string name=\"apm_magisk_conflict\">Moduuleja ei ole saatavilla ristiriidan vuoksi Magiskin kanssa!</string>\n    <string name=\"apm_reboot_to_apply\">Käynnistä uudelleen, jotta se tulee voimaan</string>\n    <string name=\"apm_changelog\">Muutosloki</string>\n    <string name=\"apm_start_downloading\">Aloita %s:n lataaminen</string>\n    <string name=\"apm_new_version_available\">Uusi versio %s on saatavilla, päivitä napsauttamalla.</string>\n    <string name=\"hide_apatch_manager\">Piilota APatch-hallinta</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Uusi hallinnan nimi</string>\n    <string name=\"hide_apatch_dialog_summary\">Sitä käytetään käynnistysohjelmassa uutena näkyvänä sovelluksen nimikkeenä</string>\n    <string name=\"hide_apatch_manager_failure\">Piilottaminen epäonnistui. Ilmoita viasta!</string>\n    <string name=\"setting_reset_su_path\">Nollaa superkäyttäjäpolku</string>\n    <string name=\"setting_reset_su_new_path\">Uusi täydellinen polku</string>\n    <string name=\"apm_webui_open\">Avaa</string>\n    <string name=\"apm_action\">Toiminta</string>\n    <string name=\"enable_web_debugging_summary\">Voidaan käyttää WebUI-viankorjaukseen. Ota käyttöön vain tarvittaessa.</string>\n    <string name=\"settings_donot_store_superkey\">Älä säilytä SuperKeyä paikallisesti</string>\n    <string name=\"home_new_apatch_found\">Uusi versio %s on saatavilla, päivitä napsauttamalla.</string>\n    <string name=\"mode_select_page_title\">Asenna</string>\n    <string name=\"mode_select_page_patch_and_install\">Korjaa ja asenna</string>\n    <string name=\"mode_select_page_select_file\">Valitse korjattava käynnistyskuva</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Asenna ei-aktiiviseen kiinnittimeen (OTA:n jälkeen)</string>\n    <string name=\"home_dialog_auth_fail_title\">Todennus epäonnistui</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Palaute tai ehdotus</string>\n    <string name=\"home_more_menu_about\">Tietoja</string>\n    <string name=\"home_dialog_uninstall_title\">Poista asennus</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Poista AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Poista koko asennus</string>\n    <string name=\"kpm_control_dialog_title\">Hallinnoi KPModulea</string>\n    <string name=\"kpm_control_dialog_content\">Syötön hallintaparametrit:</string>\n    <string name=\"kpm_control_paramters\">Parametrit</string>\n    <string name=\"kpm_control_failed\">Toiminta epäonnistui!</string>\n    <string name=\"settings_night_mode_follow_sys\">Seuraa järjestelmän tummaa teemaa</string>\n    <string name=\"settings_night_theme_enabled\">Ota tumma teema käyttöön</string>\n    <string name=\"settings_use_system_color_theme\">Järjestelmän väriteema</string>\n    <string name=\"settings_use_system_color_theme_summary\">Käytä järjestelmän luomaa väriteemaa nykyisen taustakuvan mukaan</string>\n    <string name=\"settings_custom_color_theme\">Väriteema:</string>\n    <string name=\"amber_theme\">Meripihka</string>\n    <string name=\"blue_grey_theme\">Siniharmaa</string>\n    <string name=\"blue_theme\">Sininen</string>\n    <string name=\"brown_theme\">Ruskea</string>\n    <string name=\"cyan_theme\">Syaani</string>\n    <string name=\"deep_orange_theme\">Syvä oranssi</string>\n    <string name=\"deep_purple_theme\">Syvä purppura</string>\n    <string name=\"green_theme\">Vihreä</string>\n    <string name=\"indigo_theme\">Indigo</string>\n    <string name=\"light_blue_theme\">Vaaleansininen</string>\n    <string name=\"light_green_theme\">Vaaleanvihreä</string>\n    <string name=\"lime_theme\">Lime</string>\n    <string name=\"orange_theme\">Oranssi</string>\n    <string name=\"pink_theme\">Vaaleanpunainen</string>\n    <string name=\"red_theme\">Punainen</string>\n    <string name=\"sakura_theme\">Sakura</string>\n    <string name=\"teal_theme\">Sinivihreä</string>\n    <string name=\"yellow_theme\">Keltainen</string>\n    <string name=\"about_app_version\">Versio %1$s</string>\n    <string name=\"about_telegram_channel\">Telegram-kanava</string>\n    <string name=\"about_telegram_group\">Telegram-ryhmä</string>\n    <string name=\"about_powered_by\">Voimanlähteenä %1$s</string>\n    <string name=\"crash_handle_title\">Sovellus kaatui…</string>\n    <string name=\"crash_handle_copy\">Kopioi kaatumisloki</string>\n    <string name=\"crash_handle_copied\">Kaatumisloki kopioittu leikepöydälle.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"patch_warnning\">Ang instalasyon na ito ay pwede ikaka-sira ng inyong kagamitan, tiyakin muna kung ang iyong data ay naka-backup.</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"reboot\">Reboot</string>\n    <string name=\"settings\">Mga settings</string>\n    <string name=\"send_log\">Send Log</string>\n    <string name=\"home_patch_set_key_desc\">Kredensiyal para sa KernelPatch</string>\n    <string name=\"home_install_unknown\">Hindi alam</string>\n    <string name=\"home_click_to_learn_apatch\">Alamin ang mga features ng AndroidPatch at kung paano ito gamitin</string>\n    <string name=\"home_installing\">Installing</string>\n    <string name=\"home_learn_apatch\">Alamin ang AndroidPatch</string>\n    <string name=\"home_click_to_install\">I-click para mag install</string>\n    <string name=\"patch_set_superkey\">I-set ang SuperKey</string>\n    <string name=\"home_working\">Gumagana</string>\n    <string name=\"home_not_installed\">Hindi naka-installed</string>\n    <string name=\"home_need_update\">May update</string>\n    <string name=\"home_patch_next_step\">Susunod na hakbang</string>\n    <string name=\"home_auth_key_desc\">Magsimula ng trabaho pagkatapos ng sertipikasyon</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"home_apatch_version\">APatch: %s</string>\n    <string name=\"home_su_path\">su: %s</string>\n    <string name=\"home_auth_key_title\">Ilagay ang superkey</string>\n    <string name=\"home_ap_cando_install\">I-install</string>\n    <string name=\"home_ap_cando_update\">I-update</string>\n    <string name=\"kpm_unload_confirm\">Sigurado ka bang nais mong i-unload ang module %s?</string>\n    <string name=\"kpm_kp_not_installed\">Hindi naka install ang Kernel Patch</string>\n    <string name=\"kpm_desc\">Desc</string>\n    <string name=\"home_ap_cando_uninstall\">I-uninstall</string>\n    <string name=\"kpm_args\">Args</string>\n    <string name=\"home_fingerprint\">Fingerprint</string>\n    <string name=\"safe_mode\">Safe na mode</string>\n    <string name=\"home_selinux_status_unknown\">Hindi alam</string>\n    <string name=\"home_selinux_status_permissive\">Pamahinang (Permissive)</string>\n    <string name=\"home_selinux_status\">SELinux status</string>\n    <string name=\"kpm_load_toast_failed\">Nabigo ang pag-load</string>\n    <string name=\"kpm_unload\">I-unload</string>\n    <string name=\"home_kernel\">Kernel</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"home_selinux_status_enforcing\">Pinapatupad (Enforcing)</string>\n    <string name=\"kpm_apm_empty\">Walang naka-load na module</string>\n    <string name=\"home_manager_version\">Bersyon ng Manager</string>\n    <string name=\"kpm_load_toast_succ\">Tagumpay ang pag-load</string>\n    <string name=\"patch_title\">Patch</string>\n    <string name=\"kpm_author\">May-akda</string>\n    <string name=\"home_selinux_status_disabled\">Hindi pinagana</string>\n    <string name=\"kpm_license\">Lisensiya</string>\n    <string name=\"apm_install\">I-install</string>\n    <string name=\"apm_remove\">I-uninstall</string>\n    <string name=\"apm_uninstall_confirm\">Sigurado ka bang gusto mong i-uninstall ang module %s?</string>\n    <string name=\"su_pkg_excluded_setting_title\">I-exclude</string>\n    <string name=\"su_pkg_excluded_setting_summary\">para sa mga modules</string>\n    <string name=\"su_pkg_excluded_label\">exclude</string>\n    <string name=\"su_title\">Superuser</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"su_selinux_via_hook\">bypass via hook</string>\n    <string name=\"su_refresh\">I-refresh</string>\n    <string name=\"su_show_system_apps\">Ipakita ang mga system apps</string>\n    <string name=\"apm_failed_to_disable\">Hindi tagumpay ang pagpapatigil ng module: %s</string>\n    <string name=\"apm_failed_to_enable\">Hindi tagumpay ang pagpapagana ng module: %s</string>\n    <string name=\"su_hide_system_apps\">Itago ang mga system apps</string>\n    <string name=\"apm_empty\">Walang naka-install na module</string>\n    <string name=\"kpm_load\">Mag Load</string>\n    <string name=\"apm_reboot_to_apply\">Mag restart para magkaruon ng epekto</string>\n    <string name=\"apm_overlay_fs_not_available\">walang overlayfs, hindi maaaring gumana ang module!</string>\n    <string name=\"apm_uninstall_failed\">Hindi tagumpay ang pag-uninstall ng: %s</string>\n    <string name=\"apm_desc\">Desc</string>\n    <string name=\"apm_author\">May-akda</string>\n    <string name=\"apm_version\">Bersyon</string>\n    <string name=\"kpm_version\">Bersyon</string>\n    <string name=\"apm_changelog\">Mga Pagbabago</string>\n    <string name=\"apm_update\">I-update</string>\n    <string name=\"apm_start_downloading\">Simulan ang pag-download ng: %s</string>\n    <string name=\"apm_downloading\">Ini-download ang module: %s</string>\n    <string name=\"apm_new_version_available\">Bagong bersyon: %s ay available, i-click para i-upgrade</string>\n    <string name=\"home\">Tahanan</string>\n    <string name=\"patch\">Mga patch</string>\n    <string name=\"reboot_recovery\">I-reboot sa Recovery</string>\n    <string name=\"reboot_bootloader\">I-reboot sa Bootloader</string>\n    <string name=\"reboot_download\">I-reboot sa Download</string>\n    <string name=\"reboot_edl\">I-reboot sa EDL</string>\n    <string name=\"about\">Tungkol nito</string>\n    <string name=\"settings_app_language\">Wika</string>\n    <string name=\"system_default\">Default ng system</string>\n    <string name=\"settings_global_namespace_mode\">Pandaigdigang Namespace Mode</string>\n    <string name=\"settings_global_namespace_mode_summary\">Ginagamit ng lahat ng root session ang pandaigdigang mount namespace</string>\n    <string name=\"settings_clear_super_key_dialog\">Gusto mo ba talagang magpatuloy?</string>\n    <string name=\"success\">Matagumpay</string>\n    <string name=\"failure\">Hindi matagumpay</string>\n    <string name=\"log_saved\">Na-save ang Log</string>\n    <string name=\"crash_handle_copy\">Kopyahin ang log sa pag-crash</string>\n    <string name=\"crash_handle_copied\">Nakopya ang log sa pag-crash sa clipboard.</string>\n    <string name=\"clear_super_key\">Alisin ang SuperKey</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot_recovery\">Redémarrer en mode récupération</string>\n    <string name=\"reboot_download\">Redémarrer en mode téléchargement</string>\n    <string name=\"reboot_edl\">Redémarrer en mode EDL</string>\n    <string name=\"about\">À propos</string>\n    <string name=\"home_learn_apatch\">En apprendre plus sur AndroidPatch</string>\n    <string name=\"home\">Accueil</string>\n    <string name=\"patch_warnning\">L\\'installation comporte des risques. Veillez à ce que vos données soient sauvegardées.</string>\n    <string name=\"settings\">Paramètres</string>\n    <string name=\"reboot_bootloader\">Redémarrage en mode bootloader</string>\n    <string name=\"reboot\">Redémarrer</string>\n    <string name=\"home_click_to_learn_apatch\">Découvrez les fonctionnalités d\\'AndroidPatch et apprenez comment l\\'utiliser</string>\n    <string name=\"safe_mode\">Mode sécurisé</string>\n    <string name=\"home_not_installed\">Non installé</string>\n    <string name=\"home_click_to_install\">Appuyer pour installer</string>\n    <string name=\"home_installing\">Installation</string>\n    <string name=\"home_need_update\">Nouvelle version disponible</string>\n    <string name=\"apatch_version\">Version : %s</string>\n    <string name=\"home_patch_next_step\">Suivant</string>\n    <string name=\"home_install_unknown\">Non installé ou authentifié</string>\n    <string name=\"kpatch_version\">Version : %s</string>\n    <string name=\"clear_super_key\">Effacer la clé</string>\n    <string name=\"home_su_path\">Exécutable su</string>\n    <string name=\"home_apatch_version\">Version d\\'APatch</string>\n    <string name=\"apatch_version_update\">Version : %s -&gt; %s</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Voir le code source sur %1$s<p/>Rejoindre notre canal %2$s<p/>Rejoindre notre groupe %3$s]]></string>\n    <string name=\"patch_set_superkey\">Initialiser la clé</string>\n    <string name=\"send_log\">Envoyer le log</string>\n    <string name=\"home_kernel\">Version du noyau</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"apm_version\">Version</string>\n    <string name=\"home_working\">Fonctionnel 😋</string>\n    <string name=\"home_patch_set_key_desc\">Authentification unique pour KernelPatch</string>\n    <string name=\"home_auth_key_title\">Renseigner la clé</string>\n    <string name=\"home_ap_cando_install\">Installer</string>\n    <string name=\"home_ap_cando_update\">Mettre à jour</string>\n    <string name=\"home_ap_cando_uninstall\">Désinstaller</string>\n    <string name=\"home_manager_version\">Version du gestionnaire</string>\n    <string name=\"home_fingerprint\">Empreinte</string>\n    <string name=\"kpm_load_toast_failed\">Chargement échoué</string>\n    <string name=\"kpm_version\">Version</string>\n    <string name=\"kpm_license\">Licence</string>\n    <string name=\"kpm_author\">Auteur</string>\n    <string name=\"kpm_desc\">Description</string>\n    <string name=\"su_title\">Super utilisateur</string>\n    <string name=\"su_pkg_excluded_label\">exclure</string>\n    <string name=\"su_show_system_apps\">Afficher les applications système</string>\n    <string name=\"su_hide_system_apps\">Masquer les applications système</string>\n    <string name=\"su_selinux_via_hook\">contournement via hook</string>\n    <string name=\"su_refresh\">Rafraîchir</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"apm_empty\">Aucun module installé</string>\n    <string name=\"apm_install\">Installer</string>\n    <string name=\"apm_uninstall_success\">%s a été désinstallé</string>\n    <string name=\"apm_author\">Auteur</string>\n    <string name=\"apm_desc\">Description</string>\n    <string name=\"apm_reboot_to_apply\">Redémarrer pour appliquer les changements</string>\n    <string name=\"apm_changelog\">Journal des modifications</string>\n    <string name=\"apm_update\">Mettre à jour</string>\n    <string name=\"apm_start_downloading\">Téléchargement de %s démarré</string>\n    <string name=\"home_selinux_status_disabled\">Inactif</string>\n    <string name=\"home_auth_key_desc\">Démarrage après certification</string>\n    <string name=\"kpm_unload_confirm\">Décharger le module \\\"%s\\\" ?</string>\n    <string name=\"apm_not_installed\">AndroidPatch n\\'est pas installé</string>\n    <string name=\"apm_failed_to_disable\">Impossible de désactiver le module \\\"%s\\\"</string>\n    <string name=\"apm_uninstall_confirm\">Désinstaller le module \\\"%s\\\" ?</string>\n    <string name=\"apm_uninstall_failed\">Impossible de désinstaller %s</string>\n    <string name=\"apm_magisk_conflict\">Les modules sont indisponibles en raison d\\'un conflit avec Magisk !</string>\n    <string name=\"apm_downloading\">Téléchargement du module \\\"%s\\\"…</string>\n    <string name=\"apm_new_version_available\">Appuyez pour installer la nouvelle version, %s.</string>\n    <string name=\"home_selinux_status_permissive\">Permissif</string>\n    <string name=\"home_selinux_status_unknown\">Inconnu</string>\n    <string name=\"super_key\">Clé</string>\n    <string name=\"patch_title\">Patcher</string>\n    <string name=\"home_selinux_status\">État de SELinux</string>\n    <string name=\"home_selinux_status_enforcing\">Actif</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch n\\'est pas installé</string>\n    <string name=\"kpm_load\">Charger</string>\n    <string name=\"kpm_load_toast_succ\">Chargement réussi</string>\n    <string name=\"kpm_unload\">Décharger</string>\n    <string name=\"kpm_apm_empty\">Aucun module chargé</string>\n    <string name=\"apm_failed_to_enable\">Impossible d\\'activer le module \\\"%s\\\"</string>\n    <string name=\"kpm_args\">Arguments</string>\n    <string name=\"su_pkg_excluded_setting_summary\">L\\'activation de cette option permettra à APatch de restaurer tous les fichiers modifiés par les modules de cette application.</string>\n    <string name=\"apm_remove\">Désinstaller</string>\n    <string name=\"su_pkg_excluded_setting_title\">Exclure les modifications</string>\n    <string name=\"apm_overlay_fs_not_available\">Les modules sont indisponibles car OverlayFS est désactivé par le noyau !</string>\n    <string name=\"patch\">Patcher</string>\n    <string name=\"settings_app_language\">Langue</string>\n    <string name=\"system_default\">Système par défaut</string>\n    <string name=\"settings_global_namespace_mode\">Mode espace de nommage global</string>\n    <string name=\"settings_global_namespace_mode_summary\">Toutes les sessions root utilisent l\\'espace de nommage global</string>\n    <string name=\"settings_clear_super_key_dialog\">Voulez-vous vraiment continuer ?</string>\n    <string name=\"kpatch_version_update\">Version : %s -&gt; %s</string>\n    <string name=\"home_kpatch_info_title\">Info</string>\n    <string name=\"home_ap_cando_reboot\">Redémarrer</string>\n    <string name=\"patch_config_title\">Patchs</string>\n    <string name=\"patch_item_kernel\">Noyau</string>\n    <string name=\"patch_item_set_skey_label\">La longueur de la clé doit être d\\'au moins 8 caractères et inclure à la fois des numéros et des lettres, mais pas de caractères spéciaux.</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nouveau nom du gestionnaire</string>\n    <string name=\"hide_apatch_dialog_summary\">Il sera utilisé comme label de la nouvelle application affichée dans le lanceur d\\'applications</string>\n    <string name=\"hide_apatch_manager_summary\">Installer un proxy avec un identifiant de paquet aléatoire et un label d\\'application personnalisé</string>\n    <string name=\"hide_apatch_manager_failure\">Échec de la dissimulation, merci de signaler le bug !</string>\n    <string name=\"patch_embed_kpm_btn\">Intégrer un KPM</string>\n    <string name=\"patch_start_patch_btn\">Démarrer</string>\n    <string name=\"success\">Succès</string>\n    <string name=\"failure\">Échec</string>\n    <string name=\"patch_mode_bootimg_patch\">Mode : Patch</string>\n    <string name=\"patch_select_bootimg_btn\">Sélectionner l\\'image de boot</string>\n    <string name=\"patch_start_unpatch_btn\">Dépatcher</string>\n    <string name=\"patch_item_error\">!! ERREUR !!</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_bootimg_slot\">slot :</string>\n    <string name=\"patch_item_bootimg_dev\">appareil :</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Version :</string>\n    <string name=\"patch_item_kpimg_comile_time\">Date :</string>\n    <string name=\"patch_item_kpimg_config\">Config :</string>\n    <string name=\"patch_item_new_extra_kpm\">Intégrer un nouveau</string>\n    <string name=\"patch_item_extra_name\">Nom :</string>\n    <string name=\"patch_item_extra_author\">Auteur :</string>\n    <string name=\"patch_item_extra_kpm_license\">Licence :</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Description :</string>\n    <string name=\"patch_item_extra_event\">Événement :</string>\n    <string name=\"patch_item_skey\">Clé</string>\n    <string name=\"kpm_add_kpm\">Ajouter un KPM</string>\n    <string name=\"kpm_install\">Installer</string>\n    <string name=\"kpm_embed\">Intégrer</string>\n    <string name=\"setting_reset_su_path\">Réinitialiser le chemin su</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"patch_mode_uninstall_patch\">Mode : Dépatch</string>\n    <string name=\"patch_item_extra_version\">Version :</string>\n    <string name=\"patch_item_extra_args\">Args :</string>\n    <string name=\"hide_apatch_manager\">Masquer le gestionnaire APatch</string>\n    <string name=\"setting_reset_su_new_path\">nouveau chemin complet</string>\n    <string name=\"patch_item_existed_extra_kpm\">Existait</string>\n    <string name=\"settings_donot_store_superkey_summary\">Authentifier la clé à chaque démarrage du gestionnaire</string>\n    <string name=\"mode_select_page_select_file\">Sélectionner une image boot à patcher</string>\n    <string name=\"mode_select_page_patch_and_install\">Patcher et installer</string>\n    <string name=\"settings_check_update\">Vérifier les mises à jour</string>\n    <string name=\"settings_check_update_summary\">Vérifier automatiquement les mises à jour à l\\'ouverture de l\\'application</string>\n    <string name=\"home_more_menu_about\">À propos</string>\n    <string name=\"home_install_unknown_summary\">Cliquer pour installer</string>\n    <string name=\"home_device_info\">Appareil</string>\n    <string name=\"home_system_version\">Version du système</string>\n    <string name=\"home_kpatch_version\">Version de KernelPatch</string>\n    <string name=\"enable_web_debugging_summary\">Peut être utilisé pour déboguer l\\'interface web, n\\'activer cette option qu\\'en cas de besoin.</string>\n    <string name=\"home_new_apatch_found\">Nouvelle version disponible : %s, Cliquer pour mettre à jour.</string>\n    <string name=\"home_dialog_auth_fail_title\">Echec de l\\'authentification</string>\n    <string name=\"home_dialog_uninstall_title\">Désinstaller</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Supprimer AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Désinstaller complètement</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mode : Installer dans le slot suivant (après OTA)</string>\n    <string name=\"mode_select_page_title\">Installer</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Installer dans le slot inactif (après OTA)</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Commentaires ou suggestions</string>\n    <string name=\"patch_mode_patch_and_install\">Mode : Patcher et installer</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Votre appareil sera **FORCÉ** de démarrer sur le slot inactif actuel après un redémarrage !\n\\nN\\'utilisez cette option qu\\'une fois l\\'OTA terminée.\n\\nContinuer ?</string>\n    <string name=\"home_dialog_auth_fail_content\">Impossible d\\'authentifier la clé, par conséquent APatch ne peut pas fonctionner correctement. \\nVoici quelques raisons possibles de l\\'échec de l\\'authentification : \\n1. Vous n\\'avez pas patché l\\'image de démarrage avec KernelPatch. \\n2. L\\'image de démarrage patchée n\\'a pas été flashée. \\n3. La clé est erronée. \\n4. Votre appareil ne prend pas en charge APatch et KernelPatch. \\n \\nVeuillez vérifier et réessayer. Si des problèmes persistent, vous pouvez toujours poser vos questions sur le dépôt officiel.</string>\n    <string name=\"settings_donot_store_superkey\">Ne pas stocker la clé localement</string>\n    <string name=\"apm_webui_open\">Ouvrir l\\'interface web</string>\n    <string name=\"enable_web_debugging\">Activer le débogage WebView</string>\n    <string name=\"kpm_control\">Contrôle</string>\n    <string name=\"settings_night_mode_follow_sys\">Suivre le thème sombre du système</string>\n    <string name=\"teal_theme\">Thème sarcelle</string>\n    <string name=\"amber_theme\">Thème ambre</string>\n    <string name=\"lime_theme\">Thème citron vert</string>\n    <string name=\"pink_theme\">Thème rose</string>\n    <string name=\"blue_grey_theme\">Thème bleu gris</string>\n    <string name=\"purple_theme\">Thème violet</string>\n    <string name=\"brown_theme\">Thème marron</string>\n    <string name=\"cyan_theme\">Thème cyan</string>\n    <string name=\"orange_theme\">Thème orange</string>\n    <string name=\"yellow_theme\">Thème jaune</string>\n    <string name=\"about_app_desc\">Solution Root noyau avec seulement une image de noyau dépouillée, offrant la possibilité de monter un module système et de hook une fonction du noyau.</string>\n    <string name=\"kpm_control_ok\">Opération réussie !</string>\n    <string name=\"settings_night_theme_enabled\">Activer le thème sombre</string>\n    <string name=\"settings_use_system_color_theme\">Thème de couleur du système</string>\n    <string name=\"about_app_version\">Version %1$s</string>\n    <string name=\"kpm_control_dialog_content\">Paramètres de contrôle d\\'entrée :</string>\n    <string name=\"settings_custom_color_theme\">Thème de couleur</string>\n    <string name=\"light_blue_theme\">Thème bleu clair</string>\n    <string name=\"kpm_control_dialog_title\">Contrôler le KPModule</string>\n    <string name=\"kpm_control_outMsg\">Message</string>\n    <string name=\"kpm_control_failed\">Opération échouée !</string>\n    <string name=\"settings_use_system_color_theme_summary\">Utiliser un thème de couleur généré par le système avec le fond d\\'écran actuel</string>\n    <string name=\"blue_theme\">Thème bleu</string>\n    <string name=\"deep_orange_theme\">Thème orange foncé</string>\n    <string name=\"deep_purple_theme\">Thème violet foncé</string>\n    <string name=\"indigo_theme\">Thème indigo</string>\n    <string name=\"about_telegram_channel\">Canal Telegram</string>\n    <string name=\"about_telegram_group\">Groupe Telegram</string>\n    <string name=\"about_powered_by\">Propulsé par %1$s</string>\n    <string name=\"green_theme\">Thème vert</string>\n    <string name=\"light_green_theme\">Thème vert clair</string>\n    <string name=\"sakura_theme\">Thème sakura</string>\n    <string name=\"red_theme\">Thème rouge</string>\n    <string name=\"kpm_control_paramters\">Paramètres</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Basculement automatique vers le thème sombre en fonction des paramètres du système</string>\n    <string name=\"save_log\">Enregistrer le journal</string>\n    <string name=\"apm_action\">Action</string>\n    <string name=\"log_saved\">Journal enregistré</string>\n    <string name=\"crash_handle_title\">L\\'application a planté…</string>\n    <string name=\"crash_handle_copy\">Copier le rapport de plantage</string>\n    <string name=\"crash_handle_copied\">Rapport de plantage copié dans le presse-papiers.</string>\n    <string name=\"settings_lite_mode\">Activer le mode Lite</string>\n    <string name=\"settings_lite_mode_mode_summary\">Les fonctions APModule peuvent présenter des défaillances après avoir été activées, mais dans certains cas, elles peuvent toujours éviter la détection. Redémarrage requis.</string>\n    <string name=\"settings_force_overlayfs_mode\">Utilisation forcée de OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Utilisez OverlayFS pour monter APModules au lieu de Magic Mount lorsque le support du noyau est disponible. Redémarrage requis.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-gl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">Fogar</string>\n    <string name=\"patch_warnning\">A instalación conleva uns riscos. Por favor, asegura os teus datos.</string>\n    <string name=\"patch\">Parche</string>\n    <string name=\"kernel_patch\">Parche do Kernel</string>\n    <string name=\"android_patch\">Parche de Android</string>\n    <string name=\"reboot\">Reiniciar</string>\n    <string name=\"settings\">Configuración</string>\n    <string name=\"reboot_bootloader\">Reiniciar no cargador de arranque</string>\n    <string name=\"reboot_download\">Reiniciar para descargar</string>\n    <string name=\"reboot_edl\">Reiniciar a EDL</string>\n    <string name=\"about\">Acerca de</string>\n    <string name=\"system_default\">Por defecto do sistema</string>\n    <string name=\"reboot_recovery\">Reiniciar para recuperar</string>\n    <string name=\"settings_app_language\">Lingua</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-hr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"reboot\">Ponovno pokreni</string>\n    <string name=\"home\">Početna</string>\n    <string name=\"patch\">Patch</string>\n    <string name=\"settings\">Postavke</string>\n    <string name=\"reboot_recovery\">Pokreni u Modu za Oporavak</string>\n    <string name=\"reboot_bootloader\">Pokreni u Bootloader</string>\n    <string name=\"reboot_download\">Pokreni u Download</string>\n    <string name=\"reboot_edl\">Pokreni u EDL</string>\n    <string name=\"settings_app_language\">Jezik</string>\n    <string name=\"home_learn_apatch\">Nauči o APatch-u</string>\n    <string name=\"home_click_to_learn_apatch\">Nauči više o značajkama APatch i kako ih koristiti</string>\n    <string name=\"about_source_code\">Pogledaj izvorni kod na %1$s<br/>Pridruži se na našem %2$s kanalu</string>\n    <string name=\"send_log\">Pošalji logove</string>\n    <string name=\"safe_mode\">Sigurni način</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"clear_super_key\">Izbriši SuperKey</string>\n    <string name=\"patch_set_superkey\">Postavi SuperKey</string>\n    <string name=\"home_patch_next_step\">Sljedeći korak</string>\n    <string name=\"home_not_installed\">Nije instalirano</string>\n    <string name=\"home_install_unknown\">Nepoznato</string>\n    <string name=\"home_click_to_install\">Klikni za instalaciju</string>\n    <string name=\"home_working\">Funkcionira</string>\n    <string name=\"home_installing\">Instaliranje</string>\n    <string name=\"home_need_update\">Nova inačica dostupna</string>\n    <string name=\"kpatch_version\">Verzija: %s</string>\n    <string name=\"apatch_version\">Inačica:\n\\n%s</string>\n    <string name=\"apatch_version_update\">Inačica:\n\\n%s -&gt; %s</string>\n    <string name=\"home_su_path\">su: %s</string>\n    <string name=\"home_auth_key_desc\">Pokreni nakon certificiranja</string>\n    <string name=\"home_ap_cando_install\">Instaliraj</string>\n    <string name=\"home_ap_cando_update\">Ažuriraj</string>\n    <string name=\"home_ap_cando_uninstall\">De-instaliraj</string>\n    <string name=\"patch_title\">Patch</string>\n    <string name=\"home_kernel\">Kernel</string>\n    <string name=\"about\">Informacije</string>\n    <string name=\"system_default\">Sistemska postavka</string>\n    <string name=\"settings_global_namespace_mode\">Global Namespace Mode</string>\n    <string name=\"home_manager_version\">Upravitelj verzija</string>\n    <string name=\"home_fingerprint\">Otisak</string>\n    <string name=\"home_selinux_status\">SELinux status</string>\n    <string name=\"home_selinux_status_disabled\">Isključeno</string>\n    <string name=\"home_selinux_status_permissive\">Permissive</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"kpm_load_toast_succ\">Učitavanje završeno</string>\n    <string name=\"kpm_load_toast_failed\">Učitavanje neusješno</string>\n    <string name=\"kpm_unload_confirm\">Odčitaj \\\"%s\\\" modul?</string>\n    <string name=\"kpm_unload\">Odčitaj</string>\n    <string name=\"kpm_apm_empty\">Nijedan modul očitan</string>\n    <string name=\"kpm_version\">Inačica</string>\n    <string name=\"kpm_license\">Licenca</string>\n    <string name=\"kpm_author\">Autor</string>\n    <string name=\"kpm_desc\">Opis</string>\n    <string name=\"kpm_args\">Argumenti</string>\n    <string name=\"su_title\">Superuser</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Uključivanjem ove opcije dozvoljavate APatch-u da vrati bilo koje datoteke modificirane modulima ove aplikacije.</string>\n    <string name=\"su_show_system_apps\">Prikaži sistemske aplikacije</string>\n    <string name=\"su_hide_system_apps\">Sakrij sistemske aplikacije</string>\n    <string name=\"su_refresh\">Osvježi</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"apm_not_installed\">AndroidPatch nije instaliran</string>\n    <string name=\"apm_failed_to_enable\">Nije bilo moguće uključit \\\"%s\\\" modul</string>\n    <string name=\"apm_empty\">Nema modula instalirana</string>\n    <string name=\"apm_remove\">Ukloni</string>\n    <string name=\"apm_install\">Instaliraj</string>\n    <string name=\"apm_start_downloading\">Počni preuzimati %s</string>\n    <string name=\"apm_new_version_available\">Nova verzija %s je dostupna, klikni za nadogradnju.</string>\n    <string name=\"su_selinux_via_hook\">bypass via hook</string>\n    <string name=\"su_pkg_excluded_label\">Isključi</string>\n    <string name=\"su_pkg_excluded_setting_title\">Isključi modifikacije</string>\n    <string name=\"patch_warnning\">Instalacija može biti riskantna. Sačuvaj osobne podatke.</string>\n    <string name=\"kpm_load\">Učitaj</string>\n    <string name=\"home_apatch_version\">Apatch: %s</string>\n    <string name=\"home_auth_key_title\">Unesi SuperKey</string>\n    <string name=\"home_selinux_status_enforcing\">Enforcing</string>\n    <string name=\"home_selinux_status_unknown\">Nepoznato</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch nije instaliran</string>\n    <string name=\"apm_failed_to_disable\">Nije bilo moguće isključiti \\\"%s\\\" modul</string>\n    <string name=\"apm_desc\">Opis</string>\n    <string name=\"apm_uninstall_confirm\">Deinstaliraj \\\"%s\\\" modul?</string>\n    <string name=\"apm_uninstall_success\">%s deinstaliran</string>\n    <string name=\"apm_uninstall_failed\">Nije bilo moguće deinstalirati %s</string>\n    <string name=\"apm_version\">Verzija</string>\n    <string name=\"apm_author\">Autor</string>\n    <string name=\"apm_overlay_fs_not_available\">Moduli nisu dostupni jer je OverlayFS onemogućeni od strane kernela.</string>\n    <string name=\"apm_magisk_conflict\">Moduli su nedostupni radi konflikta s Magiskom!</string>\n    <string name=\"apm_reboot_to_apply\">Ponovno pokreni za promjene</string>\n    <string name=\"apm_changelog\">Lista promjene</string>\n    <string name=\"apm_update\">Ažuriraj</string>\n    <string name=\"apm_downloading\">Preuzimanje \\\"%s\\\" modula…</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"settings_global_namespace_mode_summary\">Sve root sesije koriste globalni mount namespace</string>\n    <string name=\"home_patch_set_key_desc\">Samo zaporke za KernelPatch</string>\n    <string name=\"settings_clear_super_key_dialog\">Želite li stvarno nastaviti?</string>\n    <string name=\"success\">Uspješno</string>\n    <string name=\"failure\">Neuspješno</string>\n    <string name=\"settings_check_update\">Provjeriti ažuriranja</string>\n    <string name=\"patch_item_kpimg_comile_time\">Vrijeme:</string>\n    <string name=\"patch_item_extra_version\">Verzija:</string>\n    <string name=\"patch_item_kpimg_config\">Konfiguracija:</string>\n    <string name=\"patch_item_extra_author\">Autor:</string>\n    <string name=\"patch_item_extra_kpm_license\">Licenca:</string>\n    <string name=\"patch_item_extra_args\">Argumenti:</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"patch_item_bootimg_dev\">uređaj:</string>\n    <string name=\"patch_config_title\">Patchovi</string>\n    <string name=\"patch_mode_bootimg_patch\">Mod: Patch</string>\n    <string name=\"patch_item_existed_extra_kpm\">Postojalo</string>\n    <string name=\"patch_item_extra_name\">Ime:</string>\n    <string name=\"save_log\">Spremi logove</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Opis:</string>\n    <string name=\"patch_item_extra_event\">Događaj:</string>\n    <string name=\"home_new_apatch_found\">Nova verzija %s je dostupna, klikni za nadogradnju.</string>\n    <string name=\"settings_check_update_summary\">Automatski provjeri za nadogradnje prilikom otvaranja aplikacije</string>\n    <string name=\"kpatch_version_update\">Verzija: %s -&gt; %s</string>\n    <string name=\"home_ap_cando_reboot\">Restartiraj</string>\n    <string name=\"patch_mode_patch_and_install\">Mod: Patch i instaliraj</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mod: Instaliraj na inaktivni slot (Poslije OTA nadogradnje)</string>\n    <string name=\"patch_mode_uninstall_patch\">Mod: Deinstaliraj KPatch</string>\n    <string name=\"patch_start_patch_btn\">Pokreni</string>\n    <string name=\"patch_item_error\">!!GREŠKA!!</string>\n    <string name=\"patch_item_kpimg_version\">Verzija:</string>\n    <string name=\"patch_item_set_skey_label\">SuperKey treba biti 8-63 znamenke dugačak, uključujući brojeve i slova ali ne posebne simbole.</string>\n    <string name=\"home_device_info\">Uređaj</string>\n    <string name=\"home_system_version\">Verzija sustava</string>\n    <string name=\"kpm_install\">Instaliraj</string>\n    <string name=\"kpm_control\">Kontrola</string>\n    <string name=\"hide_apatch_manager\">Sakrij APatch Manager</string>\n    <string name=\"hide_apatch_manager_failure\">Nije moguće sakriti. Molimo prijavite grešku!</string>\n    <string name=\"log_saved\">Logovi spremljeni</string>\n    <string name=\"mode_select_page_title\">Instaliraj</string>\n    <string name=\"apm_webui_open\">Otvori</string>\n    <string name=\"apm_action\">Radnja</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Deinstaliraj AndroidPatch</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Vaš uređaj će biti **FORSIRAN* da pokrene trenutni inaktivni slot nakon restarta!\\nSamo koristite ovu opcije nakon što je OTA nadogradnje dovršena.\\nNastaviti?</string>\n    <string name=\"home_dialog_uninstall_all\">Deinstaliraj sve</string>\n    <string name=\"home_dialog_auth_fail_title\">Autentikacija nije uspjela</string>\n    <string name=\"home_dialog_uninstall_title\">Deinstaliraj</string>\n    <string name=\"kpm_control_paramters\">Parametri</string>\n    <string name=\"kpm_control_outMsg\">Poruka</string>\n    <string name=\"kpm_control_ok\">Operacija uspješna!</string>\n    <string name=\"patch_item_kernel\">Jezgra</string>\n    <string name=\"settings_donot_store_superkey_summary\">Autentificiraj SuperKey pri svakom pokretanju upravitelja</string>\n    <string name=\"settings_donot_store_superkey\">Nemoj spremati SuperKey u local</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Novo ime upravitelja</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Automatski prebaci na tamni prikaz ovisno o postavkama sistema</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"home_dialog_auth_fail_content\">Nije moguće autentificirati SuperKey, stoga APatch ne može pravilno funkcionirati.\\nOvo su neki od mogućih uzroka neuspjeha autentifikacije:\\n1.</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Povratne informacije ili prijedlozi</string>\n    <string name=\"settings_night_theme_enabled\">Uključi tamni prikaz</string>\n    <string name=\"settings_custom_color_theme\">Boje prikaza</string>\n    <string name=\"blue_grey_theme\">Plavo-siva</string>\n    <string name=\"blue_theme\">Plava</string>\n    <string name=\"orange_theme\">Narančasta</string>\n    <string name=\"pink_theme\">Ružičasta</string>\n    <string name=\"red_theme\">Crvena</string>\n    <string name=\"green_theme\">Zelena</string>\n    <string name=\"indigo_theme\">Indigo</string>\n    <string name=\"patch_select_bootimg_btn\">Odaberite pokretanje</string>\n    <string name=\"home_more_menu_about\">Informacije</string>\n    <string name=\"home_install_unknown_summary\">Pritisnite za instalaciju</string>\n    <string name=\"home_kpatch_info_title\">Informacije</string>\n    <string name=\"patch_start_unpatch_btn\">Makni patch</string>\n    <string name=\"patch_item_bootimg\">Slika za pokretanje</string>\n    <string name=\"kpm_add_kpm\">Dodaj KPM</string>\n    <string name=\"hide_apatch_manager_summary\">Instaliraj novu aplikaciju upravitelja s nasumičnim ID-jem i prilagođenom oznakom</string>\n    <string name=\"hide_apatch_dialog_summary\">Biti će korišteno za novu oznaku aplikacije prikazane u pokretaču</string>\n    <string name=\"setting_reset_su_path\">Resetiraj su put</string>\n    <string name=\"setting_reset_su_new_path\">Novi puni put</string>\n    <string name=\"enable_web_debugging\">Uključi WebView debugganje</string>\n    <string name=\"enable_web_debugging_summary\">Može se koristiti za debuggiranje WebUI-a. Molimo uključite samo kada potrebno.</string>\n    <string name=\"mode_select_page_patch_and_install\">Primjeni i instaliraj</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Instaliraj u neaktivni utor (Nakon OTA)</string>\n    <string name=\"kpm_control_dialog_title\">Kontroliraj KPModule</string>\n    <string name=\"kpm_control_dialog_content\">Parametri kontrola unosa:</string>\n    <string name=\"kpm_control_failed\">Operacija neuspješna!</string>\n    <string name=\"settings_night_mode_follow_sys\">Prati tamni prikaz sistema</string>\n    <string name=\"settings_use_system_color_theme\">Boje prikaza sistema</string>\n    <string name=\"settings_use_system_color_theme_summary\">Koristi boje prikaza koje je sistem generirao bazirano na trenutačnoj pozadini.</string>\n    <string name=\"amber_theme\">Jantar</string>\n    <string name=\"brown_theme\">Smeđa</string>\n    <string name=\"deep_orange_theme\">Tamno narančasta</string>\n    <string name=\"deep_purple_theme\">Tamno ljubičasta</string>\n    <string name=\"light_blue_theme\">Svijetlo plava</string>\n    <string name=\"light_green_theme\">Svijetlo zelena</string>\n    <string name=\"lime_theme\">Boja limete</string>\n    <string name=\"purple_theme\">Ljubičasta</string>\n    <string name=\"sakura_theme\">Boja sakure</string>\n    <string name=\"teal_theme\">Tirkizna</string>\n    <string name=\"yellow_theme\">Žuta</string>\n    <string name=\"about_telegram_channel\">Telegram kanal</string>\n    <string name=\"about_telegram_group\">Telegram grupa</string>\n    <string name=\"crash_handle_title\">Aplikacija se srušila…</string>\n    <string name=\"crash_handle_copy\">Kopiraj log rušenja</string>\n    <string name=\"crash_handle_copied\">Log rušenja kopiran u međuspremnik.</string>\n    <string name=\"cyan_theme\">Cijan</string>\n    <string name=\"about_app_version\">Verzija %1$s</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"kpatch_version\">Verzió: %s</string>\n    <string name=\"home_apatch_version\">APatch: %s</string>\n    <string name=\"reboot\">Újraindítás</string>\n    <string name=\"settings\">Beállítások</string>\n    <string name=\"home_install_unknown\">Ismeretlen</string>\n    <string name=\"home_click_to_install\">Kattints a telepítéshez</string>\n    <string name=\"home_installing\">Telepítés...</string>\n    <string name=\"home_need_update\">Frissítés elérhető</string>\n    <string name=\"apatch_version_update\">Verzió: %s -&gt; %s</string>\n    <string name=\"home_su_path\">su: %s</string>\n    <string name=\"home_ap_cando_install\">Telepítés</string>\n    <string name=\"home_ap_cando_update\">Frissítés</string>\n    <string name=\"home_ap_cando_uninstall\">Eltávolítás</string>\n    <string name=\"home_kernel\">Kernel</string>\n    <string name=\"home_fingerprint\">Ujjlenyomat</string>\n    <string name=\"home_selinux_status\">SELinux állapot</string>\n    <string name=\"home_selinux_status_disabled\">kikapcsolva</string>\n    <string name=\"home_selinux_status_unknown\">Ismeretlen</string>\n    <string name=\"kpm_load\">Betöltés</string>\n    <string name=\"kpm_load_toast_succ\">Betöltés sikeres</string>\n    <string name=\"kpm_load_toast_failed\">Betöltés sikertelen</string>\n    <string name=\"kpm_apm_empty\">Nincs modul betöltve</string>\n    <string name=\"kpm_version\">Verzió</string>\n    <string name=\"kpm_license\">Licensz</string>\n    <string name=\"kpm_author\">Szerző</string>\n    <string name=\"su_pkg_excluded_label\">kizárás</string>\n    <string name=\"su_pkg_excluded_setting_title\">Kizárja a módosításokat</string>\n    <string name=\"settings_app_language\">Nyelv</string>\n    <string name=\"system_default\">Rendszer alapértelmezett</string>\n    <string name=\"apm_desc\">Leírás</string>\n    <string name=\"apm_version\">Verzió</string>\n    <string name=\"apm_author\">Szerző</string>\n    <string name=\"home_patch_next_step\">Következő Lépés</string>\n    <string name=\"home_not_installed\">Nincs telepítve</string>\n    <string name=\"apatch_version\">Verzió: %s</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Ennek az opciónak a bekapcsolása engedélyezi az APatch számára, hogy visszaállítson más modulok álltal módosított fájlokat.</string>\n    <string name=\"apm_uninstall_confirm\">A(z) \\\"%s\\\" modul eltávolítása?</string>\n    <string name=\"apm_uninstall_success\">%s eltávolítva</string>\n    <string name=\"apm_uninstall_failed\">Nem sikerült eltávolítani a(z) %s-t</string>\n    <string name=\"apm_magisk_conflict\">A modulok nem érhetők el a Magiskkal való konfliktus miatt.</string>\n    <string name=\"apm\">APModul</string>\n    <string name=\"apm_not_installed\">Az AndroidPatch nincs telepítva</string>\n    <string name=\"apm_failed_to_disable\">Nem kapcsolható ki a \\\"%s\\\" modul</string>\n    <string name=\"apm_empty\">Nincs telepített modul</string>\n    <string name=\"su_show_system_apps\">Rendszeralkalmazások megjelenítése</string>\n    <string name=\"su_hide_system_apps\">Rendszeralkalmazások elrejtése</string>\n    <string name=\"su_refresh\">Frissítés</string>\n    <string name=\"apm_remove\">Eltávolítás</string>\n    <string name=\"apm_install\">Telepítés</string>\n    <string name=\"apm_reboot_to_apply\">Újraindítsa a hatás eléréséhez</string>\n    <string name=\"apm_changelog\">Változásnapló</string>\n    <string name=\"apm_update\">Frissítés</string>\n    <string name=\"apm_downloading\">\\\"%s\\\" modul letöltés alatt…</string>\n    <string name=\"apm_start_downloading\">%s letöltésének elkezdése</string>\n    <string name=\"apm_new_version_available\">Új verzió (%s) érhető el. Kattints a telepítéshez!</string>\n    <string name=\"patch_warnning\">A telepítés kockázatokkal jár. Kérjük, készíts biztonsági másolatot az adataidról.</string>\n    <string name=\"patch\">Javítás</string>\n    <string name=\"reboot_bootloader\">Újraindítás a Bootloaderbe</string>\n    <string name=\"settings_global_namespace_mode_summary\">Minden gyökérmunka a globális hegyi neveket használja</string>\n    <string name=\"home_learn_apatch\">APatch tanulása</string>\n    <string name=\"apm_overlay_fs_not_available\">A modulok nem elérhetőek, mert az OverlayFS ki van kapcsolva a kernelben!</string>\n    <string name=\"settings_clear_super_key_dialog\">Biztos folytatni akarod?</string>\n    <string name=\"home_click_to_learn_apatch\">Ismerd meg az APatch funkcióit és használatát</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Forráskód megtekintése %1$s-on<p/>Csatlakozz a %2$s csatornánkhoz<p/>Csatlakozz a %3$s csoportunkhoz]]></string>\n    <string name=\"send_log\">Naplók küldése</string>\n    <string name=\"safe_mode\">Biztonságos mód</string>\n    <string name=\"super_key\">SzuperKulcs</string>\n    <string name=\"clear_super_key\">SzuperKulcs tisztítása</string>\n    <string name=\"patch_set_superkey\">SzuperKulcs beállítása</string>\n    <string name=\"home_patch_set_key_desc\">Kizárólag a KernelPatch hitelesítéséhez</string>\n    <string name=\"kpatch_version_update\">Verzió: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_auth_key_title\">Írd be a SzuperKulcsot</string>\n    <string name=\"home_auth_key_desc\">Kezdés a tanúsítás után</string>\n    <string name=\"home_kpatch_info_title\">Infó</string>\n    <string name=\"home_ap_cando_reboot\">Újraindítás</string>\n    <string name=\"patch_title\">Javítás</string>\n    <string name=\"patch_config_title\">Javítások</string>\n    <string name=\"patch_mode_bootimg_patch\">Mód: Javítás</string>\n    <string name=\"patch_select_bootimg_btn\">Választás indításnal</string>\n    <string name=\"patch_embed_kpm_btn\">KPM beágyazása</string>\n    <string name=\"patch_start_patch_btn\">Indítás</string>\n    <string name=\"patch_start_unpatch_btn\">Javítás visszavonása</string>\n    <string name=\"patch_mode_uninstall_patch\">Mód: Javítás visszavonása</string>\n    <string name=\"patch_item_error\">!!HIBA!!</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_bootimg_slot\">hely:</string>\n    <string name=\"patch_item_bootimg_dev\">eszköz:</string>\n    <string name=\"patch_item_kernel\">kernel</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">verzió:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Idő:</string>\n    <string name=\"patch_item_kpimg_config\">Konfig:</string>\n    <string name=\"patch_item_new_extra_kpm\">új beágyazása</string>\n    <string name=\"patch_item_existed_extra_kpm\">létezett</string>\n    <string name=\"patch_item_extra_name\">Név:</string>\n    <string name=\"patch_item_extra_version\">Verzió:</string>\n    <string name=\"patch_item_extra_kpm_license\">licenc:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Leírás:</string>\n    <string name=\"patch_item_extra_args\">Argumentumok:</string>\n    <string name=\"patch_item_extra_event\">Események:</string>\n    <string name=\"patch_item_skey\">Szuper kulcs</string>\n    <string name=\"patch_item_extra_author\">Szerző:</string>\n    <string name=\"patch_item_set_skey_label\">A szuperkulcs hossza legalább 8 karakter legyen, és tartalmazzon számokat és betűket egyaránt.</string>\n    <string name=\"home_manager_version\">Kezelő Verziója</string>\n    <string name=\"home_selinux_status_enforcing\">Kényszerített</string>\n    <string name=\"home_selinux_status_permissive\">Permisszív</string>\n    <string name=\"kpm\">KPModul</string>\n    <string name=\"kpm_kp_not_installed\">A KernelPatch nincs telepítve</string>\n    <string name=\"kpm_desc\">Leírás</string>\n    <string name=\"kpm_args\">Argumentumok</string>\n    <string name=\"su_selinux_via_hook\">kikerülés horoggal</string>\n    <string name=\"apm_failed_to_enable\">Nem sikerült bekapcsolni a(z) \\\"%s\\\" modult</string>\n    <string name=\"home\">Kezdőlap</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot_recovery\">Újaraindítás a Visszaállítóba</string>\n    <string name=\"reboot_download\">Újraindítás a Letöltés-módba</string>\n    <string name=\"reboot_edl\">Újraindítás az EDL-be</string>\n    <string name=\"about\">Rólunk</string>\n    <string name=\"settings_global_namespace_mode\">Globális névtér mód</string>\n    <string name=\"home_working\">Működik</string>\n    <string name=\"kpm_unload\">Kitöltés</string>\n    <string name=\"kpm_unload_confirm\">\\\"%s\\\" modul kitöltése?</string>\n    <string name=\"su_title\">Superuser</string>\n    <string name=\"success\">Sikeres</string>\n    <string name=\"failure\">Hiba</string>\n    <string name=\"settings_check_update_summary\">Frissítések automatikus keresése minden induláskor</string>\n    <string name=\"settings_check_update\">Frissítés ellenőrzése</string>\n    <string name=\"home_device_info\">Eszköz</string>\n    <string name=\"home_system_version\">Rendszer verziója</string>\n    <string name=\"kpm_control\">Control</string>\n    <string name=\"kpm_install\">Telepítés</string>\n    <string name=\"kpm_embed\">Beágyazás</string>\n    <string name=\"home_kpatch_version\">KernelPatch verzió</string>\n    <string name=\"kpm_add_kpm\">KPM hozzáadása</string>\n    <string name=\"save_log\">ddd</string>\n    <string name=\"hide_apatch_manager_summary\">Új menedzser alk. telepítése véletlenszerű ID-vel és saját címkével</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Új menedzser neve</string>\n    <string name=\"hide_apatch_manager\">APatch Menedzser elrejtése</string>\n    <string name=\"setting_reset_su_new_path\">Új, teljes elérési út</string>\n    <string name=\"hide_apatch_manager_failure\">Nem sikerült elrejteni. Kérlek jelentsd a hibát!</string>\n    <string name=\"setting_reset_su_path\">a \\'su\\' elérési útjának visszaállítása</string>\n    <string name=\"apm_webui_open\">Megnyitás</string>\n    <string name=\"enable_web_debugging\">A WebView hibakeresés engedélyezése</string>\n    <string name=\"patch_mode_patch_and_install\">Mód: Javítás és telepítés</string>\n    <string name=\"home_install_unknown_summary\">Kattints a telepítéshez</string>\n    <string name=\"log_saved\">Napló elmentve</string>\n    <string name=\"apm_action\">Művelet</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mód:Telepítés inaktív helyre (OTA után)</string>\n    <string name=\"settings_donot_store_superkey\">Ne mentse a Szuper kulcsot helyileg</string>\n    <string name=\"enable_web_debugging_summary\">Nem használható a WebUI hibakereséséhez. Csak akkor engedélyezze ha szüksége van rá.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-in/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"patch_warnning\">Berisiko! Pastikan data anda telah dicadangkan.</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"apm\">APModul</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"kpm\">KPModul</string>\n    <string name=\"reboot_recovery\">Reboot ke Recovery</string>\n    <string name=\"reboot\">Reboot</string>\n    <string name=\"settings\">Setelan</string>\n    <string name=\"reboot_bootloader\">Reboot ke Bootloader</string>\n    <string name=\"home_click_to_learn_apatch\">Pelajari fitur dan penggunaan APatch</string>\n    <string name=\"reboot_edl\">Reboot ke EDL</string>\n    <string name=\"home_learn_apatch\">Pelajari APatch</string>\n    <string name=\"about\">Tentang</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Lihat kode sumber di %1$s<p/>Gabung kanal %2$s kami<p/>Gabung grup %3$s kami]]></string>\n    <string name=\"send_log\">Kirim log</string>\n    <string name=\"safe_mode\">Mode aman</string>\n    <string name=\"home_patch_set_key_desc\">Kredensial untuk KernelPatch</string>\n    <string name=\"patch_set_superkey\">Pasang SuperKey</string>\n    <string name=\"home_install_unknown\">Tidak terinstall atau terautentikasi</string>\n    <string name=\"home_click_to_install\">Klik untuk menginstal</string>\n    <string name=\"home_patch_next_step\">Langkah selanjutnya</string>\n    <string name=\"home_not_installed\">Tidak terinstal</string>\n    <string name=\"home\">Beranda</string>\n    <string name=\"home_working\">Berfungsi 😋</string>\n    <string name=\"kpatch_version\">Versi: %s</string>\n    <string name=\"home_installing\">Menginstal</string>\n    <string name=\"apatch_version\">Versi: %s</string>\n    <string name=\"home_need_update\">Versi terbaru tersedia</string>\n    <string name=\"apatch_version_update\">Versi: %s -&gt; %s</string>\n    <string name=\"home_auth_key_title\">Masukkan SuperKey</string>\n    <string name=\"reboot_download\">Reboot ke Download</string>\n    <string name=\"home_auth_key_desc\">Mulai setelah sertifikasi</string>\n    <string name=\"home_ap_cando_update\">Perbarui</string>\n    <string name=\"home_ap_cando_uninstall\">Hapus</string>\n    <string name=\"home_ap_cando_install\">Instal</string>\n    <string name=\"home_apatch_version\">Versi APatch</string>\n    <string name=\"home_su_path\">Binari SU</string>\n    <string name=\"home_kernel\">Kernel</string>\n    <string name=\"home_manager_version\">Versi manajer</string>\n    <string name=\"patch_title\">Patch</string>\n    <string name=\"apm_uninstall_success\">%s berhasil dihapus</string>\n    <string name=\"apm_install\">Instal</string>\n    <string name=\"apm_remove\">Hapus</string>\n    <string name=\"apm_uninstall_confirm\">Hapus modul \\\"%s\\\"?</string>\n    <string name=\"apm_version\">Versi</string>\n    <string name=\"apm_overlay_fs_not_available\">Modul tidak tersedia karena OverlayFS dinonaktifkan oleh kernel!</string>\n    <string name=\"apm_uninstall_failed\">Gagal menghapus %s</string>\n    <string name=\"apm_magisk_conflict\">Modul tidak tersedia karena ada konflik dengan Magisk!</string>\n    <string name=\"apm_desc\">Ket.</string>\n    <string name=\"apm_empty\">Tidak ada modul terinstal</string>\n    <string name=\"apm_author\">Oleh</string>\n    <string name=\"apm_reboot_to_apply\">Reboot untuk menerapkan</string>\n    <string name=\"apm_start_downloading\">Mulai mengunduh %s</string>\n    <string name=\"kpm_desc\">Ket.</string>\n    <string name=\"su_show_system_apps\">Tampilkan aplikasi sistem</string>\n    <string name=\"apm_changelog\">Log perubahan</string>\n    <string name=\"kpm_author\">Oleh</string>\n    <string name=\"apm_downloading\">Modul %s sedang diunduh…</string>\n    <string name=\"apm_new_version_available\">Versi baru %s tersedia, klik untuk memperbarui.</string>\n    <string name=\"apm_update\">Membarui</string>\n    <string name=\"su_refresh\">Muat ulang</string>\n    <string name=\"apm_failed_to_disable\">Gagal menonaktifkan modul \\\"%s\\\"</string>\n    <string name=\"apm_failed_to_enable\">Gagal mengaktifkan modul \\\"%s\\\"</string>\n    <string name=\"su_hide_system_apps\">Sembunyikan aplikasi sistem</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch tidak terinstal</string>\n    <string name=\"su_pkg_excluded_setting_title\">Kecualikan modifikasi</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Aktifkan opsi ini agar APatch dapat memulihkan kembali berkas yang termodifikasi oleh modul ini.</string>\n    <string name=\"su_pkg_excluded_label\">dikecualikan</string>\n    <string name=\"su_title\">SuperUser</string>\n    <string name=\"su_selinux_via_hook\">bypass via hook</string>\n    <string name=\"kpm_version\">Versi</string>\n    <string name=\"home_selinux_status_unknown\">Tidak diketahui</string>\n    <string name=\"home_selinux_status_permissive\">Permisif</string>\n    <string name=\"home_selinux_status\">Status SELinux</string>\n    <string name=\"kpm_load_toast_failed\">Gagal memuat</string>\n    <string name=\"home_selinux_status_disabled\">Dinonaktifkan</string>\n    <string name=\"kpm_load\">Muat</string>\n    <string name=\"home_selinux_status_enforcing\">Enforcing</string>\n    <string name=\"kpm_license\">Lisensi</string>\n    <string name=\"kpm_load_toast_succ\">Berhasil memuat</string>\n    <string name=\"kpm_apm_empty\">Tidak ada modul</string>\n    <string name=\"kpm_unload_confirm\">Lepas modul %s?</string>\n    <string name=\"kpm_unload\">Lepas</string>\n    <string name=\"kpm_args\">Argu</string>\n    <string name=\"home_fingerprint\">Identitas</string>\n    <string name=\"clear_super_key\">Hapus SuperKey</string>\n    <string name=\"apm_not_installed\">AndroidPatch tidak terinstal</string>\n    <string name=\"settings_app_language\">Bahasa</string>\n    <string name=\"system_default\">Bawaan sistem</string>\n    <string name=\"patch\">Patch</string>\n    <string name=\"settings_global_namespace_mode_summary\">Gunakan universal namespace ke semua root sesi</string>\n    <string name=\"settings_global_namespace_mode\">Mode universal namespace</string>\n    <string name=\"settings_clear_super_key_dialog\">Anda yakin untuk melanjutkan?</string>\n    <string name=\"kpatch_version_update\">Versi: %s -&gt; %s</string>\n    <string name=\"home_kpatch_info_title\">Info</string>\n    <string name=\"home_ap_cando_reboot\">Reboot</string>\n    <string name=\"patch_config_title\">Patch</string>\n    <string name=\"patch_embed_kpm_btn\">Tanam KPM</string>\n    <string name=\"patch_mode_bootimg_patch\">Mode: Patch</string>\n    <string name=\"patch_select_bootimg_btn\">Pilih boot</string>\n    <string name=\"patch_start_patch_btn\">Mulai</string>\n    <string name=\"patch_item_error\">!!GALAT!!</string>\n    <string name=\"patch_mode_patch_and_install\">Mode: Patch dan instal</string>\n    <string name=\"patch_item_bootimg_dev\">perangkat:</string>\n    <string name=\"patch_item_kpimg_version\">Versi:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Waktu:</string>\n    <string name=\"patch_item_kpimg_config\">Konfigurasi:</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"patch_item_new_extra_kpm\">Tanam baru</string>\n    <string name=\"patch_item_existed_extra_kpm\">Tertanam</string>\n    <string name=\"patch_item_extra_name\">Nama:</string>\n    <string name=\"patch_item_extra_kpm_license\">Lisensi:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Deskripsi:</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"patch_item_set_skey_label\">SuperKey terdiri dari 8-63 karakter dan memuat huruf dan angka, tanpa memuat karakter spesial.</string>\n    <string name=\"patch_item_extra_version\">Versi:</string>\n    <string name=\"patch_item_extra_author\">Oleh:</string>\n    <string name=\"patch_item_extra_args\">Argu:</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_mode_uninstall_patch\">Mode: Hapus KPatch</string>\n    <string name=\"patch_start_unpatch_btn\">UnPatch</string>\n    <string name=\"patch_item_extra_event\">Event:</string>\n    <string name=\"patch_item_bootimg_slot\">slot:</string>\n    <string name=\"kpm_add_kpm\">Tambah KPM</string>\n    <string name=\"kpm_install\">Pasang</string>\n    <string name=\"kpm_embed\">Tanam</string>\n    <string name=\"hide_apatch_manager_failure\">Gagal menyembunyikan. Tolong laporkan bug ini!</string>\n    <string name=\"hide_apatch_manager_summary\">Instal apl proksi dengan ID acak dan label kustom</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nama manajer baru</string>\n    <string name=\"hide_apatch_manager\">Sembunyikan manajer APatch</string>\n    <string name=\"hide_apatch_dialog_summary\">Digunakan sebagai nama aplikasi di peluncur</string>\n    <string name=\"success\">Berhasil</string>\n    <string name=\"failure\">Gagal</string>\n    <string name=\"setting_reset_su_new_path\">Jalur penuh baru</string>\n    <string name=\"setting_reset_su_path\">Reset jalur su</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mode: Instal ke slot nonaktif (Setelah OTA)</string>\n    <string name=\"settings_check_update_summary\">Otomatis memeriksa pembaruan saat membuka manajer</string>\n    <string name=\"apm_webui_open\">Buka</string>\n    <string name=\"home_dialog_auth_fail_title\">Gagal mengautentikasi</string>\n    <string name=\"home_more_menu_about\">Tentang</string>\n    <string name=\"mode_select_page_patch_and_install\">Patch dan pasang</string>\n    <string name=\"mode_select_page_select_file\">Pilih Boot Image</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Saran dan Masukan</string>\n    <string name=\"mode_select_page_title\">Pasang</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Pasang ke slot tidak aktif (Setelah OTA)</string>\n    <string name=\"home_kpatch_version\">Versi KernelPatch</string>\n    <string name=\"enable_web_debugging\">Aktifkan debugging WebView</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Perangkat akan **DIPAKSA** untuk memulai ulang ke slot nonaktif!\\nHanya gunakan opsi ini setelah proses OTA selesai.\\nLanjutkan?</string>\n    <string name=\"home_dialog_uninstall_title\">Copot</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Hapus AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Copot semua</string>\n    <string name=\"settings_check_update\">Periksa pembaruan</string>\n    <string name=\"home_install_unknown_summary\">Klik untuk menginstal</string>\n    <string name=\"home_device_info\">Perangkat</string>\n    <string name=\"home_system_version\">Versi Sistem</string>\n    <string name=\"home_dialog_auth_fail_content\">Gagal mengautentikasi SuperKey, APatch tidak dapat berfungsi normal.\\nHal ini dapat disebabkan oleh:\\n1. Boot.img tidak di-patch dengan KernelPatch.\\n2. Tidak menginstal/pasang boot.img yang sudah di-patch.\\n3. Salah memasukkan atau terdapat karakter spesial pada SuperKey.\\n4. Perangkat tidak mendukung APatch dan KernelPatch.\\n\\nCek dan coba kembali. Jika tetap gagal, dapat menanyakan pada laman permasalahan di repositori resmi kami.</string>\n    <string name=\"enable_web_debugging_summary\">Dapat digunakan untuk men-debug WebUI. Harap aktifkan hanya bila diperlukan.</string>\n    <string name=\"settings_donot_store_superkey_summary\">Autentikasi SuperKey setiap kali membuka manajer</string>\n    <string name=\"settings_donot_store_superkey\">Jangan simpan SuperKey secara lokal</string>\n    <string name=\"home_new_apatch_found\">Versi terbaru %s tersedia, klik untuk memperbarui.</string>\n    <string name=\"kpm_control_failed\">Operasi gagal!</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Beralih secara otomatis ke tema gelap berdasarkan bawaan sistem</string>\n    <string name=\"settings_night_theme_enabled\">Aktifkan tema gelap</string>\n    <string name=\"settings_use_system_color_theme\">Tema warna sistem</string>\n    <string name=\"settings_use_system_color_theme_summary\">Gunakan tema warna yang dihasilkan sistem berdasarkan wallpaper saat ini</string>\n    <string name=\"settings_custom_color_theme\">Warna tema</string>\n    <string name=\"red_theme\">Merah</string>\n    <string name=\"sakura_theme\">Merah muda sakura</string>\n    <string name=\"teal_theme\">Hijau kebiruan</string>\n    <string name=\"kpm_control_dialog_title\">KPModul Kontrol</string>\n    <string name=\"amber_theme\">Kuning ambar</string>\n    <string name=\"blue_grey_theme\">Biru abu-abu</string>\n    <string name=\"cyan_theme\">Sian</string>\n    <string name=\"deep_orange_theme\">Jingga gelap</string>\n    <string name=\"green_theme\">Hijau</string>\n    <string name=\"light_blue_theme\">Biru muda</string>\n    <string name=\"light_green_theme\">Hijau muda</string>\n    <string name=\"pink_theme\">Merah muda</string>\n    <string name=\"kpm_control\">Kontrol</string>\n    <string name=\"about_app_version\">Versi %1$s</string>\n    <string name=\"about_powered_by\">Didukung oleh %1$s</string>\n    <string name=\"blue_theme\">Biru</string>\n    <string name=\"brown_theme\">Cokelat</string>\n    <string name=\"lime_theme\">Limau</string>\n    <string name=\"orange_theme\">Jingga</string>\n    <string name=\"indigo_theme\">Nila</string>\n    <string name=\"purple_theme\">Ungu</string>\n    <string name=\"kpm_control_dialog_content\">Parameter kontrol input:</string>\n    <string name=\"kpm_control_ok\">Operasi berhasil!</string>\n    <string name=\"deep_purple_theme\">Ungu gelap</string>\n    <string name=\"yellow_theme\">Kuning</string>\n    <string name=\"about_telegram_channel\">Kanal Telegram</string>\n    <string name=\"about_app_desc\">Metode root dengan hanya menggunakan kernel image, memberikan kemampuan untuk memasang modul sistem dan mengaitkan fungsi kernel.</string>\n    <string name=\"about_telegram_group\">Grup Telegram</string>\n    <string name=\"kpm_control_paramters\">Parameter</string>\n    <string name=\"kpm_control_outMsg\">Pesan</string>\n    <string name=\"settings_night_mode_follow_sys\">Ikuti tema gelap dari sistem</string>\n    <string name=\"save_log\">Simpan log</string>\n    <string name=\"apm_action\">Tindakan</string>\n    <string name=\"log_saved\">Log disimpan</string>\n    <string name=\"crash_handle_copy\">Salin log kerusakan</string>\n    <string name=\"crash_handle_title\">Aplikasi telah berhenti…</string>\n    <string name=\"crash_handle_copied\">Log kerusakan telah disalin.</string>\n    <string name=\"settings_lite_mode\">Aktifkan Mode Lite</string>\n    <string name=\"settings_lite_mode_mode_summary\">APModule mungkin gagal berfungsi setelah diaktifkan, tapi terkadang masih tetap efektif dalam menghindari deteksi. Reboot diperlukan.</string>\n    <string name=\"settings_force_overlayfs_mode\">Penggunaan Paksa OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Jika kernel mendukung, APMount menggunakan OverlayFS dibandingkan MagicMount. Reboot dibutuhkan.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"apm_reboot_to_apply\">Riavvia per rendere effettive le modifiche</string>\n    <string name=\"android_patch\">Patch di Android</string>\n    <string name=\"kpm_unload_confirm\">Rimuovi modulo \\\"%s\\\"?</string>\n    <string name=\"apm_uninstall_success\">%s disinstallato</string>\n    <string name=\"send_log\">Invia registro</string>\n    <string name=\"apm_install\">Installa</string>\n    <string name=\"home_auth_key_desc\">Avvia dopo la certificazione</string>\n    <string name=\"kpatch_version\">Versione: %s</string>\n    <string name=\"apm_remove\">Rimuovi</string>\n    <string name=\"patch_warnning\">L\\'installazione comporta dei rischi. Assicurati che i tuoi dati siano stati salvati.</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch non installato</string>\n    <string name=\"home_patch_set_key_desc\">Credenziale solo per KernelPatch</string>\n    <string name=\"home_install_unknown\">Non installato o verificato</string>\n    <string name=\"apm_uninstall_confirm\">Disinstallare il modulo \\\"%s\\\"?</string>\n    <string name=\"su_pkg_excluded_setting_title\">Escludi modifiche</string>\n    <string name=\"reboot_download\">Riavvia in modalità Download</string>\n    <string name=\"home_click_to_learn_apatch\">Scopri le caratteristiche di APatch e come utilizzarlo</string>\n    <string name=\"apm_version\">Versione</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Abilita questa opzione per permettere ad APatch di ripristinare qualsiasi file modificato dai moduli per questa applicazione.</string>\n    <string name=\"reboot_edl\">Riavvia in modalità EDL</string>\n    <string name=\"home_installing\">Installazione in corso</string>\n    <string name=\"apm_start_downloading\">Download di %s avviato</string>\n    <string name=\"su_selinux_via_hook\">Aggira tramite hook</string>\n    <string name=\"home_ap_cando_uninstall\">Disinstalla</string>\n    <string name=\"apatch_version\">Versione: %s</string>\n    <string name=\"apm_overlay_fs_not_available\">I moduli non sono disponibili poiché OverlayFS è disabilitato dal kernel</string>\n    <string name=\"kpm_version\">Versione</string>\n    <string name=\"su_refresh\">Ricarica</string>\n    <string name=\"safe_mode\">Modalità provvisoria</string>\n    <string name=\"su_show_system_apps\">Mostra app di sistema</string>\n    <string name=\"home_ap_cando_install\">Installa</string>\n    <string name=\"reboot_recovery\">Riavvia in Recovery</string>\n    <string name=\"home_learn_apatch\">Scopri APatch</string>\n    <string name=\"apm_failed_to_disable\">Impossibile disabilitare il modulo \\\"%s\\\"</string>\n    <string name=\"kernel_patch\">Patch di Kernel</string>\n    <string name=\"home_click_to_install\">Clicca per installare</string>\n    <string name=\"home_selinux_status_unknown\">Sconosciuto</string>\n    <string name=\"about\">Informazioni</string>\n    <string name=\"reboot\">Riavvio completo</string>\n    <string name=\"home_need_update\">Nuova versione disponibile</string>\n    <string name=\"home_selinux_status\">Stato di SELinux</string>\n    <string name=\"apm_uninstall_failed\">Impossibile disinstallare %s</string>\n    <string name=\"kpm_author\">Autore</string>\n    <string name=\"apm_failed_to_enable\">Impossibile abilitare il modulo \\\"%s\\\"</string>\n    <string name=\"home\">Home</string>\n    <string name=\"patch_set_superkey\">Imposta Superchiave</string>\n    <string name=\"apm_downloading\">Download del modulo \\\"%s\\\" in corso…</string>\n    <string name=\"su_hide_system_apps\">Nascondi app di sistema</string>\n    <string name=\"apm_magisk_conflict\">I moduli non sono disponibili a causa di un conflitto con Magisk!</string>\n    <string name=\"home_ap_cando_update\">Aggiorna</string>\n    <string name=\"kpm_load_toast_failed\">Caricamento fallito</string>\n    <string name=\"home_selinux_status_disabled\">Spento</string>\n    <string name=\"settings\">Impostazioni</string>\n    <string name=\"apm_new_version_available\">Clicca per installare la nuova versione %s.</string>\n    <string name=\"apatch_version_update\">Versione: %s -&gt; %s</string>\n    <string name=\"home_working\">In esecuzione 😋</string>\n    <string name=\"apm_empty\">Nessun modulo installato</string>\n    <string name=\"kpm_load\">Carica</string>\n    <string name=\"home_patch_next_step\">Avanti</string>\n    <string name=\"home_auth_key_title\">Inserisci Superchiave</string>\n    <string name=\"apm_update\">Aggiorna</string>\n    <string name=\"home_not_installed\">Non installato</string>\n    <string name=\"kpm_license\">Licenza</string>\n    <string name=\"reboot_bootloader\">Riavvia in modalità Bootloader</string>\n    <string name=\"kpm_apm_empty\">Nessun modulo caricato</string>\n    <string name=\"about_source_code\">&lt;![CDATA[&lt;p&gt;Visualizza codice sorgente %1$s&lt;p/&gt; Unisci il nostro %2$s canale &lt;p/&gt; Unisci il nostro %3$s gruppo]]] &gt;</string>\n    <string name=\"home_manager_version\">Versione del gestore</string>\n    <string name=\"kpm_load_toast_succ\">Caricamento riuscito</string>\n    <string name=\"apm_author\">Autore</string>\n    <string name=\"su_pkg_excluded_label\">escludi</string>\n    <string name=\"su_title\">Superutente</string>\n    <string name=\"kpm_desc\">Descrizione</string>\n    <string name=\"kpm_args\">Argomenti</string>\n    <string name=\"home_fingerprint\">Impronta digitale</string>\n    <string name=\"apm_desc\">Descrizione</string>\n    <string name=\"kpm_unload\">Rimuovi</string>\n    <string name=\"home_kernel\">Versione Kernel</string>\n    <string name=\"home_selinux_status_enforcing\">Rinforzo</string>\n    <string name=\"patch_title\">Applica una patch</string>\n    <string name=\"home_apatch_version\">Versione di APatch</string>\n    <string name=\"home_selinux_status_permissive\">Permissivo</string>\n    <string name=\"apm_changelog\">Registro delle modifiche</string>\n    <string name=\"home_su_path\">Eseguibile su</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"super_key\">Superchiave</string>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"clear_super_key\">Elimina Superchiave</string>\n    <string name=\"apm_not_installed\">AndroidPatch non installato</string>\n    <string name=\"system_default\">Predefinito di sistema</string>\n    <string name=\"settings_app_language\">Lingua</string>\n    <string name=\"patch\">Applica una patch</string>\n    <string name=\"settings_global_namespace_mode\">Modalità namespace globale</string>\n    <string name=\"settings_global_namespace_mode_summary\">Tutte le sessioni di root erediteranno il namespace globale</string>\n    <string name=\"settings_check_update\">Controlla aggiornamenti</string>\n    <string name=\"home_ap_cando_reboot\">Riavvia</string>\n    <string name=\"patch_config_title\">Patch</string>\n    <string name=\"patch_mode_uninstall_patch\">Modalità: Disinstalla KPatch</string>\n    <string name=\"patch_item_bootimg_slot\">Slot:</string>\n    <string name=\"patch_embed_kpm_btn\">Incorpora KPM</string>\n    <string name=\"patch_mode_patch_and_install\">Modalità: Applica patch e installa</string>\n    <string name=\"mode_select_page_select_file\">Seleziona un’immagine di avvio a cui applicare la patch</string>\n    <string name=\"patch_item_kpimg_comile_time\">Tempo:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Descrizione:</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_kpimg\">Kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Versione:</string>\n    <string name=\"patch_item_new_extra_kpm\">Incorpora nuovo</string>\n    <string name=\"patch_item_existed_extra_kpm\">Esistito</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Il dispositivo sarà **FORZATO** ad avviarsi nello slot inattivo dopo il riavvio!\n\\nUsa questa opzione solo dopo l\\'OTA.\n\\nContinuare?</string>\n    <string name=\"home_dialog_auth_fail_title\">Autenticazione fallita</string>\n    <string name=\"home_system_version\">Versione di sistema</string>\n    <string name=\"home_install_unknown_summary\">Clicca per installare</string>\n    <string name=\"home_device_info\">Dispositivo</string>\n    <string name=\"home_kpatch_version\">Versione di KernelPatch</string>\n    <string name=\"kpm_add_kpm\">Aggiungi KPM</string>\n    <string name=\"hide_apatch_manager_summary\">Installa una nuova app di gestione con un ID pacchetto casuale e nome applicazione personalizzato</string>\n    <string name=\"setting_reset_su_new_path\">Nuovo percorso</string>\n    <string name=\"home_new_apatch_found\">Clicca per aggiornare alla nuova versione disponibile %s</string>\n    <string name=\"mode_select_page_title\">Installa</string>\n    <string name=\"mode_select_page_patch_and_install\">Applica patch e installa</string>\n    <string name=\"kpm_embed\">Incorpora</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Installa nello slot inattivo (dopo OTA)</string>\n    <string name=\"settings_donot_store_superkey\">Non memorizzare la SuperKey in locale</string>\n    <string name=\"patch_start_patch_btn\">Inizia</string>\n    <string name=\"kpatch_shadow_path_title\">Kpatch</string>\n    <string name=\"patch_item_kpimg_config\">Configurazione:</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nuovo nome del gestore</string>\n    <string name=\"settings_check_update_summary\">Cerca aggiornamenti automaticamente all\\'avvio dell\\'app</string>\n    <string name=\"patch_mode_install_to_next_slot\">Modalità: Installa nello slot successivo (Dopo OTA)</string>\n    <string name=\"enable_web_debugging\">Attiva debug di WebView</string>\n    <string name=\"settings_donot_store_superkey_summary\">Richiedi la SuperKey ogni volta che il gestore viene avviato</string>\n    <string name=\"patch_item_extra_version\">Versione:</string>\n    <string name=\"patch_item_extra_author\">Autore:</string>\n    <string name=\"patch_item_extra_event\">Evento:</string>\n    <string name=\"patch_item_extra_kpm_license\">Licenza:</string>\n    <string name=\"patch_item_bootimg_dev\">Dispositivo:</string>\n    <string name=\"patch_select_bootimg_btn\">Seleziona avvio</string>\n    <string name=\"hide_apatch_manager_failure\">Errore nel nascondere l\\'app, per favore segnala il bug!</string>\n    <string name=\"kpm_install\">Installa</string>\n    <string name=\"patch_item_extra_args\">Argomenti:</string>\n    <string name=\"patch_item_skey\">Super chiave</string>\n    <string name=\"hide_apatch_dialog_summary\">Sarà usato come nome dell\\'applicazione mostrato nel launcher</string>\n    <string name=\"failure\">Fallimento</string>\n    <string name=\"patch_item_bootimg\">Bootimg</string>\n    <string name=\"patch_start_unpatch_btn\">Rimuovi patch</string>\n    <string name=\"patch_item_set_skey_label\">La super chiave dovrebbe essere di almeno 8 caratteri e includere sia numeri sia lettere, ma non caratteri speciali</string>\n    <string name=\"setting_reset_su_path\">Reimposta il percorso su</string>\n    <string name=\"home_kpatch_info_title\">Informazioni</string>\n    <string name=\"settings_clear_super_key_dialog\">Sei sicuro di voler procedere?</string>\n    <string name=\"kpatch_version_update\">Versione: %s -&gt; %s</string>\n    <string name=\"apm_webui_open\">Apri</string>\n    <string name=\"enable_web_debugging_summary\">Può essere usato per il Debug di WebUI, attiva solo se necessario.</string>\n    <string name=\"patch_mode_bootimg_patch\">Modalità: Applica patch</string>\n    <string name=\"patch_item_error\">!!ERRORE!!</string>\n    <string name=\"patch_item_extra_name\">Nome:</string>\n    <string name=\"hide_apatch_manager\">Nascondi il gestore di APatch</string>\n    <string name=\"success\">Successo</string>\n    <string name=\"kpm_control_dialog_content\">Parametri di controllo dell\\'ingresso:</string>\n    <string name=\"kpm_control_ok\">Operazione riuscita!</string>\n    <string name=\"settings_night_mode_follow_sys\">Segui il Tema scuro di sistema</string>\n    <string name=\"home_dialog_auth_fail_content\">Impossibile autenticare la Super chiave, APatch non può funzionare correttamente.\\nEcco alcuni possibili motivi per il fallimento dell\\'autenticazione:\\n1. Non hai applicato la patch all\\'immagine di avvio con KernelPatch.\\n2. L\\'immagine di avvio con patch non è stata installata.\\n3. Errata Super chiave.\\n4. Il dispositivo non supporta APatch e KernelPatch.\\nControlla e riprova. Se ci sono ancora problemi, puoi sempre fare domande sulla pagina dei problemi del repository ufficiale.</string>\n    <string name=\"kpm_control_paramters\">Parametri</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Passa automaticamente al Tema scuro usando le impostazioni di sistema</string>\n    <string name=\"home_more_menu_about\">Chi siamo</string>\n    <string name=\"home_dialog_uninstall_title\">Disinstalla</string>\n    <string name=\"kpm_control\">Controllo</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Riscontro o suggerimento</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Rimuovi AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Disinstallare tutti</string>\n    <string name=\"kpm_control_dialog_title\">Controlla KPModule</string>\n    <string name=\"kpm_control_outMsg\">Messaggio</string>\n    <string name=\"kpm_control_failed\">Operazione fallita!</string>\n    <string name=\"settings_night_theme_enabled\">Abilita il Tema scuro</string>\n    <string name=\"settings_use_system_color_theme\">Colore del Tema di sistema</string>\n    <string name=\"settings_use_system_color_theme_summary\">Usa un colore generato dallo sfondo di sistema attuale</string>\n    <string name=\"settings_custom_color_theme\">Colore</string>\n    <string name=\"amber_theme\">Tema ambra</string>\n    <string name=\"blue_grey_theme\">Tema grigio blu</string>\n    <string name=\"blue_theme\">Tema blu</string>\n    <string name=\"brown_theme\">Tema marrone</string>\n    <string name=\"cyan_theme\">Tema ciano</string>\n    <string name=\"deep_orange_theme\">Tema arancione scuro</string>\n    <string name=\"deep_purple_theme\">Tema viola scuro</string>\n    <string name=\"green_theme\">Tema verde</string>\n    <string name=\"indigo_theme\">Tema indaco</string>\n    <string name=\"light_blue_theme\">Tema azzurro</string>\n    <string name=\"light_green_theme\">Tema verde chiaro</string>\n    <string name=\"lime_theme\">Tema lime</string>\n    <string name=\"orange_theme\">Tema arancione</string>\n    <string name=\"pink_theme\">Tema rosa</string>\n    <string name=\"purple_theme\">Tema viola</string>\n    <string name=\"red_theme\">Tema rosso</string>\n    <string name=\"sakura_theme\">Sakura</string>\n    <string name=\"teal_theme\">Tema verde acqua</string>\n    <string name=\"yellow_theme\">Tema giallo</string>\n    <string name=\"about_app_version\">Versione %1$s</string>\n    <string name=\"about_app_desc\">Soluzione Kernel Root con solo un\\'immagine del kernel ridotta, che offre la possibilità di montare il modulo di sistema e agganciare la funzione kernel.</string>\n    <string name=\"about_telegram_channel\">Canale Telegram</string>\n    <string name=\"about_telegram_group\">Gruppo Telegram</string>\n    <string name=\"save_log\">Salva registro</string>\n    <string name=\"about_powered_by\">Gestito da %1$s</string>\n    <string name=\"crash_handle_copied\">Copia contenuto del registro di arresto anomalo negli appunti</string>\n    <string name=\"log_saved\">Registri salvati</string>\n    <string name=\"crash_handle_title\">App chiusa in modo anomalo..</string>\n    <string name=\"crash_handle_copy\">Copia registro di arresto anomalo</string>\n    <string name=\"apm_action\">Azione</string>\n    <string name=\"settings_lite_mode\">Abilita la modalità Lite</string>\n    <string name=\"settings_lite_mode_mode_summary\">Le funzioni APModule potrebbero presentare errori dopo essere state abilitate, ma in alcuni casi possono comunque eludere efficacemente il rilevamento. Riavvio richiesto.</string>\n    <string name=\"settings_force_overlayfs_mode\">Forza l\\'uso di OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Utilizzare OverlayFS per montare gli APModuli invece di Magic Mount quando il supporto del kernel è disponibile. Riavviare il sistema.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">ホーム</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"kpm_unload_confirm\">モジュール \\\"%s\\\" をアンロードしますか？</string>\n    <string name=\"home_auth_key_desc\">認証後に開始</string>\n    <string name=\"patch_warnning\">インストールにはリスクが伴います。データがバックアップされていることを確認してください。</string>\n    <string name=\"home_patch_set_key_desc\">KernelPatch の資格情報のみ</string>\n    <string name=\"reboot_download\">ダウンロードモードへ再起動</string>\n    <string name=\"home_click_to_learn_apatch\">APatch の機能と使い方はこちら</string>\n    <string name=\"reboot_edl\">EDL モードへ再起動</string>\n    <string name=\"home_learn_apatch\">APatch について</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"home_need_update\">新しいバージョンが利用可能</string>\n    <string name=\"settings\">設定</string>\n    <string name=\"about_source_code\"><![CDATA[<p>%1$s でソースコードを表示<p>%2$s チャンネルに参加する<p/>%3$s グループに参加する]]></string>\n    <string name=\"home_manager_version\">アプリのバージョン</string>\n    <string name=\"reboot\">再起動</string>\n    <string name=\"reboot_recovery\">リカバリーへ再起動</string>\n    <string name=\"reboot_bootloader\">ブートローダーへ再起動</string>\n    <string name=\"safe_mode\">セーフモード</string>\n    <string name=\"about\">APatch について</string>\n    <string name=\"home_patch_next_step\">次へ</string>\n    <string name=\"home_not_installed\">未インストール</string>\n    <string name=\"send_log\">ログを送信</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"patch_set_superkey\">SuperKey を設定</string>\n    <string name=\"home_installing\">インストール中</string>\n    <string name=\"home_auth_key_title\">SuperKey を入力</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch はインストールされていません</string>\n    <string name=\"kpm_load\">ロード</string>\n    <string name=\"kpm_author\">著者</string>\n    <string name=\"kpm_desc\">説明</string>\n    <string name=\"su_title\">スーパーユーザー</string>\n    <string name=\"kpm_license\">ライセンス</string>\n    <string name=\"su_pkg_excluded_label\">除外</string>\n    <string name=\"apm_version\">バージョン</string>\n    <string name=\"apm_update\">アップデート</string>\n    <string name=\"home_install_unknown\">不明</string>\n    <string name=\"home_click_to_install\">タップしてインストール</string>\n    <string name=\"home_working\">動作中 😋</string>\n    <string name=\"home_ap_cando_install\">インストール</string>\n    <string name=\"home_ap_cando_update\">アップデート</string>\n    <string name=\"home_ap_cando_uninstall\">アンインストール</string>\n    <string name=\"home_kernel\">カーネル</string>\n    <string name=\"home_fingerprint\">Fingerprint</string>\n    <string name=\"home_selinux_status\">SELinux の状態</string>\n    <string name=\"home_selinux_status_unknown\">Unknown</string>\n    <string name=\"kpm_load_toast_succ\">ロード成功</string>\n    <string name=\"kpm_load_toast_failed\">ロード失敗</string>\n    <string name=\"kpm_version\">バージョン</string>\n    <string name=\"su_pkg_excluded_setting_summary\">このオプションを有効にすると、APatch はこのアプリのモジュールによって変更されたすべてのファイルを復元できるようになります。</string>\n    <string name=\"su_show_system_apps\">システムアプリを表示</string>\n    <string name=\"su_refresh\">更新</string>\n    <string name=\"apm_not_installed\">AndroidPatch はインストールされていません</string>\n    <string name=\"apm_remove\">アンインストール</string>\n    <string name=\"apm_install\">インストール</string>\n    <string name=\"apm_author\">制作者</string>\n    <string name=\"apm_desc\">説明</string>\n    <string name=\"apm_overlay_fs_not_available\">カーネルによって OverlayFS が無効なため、モジュールを使用できません。</string>\n    <string name=\"apm_reboot_to_apply\">再起動して適用する</string>\n    <string name=\"apm_changelog\">変更履歴</string>\n    <string name=\"kpatch_version\">バージョン: %s</string>\n    <string name=\"apatch_version\">バージョン: %s</string>\n    <string name=\"apatch_version_update\">バージョン: %s → %s</string>\n    <string name=\"home_su_path\">su</string>\n    <string name=\"home_selinux_status_disabled\">無効</string>\n    <string name=\"clear_super_key\">SuperKey を消去</string>\n    <string name=\"patch_title\">パッチ</string>\n    <string name=\"home_selinux_status_enforcing\">Enforcing</string>\n    <string name=\"su_pkg_excluded_setting_title\">変更の除外</string>\n    <string name=\"su_hide_system_apps\">システムアプリを非表示</string>\n    <string name=\"home_apatch_version\">APatch のバージョン</string>\n    <string name=\"home_selinux_status_permissive\">Permissive</string>\n    <string name=\"patch\">パッチ</string>\n    <string name=\"settings_app_language\">言語</string>\n    <string name=\"system_default\">システムのデフォルト</string>\n    <string name=\"settings_global_namespace_mode\">グローバル名前空間モード</string>\n    <string name=\"settings_global_namespace_mode_summary\">すべての root セッションはグローバルマウント名前空間を使用します</string>\n    <string name=\"kpm_args\">パラメータ</string>\n    <string name=\"kpm_apm_empty\">ロードされたモジュールはありません</string>\n    <string name=\"kpm_unload\">アンロード</string>\n    <string name=\"apm_empty\">インストールされたモジュールはありません</string>\n    <string name=\"settings_clear_super_key_dialog\">本当に続行しますか？</string>\n    <string name=\"kpatch_version_update\">バージョン: %s → %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_ap_cando_reboot\">再起動</string>\n    <string name=\"patch_config_title\">パッチ</string>\n    <string name=\"patch_mode_bootimg_patch\">モード: パッチ</string>\n    <string name=\"patch_mode_patch_and_install\">モード: パッチしてインストール</string>\n    <string name=\"patch_mode_uninstall_patch\">モード: KPatch をアンインストール</string>\n    <string name=\"patch_select_bootimg_btn\">boot.img を選択</string>\n    <string name=\"patch_start_unpatch_btn\">パッチ解除</string>\n    <string name=\"patch_embed_kpm_btn\">KPM を組み込む</string>\n    <string name=\"patch_start_patch_btn\">開始</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"apm_uninstall_confirm\">\\\"%s\\\" モジュールをアンインストールしますか？</string>\n    <string name=\"apm_uninstall_failed\">%s をアンインストールできませんでした</string>\n    <string name=\"apm_failed_to_disable\">\\\"%s\\\" モジュールをオフにできませんでした</string>\n    <string name=\"apm_new_version_available\">新しいバージョン %s が利用可能です。クリックしてアップグレードしてください。</string>\n    <string name=\"su_selinux_via_hook\">フックによるバイパス</string>\n    <string name=\"home_kpatch_info_title\">情報</string>\n    <string name=\"patch_item_error\">!!エラー!!</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_bootimg_dev\">デバイス:</string>\n    <string name=\"patch_item_kernel\">カーネル</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">バージョン:</string>\n    <string name=\"patch_item_bootimg_slot\">スロット:</string>\n    <string name=\"patch_item_extra_args\">引数:</string>\n    <string name=\"patch_item_extra_name\">名前:</string>\n    <string name=\"patch_item_extra_version\">バージョン:</string>\n    <string name=\"patch_item_new_extra_kpm\">新たに組み込む</string>\n    <string name=\"patch_item_existed_extra_kpm\">設定済</string>\n    <string name=\"patch_item_extra_event\">イベント:</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"patch_item_extra_author\">制作者:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">説明:</string>\n    <string name=\"patch_item_set_skey_label\">SuperKey の長さは 8 ～ 63 文字で、数字と文字を含めることができますが、特殊文字は使用できません。</string>\n    <string name=\"apm_failed_to_enable\">\\\"%s\\\" モジュールをオンにできませんでした</string>\n    <string name=\"apm_uninstall_success\">%s をアンインストールしました</string>\n    <string name=\"apm_start_downloading\">%s のダウンロードを開始</string>\n    <string name=\"apm_downloading\">\\\"%s\\\" モジュールをダウンロード中…</string>\n    <string name=\"apm_magisk_conflict\">Magisk と競合したためモジュールを使用できません。</string>\n    <string name=\"patch_item_kpimg_comile_time\">時間:</string>\n    <string name=\"patch_item_kpimg_config\">構成:</string>\n    <string name=\"patch_item_extra_kpm_license\">ライセンス:</string>\n    <string name=\"settings_check_update\">アップデートを確認</string>\n    <string name=\"hide_apatch_manager_summary\">ランダムなパッケージIDとカスタムアプリラベルでプロキシアプリをインストールする</string>\n    <string name=\"hide_apatch_manager\">APatchマネージャーを隠す</string>\n    <string name=\"settings_check_update_summary\">アプリを開いたときに自動でアップデートを確認する</string>\n    <string name=\"kpm_install\">インストール</string>\n    <string name=\"kpm_embed\">埋め込む</string>\n    <string name=\"hide_apatch_manager_failure\">アプリを隠すことに失敗しました。バグを報告してください</string>\n    <string name=\"home_install_unknown_summary\">タップしてインストール</string>\n    <string name=\"setting_reset_su_path\">su パスをリセット</string>\n    <string name=\"apm_webui_open\">開く</string>\n    <string name=\"patch_mode_install_to_next_slot\">モード: 非アクティブ スロットにインストール (OTA 後)</string>\n    <string name=\"home_device_info\">デバイス</string>\n    <string name=\"home_system_version\">システムのバージョン</string>\n    <string name=\"home_kpatch_version\">KernelPatch バージョン</string>\n    <string name=\"success\">成功</string>\n    <string name=\"failure\">失敗</string>\n    <string name=\"hide_apatch_dialog_summary\">これはランチャーに表示される新しいアプリ名として使用されます</string>\n    <string name=\"home_dialog_uninstall_all\">全てアンインストール</string>\n    <string name=\"kpm_add_kpm\">KPM を追加</string>\n    <string name=\"kpm_control\">コントロール</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">新しいマネージャー名</string>\n    <string name=\"setting_reset_su_new_path\">新しいフルパス</string>\n    <string name=\"enable_web_debugging\">WebView デバッグを有効</string>\n    <string name=\"settings_donot_store_superkey_summary\">マネージャーの起動時に SuperKey を認証します</string>\n    <string name=\"home_new_apatch_found\">新バージョンが利用可能です: %s タップしてアップデート</string>\n    <string name=\"mode_select_page_title\">インストール</string>\n    <string name=\"enable_web_debugging_summary\">Web UI のデバッグに使用できます。必要な場合のみ有効にしてください。</string>\n    <string name=\"mode_select_page_patch_and_install\">パッチをしてインストール</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">デバイスは再起動後、**強制的に**アクティブでないスロットにブートされます。\n\\nこのオプションは、OTA が完了した後のみ使用してください。\n\\n続行しますか？</string>\n    <string name=\"home_dialog_auth_fail_content\">SuperKey の認証に失敗したため、APatchは正しく動作しません。 \\n以下の理由が考えられます: \\n1. KernelPatch で\\\"boot.img\\\"をパッチしていない。 \\n2. パッチを適用した\\\"boot.img\\\"をフラッシュしていない。 \\n3. SuperKey が間違っている。 \\n4. デバイスが APatch と KernelPatch に対応していない。 \\n \\n再度確認して、もう一度お試しください。問題が解決しない場合は、公式リポジトリの Issue ページで質問をして下さい。</string>\n    <string name=\"home_dialog_uninstall_ap_only\">APatch をアンインストール</string>\n    <string name=\"mode_select_page_select_file\">パッチするブートイメージを選択</string>\n    <string name=\"mode_select_page_install_inactive_slot\">非アクティブなスロットにインストール (OTA 後)</string>\n    <string name=\"home_dialog_auth_fail_title\">認証失敗</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">フィードバック / 提案</string>\n    <string name=\"home_dialog_uninstall_title\">アンインストール</string>\n    <string name=\"kpm_control_dialog_title\">KPModule の管理</string>\n    <string name=\"kpm_control_paramters\">パラメータ</string>\n    <string name=\"settings_night_theme_enabled\">ダークテーマを有効化</string>\n    <string name=\"blue_theme\">ブルー</string>\n    <string name=\"brown_theme\">ブラウン</string>\n    <string name=\"deep_orange_theme\">ディープオレンジ</string>\n    <string name=\"cyan_theme\">シアン</string>\n    <string name=\"deep_purple_theme\">ディープパープル</string>\n    <string name=\"light_green_theme\">ライトグリーン</string>\n    <string name=\"lime_theme\">ライム</string>\n    <string name=\"indigo_theme\">インディゴ</string>\n    <string name=\"light_blue_theme\">ライトブルー</string>\n    <string name=\"purple_theme\">パープル</string>\n    <string name=\"save_log\">ログを保存</string>\n    <string name=\"settings_donot_store_superkey\">ローカルにスーパーキーを保存しない</string>\n    <string name=\"home_more_menu_about\">APatch について</string>\n    <string name=\"settings_use_system_color_theme\">ダイナミックテーマ</string>\n    <string name=\"settings_night_mode_follow_sys\">システムテーマに従う</string>\n    <string name=\"settings_custom_color_theme\">カラーテーマ</string>\n    <string name=\"amber_theme\">アンバー</string>\n    <string name=\"blue_grey_theme\">ブルーグレー</string>\n    <string name=\"green_theme\">グリーン</string>\n    <string name=\"orange_theme\">オレンジ</string>\n    <string name=\"pink_theme\">ピンク</string>\n    <string name=\"red_theme\">レッド</string>\n    <string name=\"sakura_theme\">サクラ</string>\n    <string name=\"teal_theme\">ティール</string>\n    <string name=\"yellow_theme\">イエロー</string>\n    <string name=\"about_app_version\">バージョン %1$s</string>\n    <string name=\"about_telegram_channel\">Telegram チャンネル</string>\n    <string name=\"about_telegram_group\">Telegram グループ</string>\n    <string name=\"about_powered_by\">Powered by %1$s</string>\n    <string name=\"kpm_control_ok\">操作は成功しました！</string>\n    <string name=\"kpm_control_outMsg\">メッセージ</string>\n    <string name=\"kpm_control_failed\">操作は失敗しました！</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">システム設定を元に自動でダークテーマに切り替える</string>\n    <string name=\"settings_use_system_color_theme_summary\">現在設定している壁紙からシステムによって生成されたカラーテーマを使用する</string>\n    <string name=\"about_app_desc\">削除されたカーネルイメージのみを持つカーネルルートソリューションは、システムモジュールをマウントし、カーネル機能をフックする機能を提供します。</string>\n    <string name=\"kpm_control_dialog_content\">入力制御変数:</string>\n    <string name=\"apm_action\">アクション</string>\n    <string name=\"log_saved\">ログを保存しました</string>\n    <string name=\"crash_handle_copy\">クラッシュログをコピー</string>\n    <string name=\"crash_handle_copied\">クラッシュ ログをクリップボードにコピーしました。</string>\n    <string name=\"crash_handle_title\">アプリがクラッシュしました。</string>\n    <string name=\"settings_lite_mode\">Liteモードを有効にする</string>\n    <string name=\"settings_lite_mode_mode_summary\">APModuleの機能は、有効化された後に障害を示すことがあるが、場合によっては検出を効果的に回避することができる。再起動が必要です。</string>\n    <string name=\"settings_force_overlayfs_mode\">OverlayFSの使用を強制する</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">カーネルのサポートが利用可能な場合、Magic Mountの代わりにOverlayFSを使用してAPModuleをマウントする。再起動が必要です。</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-jv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot\">Reboot</string>\n    <string name=\"settings\">Aturan</string>\n    <string name=\"reboot_download\">Mbalek nang Donlot</string>\n    <string name=\"about_source_code\">Delok kode sumber nang %1$s%1$sGabong saluran %2$s awakdewe</string>\n    <string name=\"send_log\">Kirem catatan</string>\n    <string name=\"clear_super_key\">Apos Kunci</string>\n    <string name=\"patch_set_superkey\">Set SuperKey</string>\n    <string name=\"home\">Omah</string>\n    <string name=\"patch_warnning\">Tindakan bahaya lur, backup data mu disek.</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"reboot_recovery\">Mbalek nang Recovery</string>\n    <string name=\"reboot_bootloader\">Mbalek nang Bootloader</string>\n    <string name=\"reboot_edl\">Mbalek nang EDL</string>\n    <string name=\"about\">Tentang</string>\n    <string name=\"home_learn_apatch\">Sinau AndroidPatch</string>\n    <string name=\"home_click_to_learn_apatch\">Sinau fitur AndroidPatch lan coro ngunakno</string>\n    <string name=\"safe_mode\">Mode aman</string>\n    <string name=\"super_key\">SuperKey</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">홈</string>\n    <string name=\"patch_warnning\">설치에는 위험이 따릅니다. 데이터가 백업되었는지 확인하세요.</string>\n    <string name=\"patch\">패치</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot\">재시작</string>\n    <string name=\"settings\">설정</string>\n    <string name=\"reboot_bootloader\">부트로더로 재시작</string>\n    <string name=\"reboot_download\">다운로드 모드로 재부팅</string>\n    <string name=\"reboot_edl\">EDL로 재시작</string>\n    <string name=\"about\">정보</string>\n    <string name=\"settings_app_language\">언어</string>\n    <string name=\"home_patch_set_key_desc\">KernelPatch용 자격 증명</string>\n    <string name=\"home_patch_next_step\">다음 단계</string>\n    <string name=\"home_not_installed\">설치되지 않음</string>\n    <string name=\"home_install_unknown\">설치되지 않았거나 인증되지 않음</string>\n    <string name=\"home_click_to_install\">클릭하여 설치</string>\n    <string name=\"home_working\">작동 중 😋</string>\n    <string name=\"home_installing\">설치 중</string>\n    <string name=\"home_need_update\">새 버전 사용 가능</string>\n    <string name=\"kpatch_version\">버전: %s</string>\n    <string name=\"apatch_version\">버전: %s</string>\n    <string name=\"apatch_version_update\">버전: %s -&gt; %s</string>\n    <string name=\"home_su_path\">실행 가능한 su</string>\n    <string name=\"home_apatch_version\">APatch 버전</string>\n    <string name=\"home_auth_key_title\">SuperKey 입력</string>\n    <string name=\"home_auth_key_desc\">인증 후 시작하기</string>\n    <string name=\"home_ap_cando_install\">설치</string>\n    <string name=\"home_ap_cando_update\">업데이트</string>\n    <string name=\"home_ap_cando_uninstall\">제거</string>\n    <string name=\"home_kernel\">커널</string>\n    <string name=\"home_manager_version\">매니저 앱 버전</string>\n    <string name=\"home_fingerprint\">지문</string>\n    <string name=\"home_selinux_status\">SELinux 상태</string>\n    <string name=\"home_selinux_status_disabled\">끄기</string>\n    <string name=\"home_selinux_status_enforcing\">강제</string>\n    <string name=\"home_selinux_status_permissive\">허용</string>\n    <string name=\"home_selinux_status_unknown\">알 수 없음</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch가 설치되지 않았습니다</string>\n    <string name=\"kpm_load\">불러오기</string>\n    <string name=\"kpm_load_toast_failed\">불러오기 실패</string>\n    <string name=\"kpm_unload\">제거</string>\n    <string name=\"kpm_apm_empty\">불러온 모듈이 없습니다</string>\n    <string name=\"kpm_version\">버전</string>\n    <string name=\"kpm_license\">라이선스</string>\n    <string name=\"kpm_author\">제작자</string>\n    <string name=\"su_pkg_excluded_setting_summary\">이 옵션을 활성화하면 APatch가 이 어플리케이션에 대한 모듈에 의해 수정된 파일을 복원할 수 있습니다.</string>\n    <string name=\"su_show_system_apps\">시스템 앱 표시</string>\n    <string name=\"su_hide_system_apps\">시스템 앱 숨기기</string>\n    <string name=\"su_refresh\">새로 고침</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"apm_failed_to_disable\">\\\"%s\\\" 모듈을 끌 수 없습니다</string>\n    <string name=\"apm_empty\">설치된 모듈이 없습니다</string>\n    <string name=\"apm_remove\">제거</string>\n    <string name=\"apm_install\">설치</string>\n    <string name=\"apm_uninstall_confirm\">\\\"%s\\\" 모듈을 제거하시겠습니까?</string>\n    <string name=\"apm_uninstall_success\">%s이 제거되었습니다</string>\n    <string name=\"apm_uninstall_failed\">%s 을 제거하지 못했습니다</string>\n    <string name=\"apm_version\">버전</string>\n    <string name=\"apm_author\">제작자</string>\n    <string name=\"apm_overlay_fs_not_available\">커널에 의해 OverlayFS가 비활성화되어 모듈을 사용할 수 없습니다.</string>\n    <string name=\"system_default\">시스템 기본값</string>\n    <string name=\"home_click_to_learn_apatch\">APatch의 기능 및 사용 방법 알아보기</string>\n    <string name=\"about_source_code\"><![CDATA[<p>%1$s에서 소스 코드 보기.<p/>%2$s 채널 참여<p/>%3$s 그룹 참여]]></string>\n    <string name=\"safe_mode\">안전 모드</string>\n    <string name=\"kpm_load_toast_succ\">불러오기 성공</string>\n    <string name=\"home_learn_apatch\">APatch 알아보기</string>\n    <string name=\"send_log\">로그 보내기</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"clear_super_key\">SuperKey 지우기</string>\n    <string name=\"patch_set_superkey\">SuperKey 설정</string>\n    <string name=\"patch_title\">패치</string>\n    <string name=\"su_title\">슈퍼유저</string>\n    <string name=\"reboot_recovery\">리커버리로 재시작</string>\n    <string name=\"su_selinux_via_hook\">훅으로 우회하기</string>\n    <string name=\"kpm_unload_confirm\">\\\"%s\\\" 모듈을 제거하시겠습니까?</string>\n    <string name=\"su_pkg_excluded_label\">제외</string>\n    <string name=\"su_pkg_excluded_setting_title\">변경 제외</string>\n    <string name=\"apm_not_installed\">AndroidPatch가 설치되지 않음</string>\n    <string name=\"apm_failed_to_enable\">\\\"%s\\\" 모듈을 키지 못했습니다</string>\n    <string name=\"apm_magisk_conflict\">Magisk와 충돌이 발생해 모듈이 비활성화되었습니다.</string>\n    <string name=\"apm_reboot_to_apply\">적용하려면 재시작하세요</string>\n    <string name=\"apm_changelog\">변경 기록</string>\n    <string name=\"apm_update\">업데이트</string>\n    <string name=\"apm_downloading\">\\\"%s\\\"모듈 내려받는 중…</string>\n    <string name=\"apm_start_downloading\">%s 내려받기를 시작합니다</string>\n    <string name=\"apm_new_version_available\">새 버전 %s을 설치하려면 클릭하세요.</string>\n    <string name=\"kpm_desc\">설명</string>\n    <string name=\"kpm_args\">인수</string>\n    <string name=\"apm_desc\">설명</string>\n    <string name=\"settings_global_namespace_mode\">글로벌 네임스페이스 모드</string>\n    <string name=\"settings_global_namespace_mode_summary\">모든 루트 세션은 글로벌 마운트 세션을 사용합니다</string>\n    <string name=\"settings_check_update\">업데이트 확인</string>\n    <string name=\"settings_check_update_summary\">앱을 열 때 자동으로 업데이트 확인</string>\n    <string name=\"home_kpatch_info_title\">정보</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"patch_item_kpimg_comile_time\">시간:</string>\n    <string name=\"patch_mode_uninstall_patch\">모드: KPatch 제거</string>\n    <string name=\"patch_select_bootimg_btn\">boot 선택</string>\n    <string name=\"patch_item_existed_extra_kpm\">이미 있음</string>\n    <string name=\"patch_item_extra_name\">이름:</string>\n    <string name=\"patch_item_extra_kpm_license\">라이선스:</string>\n    <string name=\"patch_item_extra_author\">제작자:</string>\n    <string name=\"patch_item_set_skey_label\">Super Key의 길이는 숫자와 문자를 포함하여 8자리 이상이여야 합니다</string>\n    <string name=\"kpm_install\">설치</string>\n    <string name=\"kpm_embed\">통합</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">새 관리자 이름</string>\n    <string name=\"hide_apatch_manager_summary\">무작위 패키지 ID와 맞춤 이름으로 관리자 앱 설치하기</string>\n    <string name=\"patch_item_extra_kpm_desciption\">설명:</string>\n    <string name=\"home_new_apatch_found\">새 버전 사용 가능: %s, 업그레이드하려면 클릭하세요</string>\n    <string name=\"kpatch_version_update\">버전: %s -&gt; %s</string>\n    <string name=\"home_more_menu_about\">정보</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">피드백 또는 제안</string>\n    <string name=\"kpm_add_kpm\">KPM 추가</string>\n    <string name=\"home_install_unknown_summary\">클릭하여 설치</string>\n    <string name=\"mode_select_page_install_inactive_slot\">비활성 슬롯에 설치 (OTA 이후)</string>\n    <string name=\"mode_select_page_select_file\">패치할 boot 이미지 선택</string>\n    <string name=\"home_dialog_uninstall_title\">제거</string>\n    <string name=\"home_dialog_uninstall_all\">전부 제거</string>\n    <string name=\"patch_config_title\">패치</string>\n    <string name=\"patch_mode_patch_and_install\">모드: 패치 및 설치</string>\n    <string name=\"patch_item_extra_args\">인자:</string>\n    <string name=\"home_device_info\">장치</string>\n    <string name=\"home_kpatch_version\">KernelPatch 버전</string>\n    <string name=\"hide_apatch_manager\">APatch 관리자 숨기기</string>\n    <string name=\"hide_apatch_dialog_summary\">런처에서 보여질 이름으로 사용됩니다</string>\n    <string name=\"hide_apatch_manager_failure\">숨길 수 없습니다. 버그를 제보해주세요!</string>\n    <string name=\"settings_donot_store_superkey_summary\">관리자가 시작할 때마다 SuperKey를 인증합니다</string>\n    <string name=\"mode_select_page_patch_and_install\">패치 및 설치</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">재시작 후 기기가 비활성 슬롯으로 **강제** 부팅될 것 입니다!\n\\nOTA 이후에만 이 옵션을 사용하세요.\n\\n계속하시겠습니까?</string>\n    <string name=\"home_dialog_uninstall_ap_only\">AndroidPatch 제거</string>\n    <string name=\"home_ap_cando_reboot\">재시작</string>\n    <string name=\"patch_mode_bootimg_patch\">모드: 패치</string>\n    <string name=\"patch_mode_install_to_next_slot\">모드: 다음 를롯에 설치 (OTA 이후)</string>\n    <string name=\"patch_item_kpimg_config\">설정:</string>\n    <string name=\"patch_item_new_extra_kpm\">새로 통합</string>\n    <string name=\"patch_item_extra_version\">버전:</string>\n    <string name=\"patch_item_extra_event\">이벤트:</string>\n    <string name=\"patch_item_skey\">관리자 키</string>\n    <string name=\"home_system_version\">시스템 버전</string>\n    <string name=\"mode_select_page_title\">설치</string>\n    <string name=\"home_dialog_auth_fail_title\">인증 실패</string>\n    <string name=\"home_dialog_auth_fail_content\">SuperKey를 인증할 수 없어 APatch가 제대로 작동할 수 없습니다. \\n다음은 인증 실패의 몇 가지 가능한 이유입니다: \\n1. KernelPatch로 boot 이미지를 패치하지 않았습니다. \\n2. 패치한 boot 이미지를 플래시하지 않았습니다. \\n3. SuperKey가 틀림. \\n4. 장치가 Apatch와 KernelPatch를 지원하지 않습니다. \\n \\n확인 후 다시 시도해주세요. 여전히 문제가 있는 경우 공식 repository의 issues 페이지에서 언제든지 질문할 수 있습니다.</string>\n    <string name=\"patch_item_kernel\">커널</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">버전:</string>\n    <string name=\"patch_embed_kpm_btn\">KPM 통합</string>\n    <string name=\"patch_start_patch_btn\">시작</string>\n    <string name=\"patch_start_unpatch_btn\">패치 해제</string>\n    <string name=\"patch_item_error\">!!오류!!</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_bootimg_slot\">슬롯:</string>\n    <string name=\"patch_item_bootimg_dev\">장치:</string>\n    <string name=\"setting_reset_su_path\">su 경로 초기화</string>\n    <string name=\"apm_webui_open\">열기</string>\n    <string name=\"enable_web_debugging\">WebView 디버깅 활성화</string>\n    <string name=\"enable_web_debugging_summary\">WebUI를 디버그할 때 사용할 수 있습니다. 필요한 경우에만 활성화하세요.</string>\n    <string name=\"settings_donot_store_superkey\">기기에 SuperKey 저장하지 않기</string>\n    <string name=\"success\">성공</string>\n    <string name=\"failure\">실패</string>\n    <string name=\"settings_clear_super_key_dialog\">정말로 계속하시겠습니까?</string>\n    <string name=\"kpm_control_dialog_title\">KPModule 제어</string>\n    <string name=\"kpm_control_dialog_content\">제어 매개 변수 입력:</string>\n    <string name=\"kpm_control\">제어</string>\n    <string name=\"kpm_control_paramters\">매개변수</string>\n    <string name=\"kpm_control_outMsg\">메시지</string>\n    <string name=\"setting_reset_su_new_path\">새 전체 경로</string>\n    <string name=\"kpm_control_ok\">작업 성공!</string>\n    <string name=\"kpm_control_failed\">작업 실패!</string>\n    <string name=\"settings_night_mode_follow_sys\">시스템의 어두운 테마 따르기</string>\n    <string name=\"amber_theme\">등색 테마</string>\n    <string name=\"settings_use_system_color_theme\">시스템 색상 테마</string>\n    <string name=\"settings_use_system_color_theme_summary\">시스템이 현재 배경화면으로 생성한 색상 테마 사용</string>\n    <string name=\"settings_custom_color_theme\">색상 테마</string>\n    <string name=\"blue_grey_theme\">블루그레이 테마</string>\n    <string name=\"blue_theme\">블루 테마</string>\n    <string name=\"about_app_desc\">제거된 커널 이미지만 있는 커널 루트 솔루션으로, 시스템 모듈을 마운트하고 커널 기능을 후크하는 기능을 제공합니다.</string>\n    <string name=\"about_powered_by\">%1$s로 구동됨</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">시스템 설정에 따라 자동으로 어두운 테마로 전환</string>\n    <string name=\"settings_night_theme_enabled\">어두운 테마 사용</string>\n    <string name=\"brown_theme\">브라운 테마</string>\n    <string name=\"cyan_theme\">청록색 테마</string>\n    <string name=\"deep_orange_theme\">진한 오렌지 테마</string>\n    <string name=\"deep_purple_theme\">진한 퍼플 테마</string>\n    <string name=\"green_theme\">그린 테마</string>\n    <string name=\"indigo_theme\">남색 테마</string>\n    <string name=\"light_blue_theme\">라이트 블루 테마</string>\n    <string name=\"light_green_theme\">라이트 그린 테마</string>\n    <string name=\"lime_theme\">라임 테마</string>\n    <string name=\"orange_theme\">오렌지 테마</string>\n    <string name=\"pink_theme\">핑크 테마</string>\n    <string name=\"purple_theme\">퍼플 테마</string>\n    <string name=\"red_theme\">레드 테마</string>\n    <string name=\"sakura_theme\">벚꽃 테마</string>\n    <string name=\"teal_theme\">청록색 테마</string>\n    <string name=\"yellow_theme\">옐로우 테마</string>\n    <string name=\"about_app_version\">버전 %1$s</string>\n    <string name=\"about_telegram_channel\">Telegram 채널</string>\n    <string name=\"about_telegram_group\">Telegram 그룹</string>\n    <string name=\"save_log\">로그 저장</string>\n    <string name=\"log_saved\">로그 저장됨</string>\n    <string name=\"crash_handle_title\">앱 충돌됨...</string>\n    <string name=\"crash_handle_copy\">충돌 로그 복사</string>\n    <string name=\"apm_action\">동작</string>\n    <string name=\"crash_handle_copied\">충돌 로그가 클립보드에 복사됨.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-lt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"patch_warnning\">Diegimas rizikingas. Patikrinkite, kad turite atsarginę duomenų kopiją.</string>\n    <string name=\"failure\">Klaida</string>\n    <string name=\"reboot\">Perkrauti</string>\n    <string name=\"home\">Pagrindinis ekranas</string>\n    <string name=\"success\">Pavyko</string>\n    <string name=\"settings\">Nustatymai</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"success\">Veiksmīgi</string>\n    <string name=\"patch\">Ielāps</string>\n    <string name=\"reboot\">Restartēt</string>\n    <string name=\"settings\">Iestatījumi</string>\n    <string name=\"reboot_recovery\">Restartēt uz Atkopšanas režīmu</string>\n    <string name=\"reboot_download\">Restartēt uz Lejupielādes režīmu</string>\n    <string name=\"about\">Par lietotni</string>\n    <string name=\"home\">Sākums</string>\n    <string name=\"reboot_bootloader\">Restartēt uz Sāknēšanas režīmu</string>\n    <string name=\"reboot_edl\">Restartēt uz EDL režīmu</string>\n    <string name=\"settings_app_language\">Valoda</string>\n    <string name=\"safe_mode\">Drošais režīms</string>\n    <string name=\"home_installing\">Uzstāda</string>\n    <string name=\"home_not_installed\">Nav uzstādīts</string>\n    <string name=\"home_need_update\">Pieejama jauna versija</string>\n    <string name=\"kpatch_version\">Versija: %s</string>\n    <string name=\"apatch_version\">Versija: %s</string>\n    <string name=\"home_ap_cando_install\">Uzstādīt</string>\n    <string name=\"home_ap_cando_update\">Atjaunināt</string>\n    <string name=\"home_ap_cando_uninstall\">Noņemt</string>\n    <string name=\"home_ap_cando_reboot\">Restartēt</string>\n    <string name=\"patch_item_bootimg_dev\">ierīce:</string>\n    <string name=\"patch_item_kernel\">Kodols</string>\n    <string name=\"patch_item_kpimg_version\">Versija:</string>\n    <string name=\"patch_item_extra_name\">Nosaukums:</string>\n    <string name=\"patch_item_extra_version\">Versija:</string>\n    <string name=\"patch_item_extra_kpm_license\">Licence:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Apraksts:</string>\n    <string name=\"apm_remove\">Noņemt</string>\n    <string name=\"apm_update\">Atjaunināt</string>\n    <string name=\"cyan_theme\">Ciāna</string>\n    <string name=\"green_theme\">Zaļš</string>\n    <string name=\"light_blue_theme\">Gaiši zils</string>\n    <string name=\"pink_theme\">Rozā</string>\n    <string name=\"red_theme\">Sarkans</string>\n    <string name=\"teal_theme\">Tumši ciāna (Zilganzaļa)</string>\n    <string name=\"home_device_info\">Ierīce</string>\n    <string name=\"blue_theme\">Zils</string>\n    <string name=\"apm_changelog\">Izmaiņu žurnāls</string>\n    <string name=\"kpm_version\">Versija</string>\n    <string name=\"su_refresh\">Atsvaidzināt</string>\n    <string name=\"home_more_menu_about\">Par lietotni</string>\n    <string name=\"light_green_theme\">Gaiši zaļš</string>\n    <string name=\"kpm_license\">Licence</string>\n    <string name=\"apm_version\">Versija</string>\n    <string name=\"home_selinux_status_unknown\">Nezināms</string>\n    <string name=\"apm_webui_open\">Atvērt</string>\n    <string name=\"apm_install\">Uzstādīt</string>\n    <string name=\"mode_select_page_title\">Uzstādīt</string>\n    <string name=\"home_dialog_uninstall_title\">Noņemt</string>\n    <string name=\"brown_theme\">Brūns</string>\n    <string name=\"deep_orange_theme\">Tumši oranžs</string>\n    <string name=\"deep_purple_theme\">Tumši violets</string>\n    <string name=\"orange_theme\">Oranžs</string>\n    <string name=\"purple_theme\">Violets</string>\n    <string name=\"kpm_control_outMsg\">Ziņojums</string>\n    <string name=\"kpm_install\">Uzstādīt</string>\n    <string name=\"system_default\">Sistēmas noklusējuma</string>\n    <string name=\"patch_item_extra_author\">Izstrādātājs:</string>\n    <string name=\"home_selinux_status\">SELinux statuss</string>\n    <string name=\"home_selinux_status_disabled\">Atspējots</string>\n    <string name=\"home_apatch_version\">APatch versija</string>\n    <string name=\"kpm_load\">Ielādēt</string>\n    <string name=\"kpm_load_toast_succ\">Veiksmīgi ielādēts</string>\n    <string name=\"kpm_load_toast_failed\">Neizdevās ielādēt</string>\n    <string name=\"su_pkg_excluded_label\">izslēgt, neiekļaut</string>\n    <string name=\"home_manager_version\">Pārvaldnieka versija</string>\n    <string name=\"kpm_author\">Izstrādātājs</string>\n    <string name=\"apm_author\">Izstrādātājs</string>\n    <string name=\"yellow_theme\">Dzeltens</string>\n    <string name=\"about_app_version\">Versija %1$s</string>\n    <string name=\"lime_theme\">Dzeltenzaļa, laima</string>\n    <string name=\"settings_check_update\">Pārbaudīt atjauninājumu</string>\n    <string name=\"settings_clear_super_key_dialog\">Vai tiešām vēlaties turpināt?</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-ms/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">Halaman Utama</string>\n    <string name=\"patch_warnning\">Pemasangan datang dengan risiko. Sila pastikan anda telah membuat sandaran data.</string>\n    <string name=\"reboot\">But semula (Reboot)</string>\n    <string name=\"settings\">Tetapan</string>\n    <string name=\"about\">Perihal</string>\n    <string name=\"home_learn_apatch\">Ketahui tentang APatch</string>\n    <string name=\"reboot_recovery\">But semula ke Recovery</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot_bootloader\">But semula ke Bootloader</string>\n    <string name=\"reboot_download\">But semula ke Download</string>\n    <string name=\"reboot_edl\">But semula ke EDL</string>\n    <string name=\"about_source_code\">Lihat kod sumber di %1$s<br/>Sertai saluran kami di %2$s</string>\n    <string name=\"send_log\">Hantar log</string>\n    <string name=\"safe_mode\">Safe mode</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"clear_super_key\">Clear Key</string>\n    <string name=\"settings_app_language\">Bahasa</string>\n    <string name=\"home_click_to_learn_apatch\">Ketahui tentang ciri-ciri APatch dan cara menggunakannya</string>\n    <string name=\"system_default\">Lalai sistem</string>\n    <string name=\"home_installing\">Memasang</string>\n    <string name=\"apatch_version_update\">Versi: %s -&gt; %s</string>\n    <string name=\"home_patch_next_step\">Langkah Seterusnya</string>\n    <string name=\"home_not_installed\">Tidak di pasang</string>\n    <string name=\"home_install_unknown\">Tidak diketahui</string>\n    <string name=\"home_click_to_install\">Tekan untuk pasang</string>\n    <string name=\"home_need_update\">Versi baharu tersedia</string>\n    <string name=\"kpatch_version\">Versi: %s</string>\n    <string name=\"apatch_version\">Versi: %s</string>\n    <string name=\"home_install_unknown_summary\">Tekan untuk pasang</string>\n    <string name=\"success\">Berjaya</string>\n    <string name=\"failure\">Gagal</string>\n    <string name=\"settings_global_namespace_mode\">Mod ruang nama global</string>\n    <string name=\"settings_clear_super_key_dialog\">Adakah anda benar-benar mahu meneruskan?</string>\n    <string name=\"settings_check_update\">Semak kemas kini</string>\n    <string name=\"settings_check_update_summary\">Semak kemas kini secara automatik apabila membuka aplikasi</string>\n    <string name=\"kpm_desc\">Penerangan</string>\n    <string name=\"patch_item_error\">!!RALAT!!</string>\n    <string name=\"patch_start_unpatch_btn\">Menanggalkan tampalan</string>\n    <string name=\"patch_item_bootimg\">Memuat semula</string>\n    <string name=\"kpm_license\">Lesen</string>\n    <string name=\"kpm_author\">Pengarang</string>\n    <string name=\"save_log\">Simpan Log</string>\n    <string name=\"patch_set_superkey\">Tetapkan SuperKey</string>\n    <string name=\"home_patch_set_key_desc\">Hanya kelayakan untuk KernelPatch</string>\n    <string name=\"home_working\">Sedang bekerja 😋</string>\n    <string name=\"kpatch_version_update\">Versi: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_auth_key_title\">Masukkan SuperKey</string>\n    <string name=\"home_auth_key_desc\">Mula selepas pengesahan</string>\n    <string name=\"home_kpatch_info_title\">Info</string>\n    <string name=\"home_ap_cando_install\">Memuat turun</string>\n    <string name=\"home_ap_cando_update\">Kemas kini</string>\n    <string name=\"home_ap_cando_uninstall\">Nyahpasang</string>\n    <string name=\"home_ap_cando_reboot\">Mula semula</string>\n    <string name=\"patch_title\">Tampalan</string>\n    <string name=\"patch_config_title\">Tampalan</string>\n    <string name=\"patch_mode_bootimg_patch\">Mod: Tampalan</string>\n    <string name=\"patch_mode_patch_and_install\">Mod: Tampalan dan memuat turun</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mod: Memuat turun pada slot seterusnya (selepas OTA)</string>\n    <string name=\"patch_mode_uninstall_patch\">Mod: Memadam ktampalan</string>\n    <string name=\"patch_select_bootimg_btn\">Pilih mula semula</string>\n    <string name=\"patch_embed_kpm_btn\">Benamkan KPM</string>\n    <string name=\"patch_start_patch_btn\">Mula</string>\n    <string name=\"patch_item_bootimg_slot\">slot:</string>\n    <string name=\"kpm_version\">Versi</string>\n    <string name=\"patch\">tampalan</string>\n    <string name=\"apm_uninstall_failed\">APatch</string>\n    <string name=\"apm_uninstall_success\">APatch</string>\n    <string name=\"apm_install\">APatch</string>\n    <string name=\"apm_version\">Versi</string>\n    <string name=\"apm_update\">Kemas kini</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-nb-rNO/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"apm_desc\">Beskrivelse</string>\n    <string name=\"home\">Hjem</string>\n    <string name=\"kernel_patch\">Kjerneoppdatering</string>\n    <string name=\"settings\">Innstillinger</string>\n    <string name=\"about\">Om</string>\n    <string name=\"android_patch\">Android oppdatering</string>\n    <string name=\"reboot\">Omstart</string>\n    <string name=\"reboot_recovery\">Omstart til gjenoppretting</string>\n    <string name=\"reboot_bootloader\">Omstart til oppstartslaster</string>\n    <string name=\"reboot_edl\">Omstart til EDL</string>\n    <string name=\"home_learn_apatch\">Lær deg APatch</string>\n    <string name=\"send_log\">Send loggen</string>\n    <string name=\"home_click_to_learn_apatch\">Lær mer om funksjonene i AndroidPatch og hvordan det brukes</string>\n    <string name=\"safe_mode\">Trygt modus</string>\n    <string name=\"home_patch_next_step\">Neste steg</string>\n    <string name=\"home_click_to_install\">Klikk for å installere</string>\n    <string name=\"home_working\">Arbeider</string>\n    <string name=\"home_installing\">Installerer</string>\n    <string name=\"home_need_update\">Ny versjon tilgjengelig</string>\n    <string name=\"kpatch_version\">Versjon: %s</string>\n    <string name=\"apatch_version_update\">Versjon: %s → %s</string>\n    <string name=\"home_su_path\">su: %s</string>\n    <string name=\"home_auth_key_desc\">Start kjøring etter sertifisering</string>\n    <string name=\"home_ap_cando_install\">Installer</string>\n    <string name=\"home_kernel\">Kjerne</string>\n    <string name=\"home_ap_cando_update\">Oppdater</string>\n    <string name=\"patch_title\">Feilfiks</string>\n    <string name=\"home_manager_version\">Manager-versjon</string>\n    <string name=\"home_selinux_status_unknown\">Ukjent</string>\n    <string name=\"kpm_load\">Last inn</string>\n    <string name=\"kpm_load_toast_succ\">Innlastet</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch ikke installert</string>\n    <string name=\"kpm_author\">Utvikler</string>\n    <string name=\"kpm_desc\">Beskrivelse</string>\n    <string name=\"kpm_args\">Argumenter</string>\n    <string name=\"apm_remove\">Avinstaller</string>\n    <string name=\"home_ap_cando_uninstall\">Avinstaller</string>\n    <string name=\"home_fingerprint\">Fingeravtrykk</string>\n    <string name=\"home_selinux_status_enforcing\">Påtvingende</string>\n    <string name=\"home_selinux_status\">SELinux-status</string>\n    <string name=\"kpm_version\">Versjon</string>\n    <string name=\"home_selinux_status_disabled\">Deaktivert</string>\n    <string name=\"kpm_license\">Lisens</string>\n    <string name=\"su_title\">Superbruker</string>\n    <string name=\"su_show_system_apps\">Vis systemprogrammer</string>\n    <string name=\"apm_install\">Installer</string>\n    <string name=\"apm_author\">Utvikler</string>\n    <string name=\"su_refresh\">Gjenoppfrisk</string>\n    <string name=\"apm_uninstall_success\">%s avinstallert</string>\n    <string name=\"apm_version\">Versjon</string>\n    <string name=\"apm_changelog\">Endringslogg</string>\n    <string name=\"home_not_installed\">Ikke installert</string>\n    <string name=\"home_install_unknown\">Ukjent</string>\n    <string name=\"apm_start_downloading\">Start nedlasting: %s</string>\n    <string name=\"apatch_version\">Versjon: %s</string>\n    <string name=\"kpm_load_toast_failed\">Innlasting mislyktes</string>\n    <string name=\"patch_warnning\">Installasjon medfører risiko. Forsikre deg om at dataen din er sikkerhetskopiert.</string>\n    <string name=\"reboot_download\">Start på nytt for å laste ned</string>\n    <string name=\"about_source_code\"><![CDATA[<p> Vis kildekoden %1$s<p/> Bli med på %2$s kanalen vår <p/> Bli med i%3$s igruppa vår]]></string>\n    <string name=\"kpm_unload_confirm\">Vil du laste ut modulen «%s»?</string>\n    <string name=\"home_apatch_version\">APatch: %s</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Hvis du aktiverer dette alternativet, kan APatch gjenopprette filer som er endret av modulene i denne appen.</string>\n    <string name=\"su_pkg_excluded_setting_title\">Ekskluder modifikasjoner</string>\n    <string name=\"home_selinux_status_permissive\">Tilforlatelig</string>\n    <string name=\"kpm_apm_empty\">Ingen modul innlastet</string>\n    <string name=\"su_hide_system_apps\">Skjul systemprogrammer</string>\n    <string name=\"apm_empty\">Ingen modul installert</string>\n    <string name=\"apm_uninstall_failed\">Kunne ikke avinstallere: %s</string>\n    <string name=\"apm_overlay_fs_not_available\">OverlayFS er ikke tilgjengelig. Modulen kan ikke fungere.</string>\n    <string name=\"clear_super_key\">Fjern tast</string>\n    <string name=\"home_kpatch_info_title\">Info</string>\n    <string name=\"kpatch_version_update\">Versjon: %s → %s</string>\n    <string name=\"success\">Vellykket</string>\n    <string name=\"home_device_info\">Enhet</string>\n    <string name=\"home_system_version\">Systemversjon</string>\n    <string name=\"mode_select_page_title\">Installer</string>\n    <string name=\"settings_app_language\">Språk</string>\n    <string name=\"home_ap_cando_reboot\">Omstart</string>\n    <string name=\"patch_item_extra_version\">versjon:</string>\n    <string name=\"home_kpatch_version\">KernelPatch-versjon</string>\n    <string name=\"kpm_install\">Installer</string>\n    <string name=\"apm_failed_to_enable\">Kunne ikke skru på «%s»-modulen</string>\n    <string name=\"apm_failed_to_disable\">Kunne ikke skru av «%s»-modulen</string>\n    <string name=\"apm_uninstall_confirm\">Avinstaller «%s»-modulen?</string>\n    <string name=\"home_new_apatch_found\">Klikk for å installere ny versjon %s.</string>\n    <string name=\"apm_downloading\">Laster ned \\\"%s\\\" modul…</string>\n    <string name=\"settings_night_mode_follow_sys\">Følg systemets mørke tema</string>\n    <string name=\"apm_update\">Oppdater</string>\n    <string name=\"hide_apatch_manager_failure\">Kunne ikke skjule, vennligst rapporter feilen!</string>\n    <string name=\"apm_new_version_available\">Ny versjon %s er tilgjengelig, trykk for å oppgradere.</string>\n    <string name=\"settings_night_theme_enabled\">Aktiver mørkt tema</string>\n    <string name=\"system_default\">Systemstandard</string>\n    <string name=\"settings_clear_super_key_dialog\">Er du sikker på at du vil fortsette?</string>\n    <string name=\"settings_check_update\">Sjekk oppdatering</string>\n    <string name=\"settings_check_update_summary\">Sjekk automatisk etter oppdateringer når programmet åpnes</string>\n    <string name=\"patch_start_patch_btn\">Start</string>\n    <string name=\"patch_item_extra_kpm_license\">Lisens:</string>\n    <string name=\"save_log\">Lagre loggen</string>\n    <string name=\"home_install_unknown_summary\">Klikk for å installere</string>\n    <string name=\"patch_item_error\">!!FEIL!!</string>\n    <string name=\"patch_item_bootimg_dev\">enhet:</string>\n    <string name=\"patch_item_existed_extra_kpm\">Eksisterte</string>\n    <string name=\"patch_item_kpimg_comile_time\">Tid:</string>\n    <string name=\"patch_item_extra_name\">Navn:</string>\n    <string name=\"patch_item_extra_author\">Forfatter:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Beskrivelse:</string>\n    <string name=\"patch_item_extra_args\">Argumenter:</string>\n    <string name=\"patch_item_extra_event\">Hendelse:</string>\n    <string name=\"su_pkg_excluded_label\">ekskluder</string>\n    <string name=\"apm_reboot_to_apply\">Endringene trår i kraft etter omstart</string>\n    <string name=\"home_dialog_auth_fail_title\">Autentisering feilet</string>\n    <string name=\"home_dialog_uninstall_all\">Avinstaller alle</string>\n    <string name=\"kpm_control_ok\">Operasjonen var vellykket!</string>\n    <string name=\"blue_theme\">Blått tema</string>\n    <string name=\"brown_theme\">Brunt tema</string>\n    <string name=\"green_theme\">Grønt tema</string>\n    <string name=\"light_blue_theme\">Lyseblått tema</string>\n    <string name=\"light_green_theme\">Lysegrønt tema</string>\n    <string name=\"lime_theme\">Limefarget tema</string>\n    <string name=\"orange_theme\">Oransje tema</string>\n    <string name=\"about_powered_by\">Drevet av %1$s</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Tilbakemelding eller forslag</string>\n    <string name=\"home_more_menu_about\">Om</string>\n    <string name=\"home_dialog_uninstall_title\">Avinstaller</string>\n    <string name=\"kpm_control_outMsg\">Melding</string>\n    <string name=\"kpm_control_failed\">Operasjonen mislyktes</string>\n    <string name=\"settings_custom_color_theme\">Fargetema</string>\n    <string name=\"about_app_version\">Versjon %1$s</string>\n    <string name=\"failure\">Mislykket</string>\n    <string name=\"patch\">Rettelse</string>\n    <string name=\"log_saved\">Loggen lagret</string>\n    <string name=\"super_key\">SuperNøkkel</string>\n    <string name=\"patch_mode_bootimg_patch\">Patch Modus</string>\n    <string name=\"patch_config_title\">Patches</string>\n    <string name=\"patch_mode_uninstall_patch\">Modus: Avinstaller KPatch</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"settings_global_namespace_mode_summary\">Alle root-sesjoner bruker det globale Mount-Namespace</string>\n    <string name=\"home_patch_set_key_desc\">Kun opplysninger for KernelPatch</string>\n    <string name=\"patch_embed_kpm_btn\">Integrert KPM</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_auth_key_title\">Tast inn Supernøkkelen</string>\n    <string name=\"patch_mode_install_to_next_slot\">Modus: Installer for å inaktivere sporet (Etter OTA)</string>\n    <string name=\"patch_select_bootimg_btn\">Velg oppstart</string>\n    <string name=\"patch_item_kernel\">Kjerne</string>\n    <string name=\"patch_item_kpimg_version\">Versjon:</string>\n    <string name=\"patch_set_superkey\">Angi SuperKey</string>\n    <string name=\"patch_mode_patch_and_install\">Modus: Patch og installér</string>\n    <string name=\"patch_start_unpatch_btn\">Avinstaller Patch</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_bootimg_slot\">Spor</string>\n    <string name=\"patch_item_set_skey_label\">SuperKey skal være 8–63 tegn lang og inneholde tall og bokstaver, men ingen spesialtegn.</string>\n    <string name=\"hide_apatch_manager_summary\">Installer en ny administratorapp med en tilfeldig ID og tilpasset navn</string>\n    <string name=\"hide_apatch_manager\">Skjul APatch Manager</string>\n    <string name=\"settings_global_namespace_mode\">Global navnrom modus</string>\n    <string name=\"patch_item_kpimg_config\">Konfig:</string>\n    <string name=\"patch_item_new_extra_kpm\">Legg inn på nytt</string>\n    <string name=\"kpm_control\">Kontroll</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"kpm\">KPModul</string>\n    <string name=\"kpm_add_kpm\">Legg til KPM</string>\n    <string name=\"kpm_embed\">Bygg inn</string>\n    <string name=\"su_selinux_via_hook\">omgå via krok</string>\n    <string name=\"apm\">APModul</string>\n    <string name=\"apm_not_installed\">AndroidPatch er ikke innstallert</string>\n    <string name=\"apm_magisk_conflict\">Modulene er utilgjengelige på grunn av en konflikt med Magisk!</string>\n    <string name=\"hide_apatch_dialog_summary\">Den vil bli brukt som den nye appetiketten som vises i oppstartsprogrammet.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-night/themes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <style name=\"Theme.APatch.WebUI\" parent=\"Theme.APatch\" />\n\n</resources>"
  },
  {
    "path": "app/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"patch\">Patch</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"settings\">Instellingen</string>\n    <string name=\"reboot\">Opnieuw Opstarten</string>\n    <string name=\"reboot_edl\">Start opnieuw op naar EDL</string>\n    <string name=\"about\">Over</string>\n    <string name=\"settings_app_language\">Taal</string>\n    <string name=\"system_default\">Systeem standaard</string>\n    <string name=\"settings_global_namespace_mode\">Globale naamruimtemodus</string>\n    <string name=\"settings_global_namespace_mode_summary\">Alle rootsessies gebruiken de globale mount-naamruimte</string>\n    <string name=\"home_learn_apatch\">Leer APatch</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Bekijk de broncode op %1$s<p/>Word lid van ons%2$s kanaal<p/>Word lid van ons%3$s groep]]></string>\n    <string name=\"send_log\">Logbestanden versturen</string>\n    <string name=\"safe_mode\">Veilige modus</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"home_patch_set_key_desc\">Alleen referentie voor KernelPatch</string>\n    <string name=\"home_patch_next_step\">Volgende stap</string>\n    <string name=\"home_not_installed\">Niet geïnstalleerd</string>\n    <string name=\"home_install_unknown\">Niet geïnstalleerd of geverifieerd</string>\n    <string name=\"home_click_to_install\">Klik om te installeren</string>\n    <string name=\"home_working\">Werkend 😋</string>\n    <string name=\"home_installing\">Aan het installeren</string>\n    <string name=\"home_need_update\">Nieuwe versie beschikbaar</string>\n    <string name=\"kpatch_version\">Versie: %s</string>\n    <string name=\"home_fingerprint\">Vingerafdruk</string>\n    <string name=\"home_selinux_status\">SELinux status</string>\n    <string name=\"home_selinux_status_disabled\">Uitgeschakeld</string>\n    <string name=\"home_selinux_status_enforcing\">Afdwingend</string>\n    <string name=\"home_selinux_status_permissive\">Permissief</string>\n    <string name=\"home_selinux_status_unknown\">Onbekend</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"kpm_unload_confirm\">Module \\\"%s\\\" ontladen?</string>\n    <string name=\"kpm_unload\">Ontladen</string>\n    <string name=\"kpm_apm_empty\">Geen module geladen</string>\n    <string name=\"kpm_author\">Auteur</string>\n    <string name=\"kpm_desc\">Beschr.</string>\n    <string name=\"su_show_system_apps\">Systeem-apps tonen</string>\n    <string name=\"su_hide_system_apps\">Systeem-apps verbergen</string>\n    <string name=\"apm_empty\">Geen module geïnstalleerd</string>\n    <string name=\"apm_uninstall_success\">%s verwijderd</string>\n    <string name=\"apm_uninstall_failed\">Kan %s niet verwijderen</string>\n    <string name=\"apm_reboot_to_apply\">Start opnieuw op om van kracht te gaan</string>\n    <string name=\"apm_changelog\">Wijzigingslog</string>\n    <string name=\"home\">Thuis</string>\n    <string name=\"patch_warnning\">Installatie brengt risico\\'s met zich mee. Zorg ervoor dat er een back-up van uw gegevens wordt gemaakt.</string>\n    <string name=\"reboot_bootloader\">Start opnieuw op naar Bootloader</string>\n    <string name=\"home_click_to_learn_apatch\">Leer meer over de functies van APatch en hoe u deze kunt gebruiken</string>\n    <string name=\"reboot_download\">Start opnieuw op naar Download</string>\n    <string name=\"reboot_recovery\">Start opnieuw op naar herstel</string>\n    <string name=\"apatch_version\">Versie: %s</string>\n    <string name=\"home_su_path\">Uitvoerbare su</string>\n    <string name=\"home_auth_key_desc\">Start na certificering</string>\n    <string name=\"home_ap_cando_update\">Werk bij</string>\n    <string name=\"apatch_version_update\">Versie: %s -&gt; %s</string>\n    <string name=\"home_apatch_version\">APatch versie</string>\n    <string name=\"home_ap_cando_install\">Installeer</string>\n    <string name=\"home_manager_version\">Managerversie</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch niet geïnstalleerd</string>\n    <string name=\"home_ap_cando_uninstall\">Verwijder</string>\n    <string name=\"patch_title\">Patch</string>\n    <string name=\"home_kernel\">Kernel versie</string>\n    <string name=\"kpm_load\">Laden</string>\n    <string name=\"kpm_load_toast_failed\">Laden mislukt</string>\n    <string name=\"kpm_load_toast_succ\">Laden gelukt</string>\n    <string name=\"kpm_version\">Versie</string>\n    <string name=\"kpm_license\">Licensie</string>\n    <string name=\"su_pkg_excluded_label\">uitsluiten</string>\n    <string name=\"su_pkg_excluded_setting_title\">Modificaties Uitsluiten</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Het inschakelen van deze optie zal APatch toelaten om enige gemodificeerde bestanden door de modules van deze applicatie te herstellen.</string>\n    <string name=\"su_refresh\">Vernieuwen</string>\n    <string name=\"apm_not_installed\">AndroidPatch niet geïnstalleerd</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"apm_failed_to_disable\">Kon de module \\\"%s\\\" niet uitschakelen</string>\n    <string name=\"apm_failed_to_enable\">Kon de module \\\"%s\\\" niet inschakelen</string>\n    <string name=\"apm_update\">Update</string>\n    <string name=\"apm_remove\">Verwijderen</string>\n    <string name=\"apm_install\">Installeren</string>\n    <string name=\"apm_uninstall_confirm\">De module \\\"%s\\\" verwijderen?</string>\n    <string name=\"apm_version\">Versie</string>\n    <string name=\"apm_desc\">Beschr.</string>\n    <string name=\"apm_author\">Auteur</string>\n    <string name=\"apm_downloading\">Downloaden \\\"%s\\\" module…</string>\n    <string name=\"apm_start_downloading\">Begin met downloaden %s</string>\n    <string name=\"apm_new_version_available\">Een nieuwe versie %s is beschikbaar, klik om te upgraden.</string>\n    <string name=\"apm_overlay_fs_not_available\">Modules zijn onbereikbaar als OverlayFS wordt uitgeschakeld door de kern!</string>\n    <string name=\"apm_magisk_conflict\">Modules zijn niet beschikbaar door een conflict met Magisk!</string>\n    <string name=\"settings_clear_super_key_dialog\">Wil je zeker verder gaan?</string>\n    <string name=\"success\">Succes</string>\n    <string name=\"failure\">Mislukking</string>\n    <string name=\"settings_check_update\">Naar updates zoeken</string>\n    <string name=\"settings_check_update_summary\">Automatisch controleren op updates als je de app opent</string>\n    <string name=\"blue_theme\">Blauw Theme</string>\n    <string name=\"brown_theme\">Brown Theme</string>\n    <string name=\"cyan_theme\">Cyan Theem</string>\n    <string name=\"indigo_theme\">Indigo Theme</string>\n    <string name=\"deep_purple_theme\">Diep Purple Theem</string>\n    <string name=\"light_blue_theme\">Licht Theem</string>\n    <string name=\"green_theme\">Groen Theem</string>\n    <string name=\"light_green_theme\">Licht Theem</string>\n    <string name=\"purple_theme\">Purple Theme</string>\n    <string name=\"red_theme\">Red Theem</string>\n    <string name=\"sakura_theme\">Sakura Theem</string>\n    <string name=\"deep_orange_theme\">Diepe Orange Theem</string>\n    <string name=\"lime_theme\">Lime Theme</string>\n    <string name=\"orange_theme\">Orange Theme</string>\n    <string name=\"pink_theme\">Pink Theem</string>\n    <string name=\"save_log\">Logboek opslaan</string>\n    <string name=\"log_saved\">Logboek opgeslagen</string>\n    <string name=\"kpatch_version_update\">Versie: %s -&gt; %s</string>\n    <string name=\"clear_super_key\">SuperKey verwijderen</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">Info</string>\n    <string name=\"home_install_unknown_summary\">Klik om te installeren</string>\n    <string name=\"home_auth_key_title\">SuperKey invoeren</string>\n    <string name=\"home_ap_cando_reboot\">Herstarten</string>\n    <string name=\"patch_config_title\">Patches</string>\n    <string name=\"patch_mode_uninstall_patch\">Modus: KPatch verwijderen</string>\n    <string name=\"patch_mode_install_to_next_slot\">Modus: Installeren naar volgende slot (na OTA)</string>\n    <string name=\"patch_select_bootimg_btn\">Opstarten selecteren</string>\n    <string name=\"patch_mode_bootimg_patch\">Modus: Patch</string>\n    <string name=\"patch_mode_patch_and_install\">Modus: Patchen en installeren</string>\n    <string name=\"patch_set_superkey\">SuperKey instellen</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Uw apparaat zal **GEFORCEERD** worden om op te starten aan de huidige inactieve gleuf na een heropstarting!\\nDeze optie enkel gebruiken nadat OTA gedaan is.\\nDoorgaan?</string>\n    <string name=\"teal_theme\">Blauwgroen Thema</string>\n    <string name=\"crash_handle_title\">Applicatie gecrasht…</string>\n    <string name=\"crash_handle_copy\">Kopieer crash logboek</string>\n    <string name=\"crash_handle_copied\">Crash logboek gekopieerd naar klembord.</string>\n    <string name=\"patch_embed_kpm_btn\">KPM insluiten</string>\n    <string name=\"patch_start_patch_btn\">Begin</string>\n    <string name=\"patch_item_set_skey_label\">De lengte van super sleutel zou minstens 8 tekens lang moeten zijn en zowel getallen als letters bevatten.</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Beschrijving:</string>\n    <string name=\"patch_item_extra_args\">Argumenten:</string>\n    <string name=\"patch_item_bootimg\">Opstartafbeelding</string>\n    <string name=\"patch_item_existed_extra_kpm\">Bestond</string>\n    <string name=\"apm_webui_open\">Open</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Installeer aan inactieve gleuf (Na OTA)</string>\n    <string name=\"about_telegram_channel\">Telegram Kanaal</string>\n    <string name=\"home_dialog_auth_fail_title\">Verificatie gefaald</string>\n    <string name=\"patch_item_error\">!!Fout!!</string>\n    <string name=\"patch_item_bootimg_dev\">apparaat:</string>\n    <string name=\"patch_item_kpimg_version\">Versie:</string>\n    <string name=\"patch_item_kpimg\">Kpafbeelding</string>\n    <string name=\"patch_item_kernel\">Kern</string>\n    <string name=\"patch_item_bootimg_slot\">Sleuf</string>\n    <string name=\"patch_item_new_extra_kpm\">Nieuw insluiten</string>\n    <string name=\"patch_item_kpimg_config\">Configuratie:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Tijd:</string>\n    <string name=\"patch_item_extra_name\">Naam:</string>\n    <string name=\"patch_item_extra_version\">Versie:</string>\n    <string name=\"patch_item_extra_author\">Auteur:</string>\n    <string name=\"patch_item_skey\">Super Sleutel</string>\n    <string name=\"patch_item_extra_event\">Evenement:</string>\n    <string name=\"home_system_version\">Systeem versie</string>\n    <string name=\"home_kpatch_version\">KernLap versie</string>\n    <string name=\"home_device_info\">Apparaat</string>\n    <string name=\"kpm_add_kpm\">Voeg KPM toe</string>\n    <string name=\"hide_apatch_manager\">Verberg APatch Beheerder</string>\n    <string name=\"hide_apatch_manager_summary\">Installeer een proxy applicatie met een willekeurige package ID en een custom applicatie label</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nieuwe Beheerder Naam</string>\n    <string name=\"hide_apatch_dialog_summary\">Het zal gebruikt worden als de nieuwe applicatie label weergegeven in de launcher</string>\n    <string name=\"setting_reset_su_new_path\">Nieuwe volle pad</string>\n    <string name=\"hide_apatch_manager_failure\">Verbergen gefaald, gelieve deze fout te melden!</string>\n    <string name=\"setting_reset_su_path\">su pad opnieuw instellen</string>\n    <string name=\"enable_web_debugging\">Webview Debuggen Inschakelen</string>\n    <string name=\"enable_web_debugging_summary\">Kan gebruikt worden om WebUI te debuggen, gelieve in te schakelen enkel wanneer nodig.</string>\n    <string name=\"settings_donot_store_superkey\">Super sleutel niet opslaan in lokaal</string>\n    <string name=\"home_new_apatch_found\">Nieuwe versie beschikbaar:%s, klik mij en upgrade nu.</string>\n    <string name=\"mode_select_page_title\">Installeer</string>\n    <string name=\"mode_select_page_patch_and_install\">Oplappen en Installeren</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Feedback of suggestie</string>\n    <string name=\"home_more_menu_about\">Over</string>\n    <string name=\"home_dialog_uninstall_title\">Verwijder</string>\n    <string name=\"kpm_control_paramters\">Parameters</string>\n    <string name=\"kpm_control_dialog_content\">Ingave controle parameters:</string>\n    <string name=\"kpm_control_ok\">Operatie succesvol!</string>\n    <string name=\"kpm_control_failed\">Operatie gefaald!</string>\n    <string name=\"settings_use_system_color_theme_summary\">Gebruik een kleur thema gegenereerd door systeen met huidige achtergrondafbeelding</string>\n    <string name=\"settings_use_system_color_theme\">Systeem Kleur Thema</string>\n    <string name=\"kpm_args\">Argumenten</string>\n    <string name=\"su_title\">Supergebruiker</string>\n    <string name=\"su_selinux_via_hook\">Omzeilen via haak</string>\n    <string name=\"kpm_install\">Installeer</string>\n    <string name=\"kpm_embed\">Insluiten</string>\n    <string name=\"apm_action\">Actie</string>\n    <string name=\"settings_donot_store_superkey_summary\">Verifieer de super sleutel elke keer dat de beheerder begint</string>\n    <string name=\"home_dialog_uninstall_all\">Verwijder Alles</string>\n    <string name=\"kpm_control_outMsg\">Bericht</string>\n    <string name=\"mode_select_page_select_file\">Selecteer een opstartimage om te patchen</string>\n    <string name=\"kpm_control_dialog_title\">KPModule Controleren</string>\n    <string name=\"settings_night_mode_follow_sys\">Volg Systeems Donkere Thema</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Verander automatisch naar donkere thema met systeems instelling</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Verwijder AndroidPatch</string>\n    <string name=\"amber_theme\">Amber Thema</string>\n    <string name=\"settings_night_theme_enabled\">Donkere Thema Inschakelen</string>\n    <string name=\"blue_grey_theme\">BlauwGrijs Thema</string>\n    <string name=\"settings_custom_color_theme\">Kleur Thema</string>\n    <string name=\"about_app_desc\">Kernel Root-oplossing met alleen een gestripte kernel afbeelding, die de mogelijkheid biedt om een systeemmodule te mounten en een kernelfunctie te koppelen.</string>\n    <string name=\"yellow_theme\">Geel Thema</string>\n    <string name=\"about_app_version\">Versie %1$s</string>\n    <string name=\"about_telegram_group\">Telegram Groep</string>\n    <string name=\"about_powered_by\">Aangedreven door %1$s</string>\n    <string name=\"patch_item_extra_kpm_license\">Licentie:</string>\n    <string name=\"kpm_control\">Controle</string>\n    <string name=\"home_dialog_auth_fail_content\">Niet in staat om de super sleutel te verifieren, daarom kan APatch niet correct werken.\\nHier zijn een paar mogelijke redenen voor het falen van de verificatie:\\n1. U heeft de opstart afbeelding niet opgelapt met KernLap.\\n2. De opgelapte opstart afbeelding was niet geflashed.\\n3. Super sleutel fout.\\n4. Uw apparaat ondersteunt APatch en KernLap niet.\\n\\nGelieve te checken en opnieuwe te proberen. Indien er nog steeds problemen zijn, kan je steeds vragen stellen op de officiele respository\\'s problemen pagina.</string>\n    <string name=\"patch_start_unpatch_btn\">Ontsnipperen</string>\n    <string name=\"settings_lite_mode\">Lite-modus inschakelen</string>\n    <string name=\"settings_lite_mode_mode_summary\">APModule-functies kunnen fouten vertonen nadat ze zijn ingeschakeld, maar in sommige gevallen kunnen ze detectie nog steeds effectief vermijden. Opnieuw opstarten is vereist.</string>\n    <string name=\"settings_force_overlayfs_mode\">Forceer het gebruik van OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Gebruik OverlayFS om APModules te mounten in plaats van Magic Mount wanneer kernelondersteuning beschikbaar is. Herstarten is vereist.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"apm\">Moduły AP</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"kpm\">Moduły KP</string>\n    <string name=\"home\">Pulpit</string>\n    <string name=\"send_log\">Prześlij logi</string>\n    <string name=\"kpatch_version\">Wersja: %s</string>\n    <string name=\"home_click_to_learn_apatch\">Dowiedz się o funkcjach APatcha i jak go używać</string>\n    <string name=\"home_installing\">Instalowanie</string>\n    <string name=\"home_learn_apatch\">Poznaj APatch</string>\n    <string name=\"home_click_to_install\">Kliknij, aby zainstalować</string>\n    <string name=\"about\">Informacje</string>\n    <string name=\"reboot\">Uruchom ponownie</string>\n    <string name=\"home_need_update\">Dostępna nowa wersja</string>\n    <string name=\"settings\">Ustawienia</string>\n    <string name=\"home_patch_next_step\">Kolejny krok</string>\n    <string name=\"home_not_installed\">Nie zainstalowany</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Zobacz kod źródłowy na %1$s<p/>Dołącz do naszego kanału %2$s <p/>Dołącz do naszej grupy %3$s]]></string>\n    <string name=\"home_ap_cando_uninstall\">Odinstaluj</string>\n    <string name=\"apatch_version\">Wersja: %s</string>\n    <string name=\"home_ap_cando_install\">Instaluj</string>\n    <string name=\"home_selinux_status\">Status SELinux</string>\n    <string name=\"home_su_path\">Plik wykonywalny su</string>\n    <string name=\"apatch_version_update\">Wersja: %s -&gt; %s</string>\n    <string name=\"home_kernel\">Wersja jądra</string>\n    <string name=\"home_manager_version\">Wersja menedżera</string>\n    <string name=\"patch_title\">Załataj</string>\n    <string name=\"home_selinux_status_disabled\">Wyłączony</string>\n    <string name=\"home_selinux_status_enforcing\">Wymuszony</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Włączenie tej opcji umożliwi APatch przywrócenie wszystkich plików zmodyfikowanych przez moduły tej aplikacji.</string>\n    <string name=\"su_title\">Superuser</string>\n    <string name=\"kpm_version\">Wersja</string>\n    <string name=\"su_refresh\">Odśwież</string>\n    <string name=\"su_show_system_apps\">Pokaż aplikacje systemowe</string>\n    <string name=\"home_selinux_status_permissive\">Pobłażliwy</string>\n    <string name=\"kpm_author\">Autor</string>\n    <string name=\"su_hide_system_apps\">Ukryj aplikacje systemowe</string>\n    <string name=\"kpm_load_toast_failed\">Załadowanie nie powiodło się</string>\n    <string name=\"kpm_load\">Załaduj</string>\n    <string name=\"kpm_license\">Licencja</string>\n    <string name=\"kpm_apm_empty\">Brak załadowanych modułów</string>\n    <string name=\"kpm_load_toast_succ\">Pomyślnie załadowano</string>\n    <string name=\"apm_uninstall_success\">Moduł %s odinstalowany</string>\n    <string name=\"apm_install\">Instaluj</string>\n    <string name=\"apm_remove\">Usuń</string>\n    <string name=\"apm_uninstall_confirm\">Odinstalować moduł \\\"%s\\\"?</string>\n    <string name=\"apm_version\">Wersja</string>\n    <string name=\"apm_overlay_fs_not_available\">Moduły są niedostępne, ponieważ OverlayFS jest wyłączony przez jądro!</string>\n    <string name=\"apm_failed_to_disable\">Nie udało się wyłączyć modułu \\\"%s\\\"</string>\n    <string name=\"apm_uninstall_failed\">Nie udało się odinstalować modułu %s</string>\n    <string name=\"apm_failed_to_enable\">Nie udało się włączyć modułu: \\\"%s\\\"</string>\n    <string name=\"apm_magisk_conflict\">Moduły są niedostępne, ponieważ istnieje konflikt z Magiskiem!</string>\n    <string name=\"apm_author\">Autor</string>\n    <string name=\"apm_changelog\">Lista zmian</string>\n    <string name=\"apm_downloading\">Pobieranie modułu \\\"%s\\\"…</string>\n    <string name=\"apm_update\">Aktualizacja</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"apm_start_downloading\">Rozpocznij pobieranie: %s</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"apm_new_version_available\">Dostępna jest nowa wersja %s. Kliknij, aby uaktualnić.</string>\n    <string name=\"reboot_download\">Restartuj do Download</string>\n    <string name=\"reboot_edl\">Restartuj do EDL</string>\n    <string name=\"reboot_recovery\">Restartuj do Recovery</string>\n    <string name=\"patch_set_superkey\">Ustaw SuperKey</string>\n    <string name=\"reboot_bootloader\">Restartuj do Bootloadera</string>\n    <string name=\"home_apatch_version\">Wersja APatch</string>\n    <string name=\"home_auth_key_title\">Wpisz SuperKey</string>\n    <string name=\"apm_reboot_to_apply\">Uruchom ponownie aby zadziałało</string>\n    <string name=\"apm_empty\">Brak zainstalowanych modułów</string>\n    <string name=\"home_working\">Włączony</string>\n    <string name=\"home_fingerprint\">Odcisk palca</string>\n    <string name=\"home_selinux_status_unknown\">Nieznany</string>\n    <string name=\"su_pkg_excluded_setting_title\">Wyklucz modyfikacje</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch jest niezainstalowany</string>\n    <string name=\"clear_super_key\">Wyczyść SuperKey</string>\n    <string name=\"patch_warnning\">Instalacja wiąże się z ryzykiem. Upewnij się, że utworzono kopię zapasową danych.</string>\n    <string name=\"safe_mode\">Tryb bezpieczny</string>\n    <string name=\"home_install_unknown\">Nie zainstalowano lub nie uwierzytelniono</string>\n    <string name=\"home_ap_cando_update\">Aktualizacja</string>\n    <string name=\"kpm_unload_confirm\">Rozpakować \\\"%s\\\" moduł?</string>\n    <string name=\"kpm_desc\">Opis</string>\n    <string name=\"kpm_args\">Argumenty</string>\n    <string name=\"su_selinux_via_hook\">ominięcie za pomocą haka</string>\n    <string name=\"su_pkg_excluded_label\">wyklucz</string>\n    <string name=\"apm_desc\">Opis</string>\n    <string name=\"settings_app_language\">Język</string>\n    <string name=\"system_default\">Domyślne ustawienie systemowe</string>\n    <string name=\"apm_not_installed\">AndroidPatch jest niezainstalowany</string>\n    <string name=\"home_patch_set_key_desc\">Tylko dane uwierzytelniające dla KernelPatch</string>\n    <string name=\"home_auth_key_desc\">Rozpocznij po uzyskaniu certyfikatu</string>\n    <string name=\"kpm_unload\">Rozpakuj</string>\n    <string name=\"patch\">Załataj</string>\n    <string name=\"settings_global_namespace_mode\">Tryb globalnej przestrzeni nazw</string>\n    <string name=\"settings_global_namespace_mode_summary\">Wszystkie sesje root korzystają z globalnej przestrzeni montowania nazw</string>\n    <string name=\"settings_clear_super_key_dialog\">Czy na pewno chcesz kontynuować?</string>\n    <string name=\"kpatch_version_update\">Wersja: %s -&gt; %s</string>\n    <string name=\"home_kpatch_info_title\">Informacje</string>\n    <string name=\"patch_select_bootimg_btn\">Wybierz rozruch</string>\n    <string name=\"patch_embed_kpm_btn\">Osadź KPM</string>\n    <string name=\"patch_start_patch_btn\">Start</string>\n    <string name=\"patch_start_unpatch_btn\">Odłatkowanie</string>\n    <string name=\"patch_item_error\">!!BŁĄD!!</string>\n    <string name=\"patch_item_bootimg\">obraz boot</string>\n    <string name=\"patch_item_bootimg_slot\">slot:</string>\n    <string name=\"patch_item_bootimg_dev\">urządzenie:</string>\n    <string name=\"patch_item_kernel\">Jądro</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Wersja:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Czas:</string>\n    <string name=\"patch_item_kpimg_config\">Konfiguracja:</string>\n    <string name=\"patch_item_new_extra_kpm\">osadź nowy</string>\n    <string name=\"patch_item_existed_extra_kpm\">istniejący</string>\n    <string name=\"patch_item_extra_name\">Nazwa:</string>\n    <string name=\"patch_item_extra_version\">Wersja:</string>\n    <string name=\"patch_item_extra_author\">Autor:</string>\n    <string name=\"patch_item_extra_kpm_license\">Licencja:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Opis:</string>\n    <string name=\"patch_item_extra_args\">Argumenty:</string>\n    <string name=\"patch_item_extra_event\">Wydarzenie:</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"patch_item_set_skey_label\">SuperKey powinien mieć od 8 do 63 znaków i zawierać zarówno cyfry, jak i litery, ale bez znaków specjalnych.</string>\n    <string name=\"home_ap_cando_reboot\">Uruchom ponownie</string>\n    <string name=\"patch_config_title\">Łatki</string>\n    <string name=\"patch_mode_bootimg_patch\">Tryb: Łatka</string>\n    <string name=\"patch_mode_patch_and_install\">Tryb: Aktualizacja</string>\n    <string name=\"patch_mode_uninstall_patch\">Tryb: Odłatkowanie</string>\n    <string name=\"teal_theme\">Morski</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nowa nazwa menedżera</string>\n    <string name=\"hide_apatch_dialog_summary\">Będzie używana jako nowa nazwa aplikacji pokazana w Launcherze</string>\n    <string name=\"setting_reset_su_path\">Zresetuj ścieżkę su</string>\n    <string name=\"enable_web_debugging\">Włącz debugowanie WebView</string>\n    <string name=\"mode_select_page_select_file\">Wybierz obraz boot do załatania</string>\n    <string name=\"mode_select_page_patch_and_install\">Załataj i zainstaluj</string>\n    <string name=\"settings_check_update\">Sprawdź dostępność aktualizacji</string>\n    <string name=\"settings_check_update_summary\">Automatycznie sprawdzaj dostępność aktualizacji podczas otwierania aplikacji</string>\n    <string name=\"home_install_unknown_summary\">Kliknij, aby zainstalować</string>\n    <string name=\"patch_mode_install_to_next_slot\">Tryb: Instaluj do nieaktywnego slotu (po aktualizacji OTA)</string>\n    <string name=\"kpm_add_kpm\">Dodaj KPM</string>\n    <string name=\"kpm_embed\">Osadź</string>\n    <string name=\"kpm_control\">Kontrola</string>\n    <string name=\"hide_apatch_manager\">Ukryj menedżer APatch</string>\n    <string name=\"hide_apatch_manager_summary\">Zainstaluj aplikację proxy z losowym ID pakietu i niestandardową etykietą</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Twoje urządzenie będzie **ZMUSZONE** do uruchomienia się w bieżącym nieaktywnym slocie po ponownym uruchomieniu!\\nUżywaj tej opcji tylko po zakończeniu aktualizacji OTA.\\nKontynuować?</string>\n    <string name=\"about_telegram_channel\">Kanał na Telegramie</string>\n    <string name=\"about_app_version\">Wersja %1$s</string>\n    <string name=\"about_telegram_group\">Grupa na Telegramie</string>\n    <string name=\"about_powered_by\">Zasilany przez %1$s</string>\n    <string name=\"red_theme\">Czerwony</string>\n    <string name=\"setting_reset_su_new_path\">Nowa pełna ścieżka</string>\n    <string name=\"home_more_menu_about\">O aplikacji</string>\n    <string name=\"apm_webui_open\">Otwórz</string>\n    <string name=\"green_theme\">Zielony</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Usuń AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Odinstaluj wszystko</string>\n    <string name=\"kpm_control_dialog_title\">Kontroluj KPModule</string>\n    <string name=\"kpm_control_dialog_content\">Wpisz parametry kontrolne:</string>\n    <string name=\"kpm_control_paramters\">Parametry</string>\n    <string name=\"kpm_control_outMsg\">Wiadomość zwrotna</string>\n    <string name=\"kpm_control_ok\">Operacja przebiegła pomyślnie!</string>\n    <string name=\"kpm_control_failed\">Operacja nie powiodła się!</string>\n    <string name=\"settings_night_mode_follow_sys\">Podążaj za ciemnym motywem systemu</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Automatyczne przełącz na ciemny motyw na podstawie ustawień systemowych</string>\n    <string name=\"settings_night_theme_enabled\">Włącz ciemny motyw</string>\n    <string name=\"settings_use_system_color_theme\">Motyw kolorów systemu</string>\n    <string name=\"settings_use_system_color_theme_summary\">Używaj motywu kolorystycznego wygenerowanego przez system na podstawie bieżącej tapety</string>\n    <string name=\"settings_custom_color_theme\">Motyw kolorystyczny</string>\n    <string name=\"blue_grey_theme\">Niebiesko-szary</string>\n    <string name=\"blue_theme\">Niebieski</string>\n    <string name=\"brown_theme\">Brązowy</string>\n    <string name=\"cyan_theme\">Cyjanowy</string>\n    <string name=\"deep_orange_theme\">Ciemny pomarańczowy</string>\n    <string name=\"deep_purple_theme\">Ciemny fiolet</string>\n    <string name=\"indigo_theme\">Indygo</string>\n    <string name=\"light_blue_theme\">Jasnoniebieski</string>\n    <string name=\"light_green_theme\">Jasnozielony</string>\n    <string name=\"pink_theme\">Różowy</string>\n    <string name=\"purple_theme\">Fioletowy</string>\n    <string name=\"yellow_theme\">Żółty</string>\n    <string name=\"amber_theme\">Bursztynowy</string>\n    <string name=\"lime_theme\">Limonkowy</string>\n    <string name=\"orange_theme\">Pomarańczowy</string>\n    <string name=\"hide_apatch_manager_failure\">Nie udało się ukryć. Zgłoś błąd!</string>\n    <string name=\"enable_web_debugging_summary\">Może być używane do debugowania WebUI. Włącz tylko w razie potrzeby.</string>\n    <string name=\"settings_donot_store_superkey\">Nie przechowuj SuperKey lokalnie</string>\n    <string name=\"settings_donot_store_superkey_summary\">Uwierzytelniaj SuperKey przy każdym uruchomieniu menadżera</string>\n    <string name=\"home_new_apatch_found\">Dostępna jest nowa wersja %s. Kliknij, aby uaktualnić.</string>\n    <string name=\"mode_select_page_title\">Zainstaluj</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Zainstaluj do nieaktywnego slotu (po aktualizacji OTA)</string>\n    <string name=\"sakura_theme\">Sakura</string>\n    <string name=\"home_dialog_auth_fail_content\">Nie można uwierzytelnić SuperKey, dlatego APatch nie może działać poprawnie.\\nOto kilka możliwych przyczyn niepowodzenia uwierzytelniania:\\n1. Nie zaktualizowano pliku boot.img za pomocą KernelPatch.\\n2. Poprawiony plik boot.img nie został sflashowany.\\n3. Klucz SuperKey jest nieprawidłowy lub zawiera znaki specjalne.\\n4. Urządzenie nie obsługuje APatch i KernelPatch.\\n\\nSprawdź i spróbuj ponownie. Jeśli nadal występują problemy, zawsze możesz zadawać pytania na oficjalnej stronie repozytorium.</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Opinie bądź sugestie</string>\n    <string name=\"about_app_desc\">Rozwiązanie rootowania jądra z jedynie okrojonym obrazem jądra, zapewniające możliwość montowania modułu systemowego i hakowania funkcji jądra.</string>\n    <string name=\"success\">Zakończono sukcesem</string>\n    <string name=\"failure\">Niepowodzenie</string>\n    <string name=\"home_device_info\">Urządzenie</string>\n    <string name=\"home_system_version\">Wersja systemu</string>\n    <string name=\"kpm_install\">Instaluj</string>\n    <string name=\"home_dialog_auth_fail_title\">Uwierzytelnianie nie powiodło się</string>\n    <string name=\"home_dialog_uninstall_title\">Odinstaluj</string>\n    <string name=\"home_kpatch_version\">Wersja KernelPatch</string>\n    <string name=\"save_log\">Zapisz logi</string>\n    <string name=\"apm_action\">Akcja</string>\n    <string name=\"log_saved\">Zapisano logi</string>\n    <string name=\"crash_handle_title\">Aplikacja się wysypała…</string>\n    <string name=\"crash_handle_copy\">Kopiuj logi awarii</string>\n    <string name=\"crash_handle_copied\">Logi awarii skopiowano do schowka.</string>\n    <string name=\"settings_lite_mode\">Włącz tryb uproszczony</string>\n    <string name=\"settings_lite_mode_mode_summary\">Moduły AP mogą wykazywać awarie po włączeniu tej funkcji, ale w niektórych przypadkach mogą nadal skutecznie unikać wykrycia. Wymagane ponowne uruchomienie.</string>\n    <string name=\"settings_force_overlayfs_mode\">Wymuś użycie OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Użyj OverlayFS zamiast Magic Mount do montowania modułów AP, gdy jądro to obsługuje. Wymagane jest ponowne uruchomienie.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">Início</string>\n    <string name=\"patch_warnning\">A instalação apresenta riscos. Certifique-se de ter um backup dos seus dados.</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot\">Reiniciar</string>\n    <string name=\"settings\">Configurações</string>\n    <string name=\"reboot_recovery\">Reiniciar em modo de recuperação</string>\n    <string name=\"about\">Sobre</string>\n    <string name=\"home_learn_apatch\">Aprender APatch</string>\n    <string name=\"home_click_to_learn_apatch\">Aprenda sobre as características de APatch e como usar</string>\n    <string name=\"super_key\">Chave de Segurança</string>\n    <string name=\"patch_set_superkey\">Definir Chave de Segurança</string>\n    <string name=\"home_patch_next_step\">Próximo passo</string>\n    <string name=\"home_install_unknown\">\"Não foi instalado ou autenticado \"</string>\n    <string name=\"home_click_to_install\">Clique para instalar</string>\n    <string name=\"home_need_update\">Nova versão Disponível</string>\n    <string name=\"apatch_version\">Versão: %s</string>\n    <string name=\"home_auth_key_title\">Digitar SuperKey</string>\n    <string name=\"home_ap_cando_update\">Atualizar</string>\n    <string name=\"home_ap_cando_uninstall\">Desinstalar</string>\n    <string name=\"patch_title\">Patch</string>\n    <string name=\"home_kernel\">Versão do Kernel</string>\n    <string name=\"home_manager_version\">Versão do gestor</string>\n    <string name=\"home_selinux_status_disabled\">Desativado</string>\n    <string name=\"kpm\">KPModulo</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch não instalado</string>\n    <string name=\"kpm_load_toast_succ\">Carregado com sucesso</string>\n    <string name=\"kpm_load_toast_failed\">Falha no carregamento</string>\n    <string name=\"send_log\">Enviar logs</string>\n    <string name=\"safe_mode\">Modo Seguro</string>\n    <string name=\"home_patch_set_key_desc\">Apenas credencial para KernelPatch</string>\n    <string name=\"home_not_installed\">Não instalado</string>\n    <string name=\"kpatch_version\">Versão: %s</string>\n    <string name=\"home_working\">Funcionado</string>\n    <string name=\"home_installing\">Instalando</string>\n    <string name=\"apatch_version_update\">Versão: %s -&gt; %s</string>\n    <string name=\"home_ap_cando_install\">Instalar</string>\n    <string name=\"home_selinux_status_unknown\">Desconhecido</string>\n    <string name=\"kpm_load\">Carregar</string>\n    <string name=\"reboot_bootloader\">Reiniciar em modo Bootloader</string>\n    <string name=\"reboot_download\">Reiniciar em modo Download</string>\n    <string name=\"reboot_edl\">Reiniciar em modo EDL</string>\n    <string name=\"home_su_path\">su executável</string>\n    <string name=\"home_auth_key_desc\">Comece trabalho após a certificação</string>\n    <string name=\"home_fingerprint\">Impressão digital</string>\n    <string name=\"home_selinux_status\">Estado do SELinux</string>\n    <string name=\"home_selinux_status_enforcing\">A impor</string>\n    <string name=\"home_selinux_status_permissive\">Permissivo</string>\n    <string name=\"kpm_unload_confirm\">Descarregar \\\"%s\\\" módulo ?</string>\n    <string name=\"kpm_unload\">Descarregar</string>\n    <string name=\"kpm_apm_empty\">Nenhum módulo carregado</string>\n    <string name=\"su_selinux_via_hook\">ignorar via hook</string>\n    <string name=\"kpm_version\">Versão</string>\n    <string name=\"apm_downloading\">Baixando o módulo \\\"%s\\\"…</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Veja o código-fonte em %1$s<p/>Participe do nosso canal %2$s<p/>Participe do nosso grupo %3$s]]></string>\n    <string name=\"clear_super_key\">Limpar chave</string>\n    <string name=\"home_apatch_version\">Versão APatch</string>\n    <string name=\"kpm_license\">Licença</string>\n    <string name=\"kpm_author\">Autor</string>\n    <string name=\"kpm_desc\">Descrição</string>\n    <string name=\"kpm_args\">Argumentos</string>\n    <string name=\"su_title\">SuperUsuário</string>\n    <string name=\"su_pkg_excluded_label\">excluir</string>\n    <string name=\"su_pkg_excluded_setting_title\">Excluir modificações</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Ativar esta opção permitirá que o APatch restaure quaisquer ficheiros modificados pelos módulos deste app.</string>\n    <string name=\"su_show_system_apps\">Mostrar apps do sistema</string>\n    <string name=\"su_hide_system_apps\">Ocultar apps do sistema</string>\n    <string name=\"su_refresh\">Atualizar</string>\n    <string name=\"apm\">APMódulo</string>\n    <string name=\"apm_failed_to_enable\">Não foi possível ativar o módulo %s</string>\n    <string name=\"apm_failed_to_disable\">Não foi possível desligar o módulo \\\"%s\\\"</string>\n    <string name=\"apm_empty\">Nenhum módulo instalado</string>\n    <string name=\"apm_remove\">Remover</string>\n    <string name=\"apm_install\">Instalar</string>\n    <string name=\"apm_uninstall_confirm\">Desinstalar o módulo \\\"%s\\\"?</string>\n    <string name=\"apm_uninstall_success\">%s desinstalado</string>\n    <string name=\"apm_uninstall_failed\">Não foi possível desinstalar %s</string>\n    <string name=\"apm_version\">Versão</string>\n    <string name=\"apm_author\">Autor</string>\n    <string name=\"apm_desc\">Descrição</string>\n    <string name=\"apm_overlay_fs_not_available\">Os módulos não estão disponíveis porque o OverlayFS está desabilitado pelo kernel!</string>\n    <string name=\"apm_magisk_conflict\">Os módulos estão indisponíveis devido a um conflito com Magisk!</string>\n    <string name=\"apm_reboot_to_apply\">Reinicie para entrar em vigor</string>\n    <string name=\"apm_changelog\">Registro de alterações</string>\n    <string name=\"apm_start_downloading\">Iniciando download: %s</string>\n    <string name=\"apm_update\">Atualizar</string>\n    <string name=\"apm_new_version_available\">Há uma nova versão disponível, %s, clique para atualizar.</string>\n    <string name=\"apm_not_installed\">AndroidPatch não instalado</string>\n    <string name=\"system_default\">Padrão do sistema</string>\n    <string name=\"settings_app_language\">Idioma</string>\n    <string name=\"patch\">Patch</string>\n    <string name=\"settings_global_namespace_mode\">Modo de namespace global</string>\n    <string name=\"settings_global_namespace_mode_summary\">Todas as sessões root usam o Global Mount Namespace</string>\n    <string name=\"settings_check_update\">Verificar atualizações</string>\n    <string name=\"success\">Sucesso</string>\n    <string name=\"failure\">Falha</string>\n    <string name=\"settings_clear_super_key_dialog\">Você realmente quer prosseguir?</string>\n    <string name=\"settings_check_update_summary\">Verifique automaticamente as atualizações ao abrir o aplicativo</string>\n    <string name=\"home_install_unknown_summary\">Clique para instalar</string>\n    <string name=\"kpatch_version_update\">Versão: %s -&gt; %s</string>\n    <string name=\"home_kpatch_info_title\">Informação</string>\n    <string name=\"patch_select_bootimg_btn\">Selecione a inicialização</string>\n    <string name=\"patch_start_patch_btn\">Início</string>\n    <string name=\"patch_item_bootimg\">inicialização</string>\n    <string name=\"patch_item_extra_name\">Nome:</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_ap_cando_reboot\">Reiniciar</string>\n    <string name=\"patch_config_title\">Luz azul Tema</string>\n    <string name=\"patch_mode_bootimg_patch\">Modo: Patch</string>\n    <string name=\"patch_item_kpimg_comile_time\">Tempo:</string>\n    <string name=\"patch_item_extra_version\">Versão:</string>\n    <string name=\"patch_item_extra_author\">Autor:</string>\n    <string name=\"patch_item_extra_kpm_license\">Licença:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Descrição:</string>\n    <string name=\"settings_custom_color_theme\">Tema de cores</string>\n    <string name=\"blue_grey_theme\">Cinzento-azul</string>\n    <string name=\"blue_theme\">Azul</string>\n    <string name=\"brown_theme\">Castanho</string>\n    <string name=\"cyan_theme\">Ciano</string>\n    <string name=\"deep_orange_theme\">Laranja profundo</string>\n    <string name=\"deep_purple_theme\">Roxo profundo</string>\n    <string name=\"green_theme\">Verde</string>\n    <string name=\"indigo_theme\">Azul-anil</string>\n    <string name=\"light_blue_theme\">Azul claro</string>\n    <string name=\"light_green_theme\">Verde claro</string>\n    <string name=\"lime_theme\">Verde-limão</string>\n    <string name=\"orange_theme\">Laranja</string>\n    <string name=\"pink_theme\">Rosa</string>\n    <string name=\"purple_theme\">Roxo</string>\n    <string name=\"red_theme\">Vermelho</string>\n    <string name=\"sakura_theme\">Sakura</string>\n    <string name=\"teal_theme\">Verde-azulado</string>\n    <string name=\"yellow_theme\">Amarelo</string>\n    <string name=\"about_telegram_channel\">Canal do Telegram</string>\n    <string name=\"about_telegram_group\">Grupo do Telegram</string>\n    <string name=\"about_app_version\">Versão %1$s</string>\n    <string name=\"about_powered_by\">Alimentado por %1$s</string>\n    <string name=\"about_app_desc\">Solução root do kernel com uma única imagem despojada, oferecendo a capacidade de montar módulos do sistema e interceptar funções do kernel.</string>\n    <string name=\"patch_mode_patch_and_install\">Modo: Patch e instalar</string>\n    <string name=\"home_dialog_auth_fail_content\">Não foi possível autenticar a SuperKey, portanto o APatch não pode funcionar corretamente. \\nAqui estão alguns possíveis motivos para a falha de autenticação:\\n1. Não fez patch do boot.img com KernelPatch.\\n2. O boot.img corrigido não foi flashado.\\n3. A SuperKey está incorreta ou contém caracteres especiais.\\n4. O seu dispositivo não oferece suporte ao APatch e KernelPatch.\\n\\nPor favor, verifique e tente novamente. Se ainda houver problemas, pode fazer perguntas na página de problemas do repositório oficial.</string>\n    <string name=\"patch_mode_install_to_next_slot\">Modo: Instalar no slot inativo (após OTA)</string>\n    <string name=\"patch_mode_uninstall_patch\">Modo: Desinstalar KPatch</string>\n    <string name=\"patch_embed_kpm_btn\">Introduzir KPM</string>\n    <string name=\"patch_start_unpatch_btn\">Desfazer o Patch</string>\n    <string name=\"patch_item_error\">ERRO!</string>\n    <string name=\"patch_item_kpimg_config\">Configuração:</string>\n    <string name=\"patch_item_new_extra_kpm\">Implementar novo</string>\n    <string name=\"patch_item_existed_extra_kpm\">Existia</string>\n    <string name=\"patch_item_extra_args\">Argumentos:</string>\n    <string name=\"patch_item_skey\">Chave Mestra</string>\n    <string name=\"patch_item_set_skey_label\">O comprimento da Chave Mestra deve ter pelo menos 8 caracteres e incluir números e letras.</string>\n    <string name=\"home_kpatch_version\">Versão do KernelPatch</string>\n    <string name=\"hide_apatch_manager\">Ocultar o gerenciador do Apatch</string>\n    <string name=\"hide_apatch_manager_summary\">Instalar um app de proxy com ID aleatório e nome personalizado</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nome do novo gestor</string>\n    <string name=\"hide_apatch_dialog_summary\">Ele será usado como a nova tag do aplicativo mostrado ao iniciar</string>\n    <string name=\"hide_apatch_manager_failure\">Falha ao ocultar. Por favor, reporte o bug!</string>\n    <string name=\"setting_reset_su_path\">Desfazer o acesso ao su</string>\n    <string name=\"setting_reset_su_new_path\">Novo caminho completo</string>\n    <string name=\"enable_web_debugging\">Ativar depuração do WebView</string>\n    <string name=\"settings_donot_store_superkey\">Não armazenar a SuperKey no local</string>\n    <string name=\"settings_donot_store_superkey_summary\">Autentique a SuperKey sempre que o gestor iniciar</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Instalar no slot inativo (após o OTA)</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Seu dispositivo será **FORÇADO** a inicializar no slot inativo atual após uma reinicialização!\n\\nUse esta opção somente após a conclusão do OTA.\n\\nContinuar?</string>\n    <string name=\"home_dialog_auth_fail_title\">Falha na autenticação</string>\n    <string name=\"home_more_menu_about\">Acerca</string>\n    <string name=\"kpm_control_dialog_title\">Controlar KPModule</string>\n    <string name=\"settings_night_theme_enabled\">Ativar tema escuro</string>\n    <string name=\"save_log\">Salvar logs</string>\n    <string name=\"mode_select_page_title\">instalar</string>\n    <string name=\"kpm_install\">Instalar</string>\n    <string name=\"patch_item_extra_event\">Evento:</string>\n    <string name=\"patch_item_bootimg_slot\">slot:</string>\n    <string name=\"patch_item_bootimg_dev\">dispositivo:</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Versão:</string>\n    <string name=\"home_device_info\">Dispositivo</string>\n    <string name=\"home_system_version\">Versão do sistema</string>\n    <string name=\"kpm_add_kpm\">Adicionar KPM</string>\n    <string name=\"kpm_embed\">Embutido</string>\n    <string name=\"kpm_control\">Control</string>\n    <string name=\"apm_webui_open\">Abrir</string>\n    <string name=\"enable_web_debugging_summary\">Pode ser usado para depurar o WebUI. Por favor, ative somente quando necessário.</string>\n    <string name=\"home_new_apatch_found\">Nova versão %s está disponível, clique para atualizar.</string>\n    <string name=\"mode_select_page_select_file\">Selecione uma imagem de inicialização para corrigir</string>\n    <string name=\"mode_select_page_patch_and_install\">Patch e instalação</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Feedback ou sugestão</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Remover AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Desinstalar tudo</string>\n    <string name=\"home_dialog_uninstall_title\">Desinstalar</string>\n    <string name=\"kpm_control_dialog_content\">Parâmetros de controle de entrada:</string>\n    <string name=\"kpm_control_ok\">A operação foi bem sucedida!</string>\n    <string name=\"kpm_control_failed\">A operação falhou!</string>\n    <string name=\"settings_night_mode_follow_sys\">Seguir tema escuro do sistema</string>\n    <string name=\"kpm_control_paramters\">Parâmetros</string>\n    <string name=\"kpm_control_outMsg\">Mensagem</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Mude automaticamente para o tema escuro com base nas configurações do sistema</string>\n    <string name=\"settings_use_system_color_theme\">Tema de cores do sistema</string>\n    <string name=\"settings_use_system_color_theme_summary\">Use um tema de cores gerado pelo sistema com base no plano de fundo atual</string>\n    <string name=\"amber_theme\">Âmbar</string>\n    <string name=\"apm_action\">Ação</string>\n    <string name=\"log_saved\">Logs salvos</string>\n    <string name=\"crash_handle_title\">A app travou…</string>\n    <string name=\"crash_handle_copy\">Copiar registro de falha</string>\n    <string name=\"crash_handle_copied\">Registo de falhas copiado.</string>\n    <string name=\"settings_lite_mode\">Habilitar modo leve</string>\n    <string name=\"settings_lite_mode_mode_summary\">Funções APModule podem exibir falhas após serem habilitadas, mas em alguns casos elas conseguem evitar detecção eficientemente. Necessário reinicialização.</string>\n    <string name=\"settings_force_overlayfs_mode\">Forçar o uso de OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Usar OverlayFS para montar APModules ao invés de Magic Mount quando o suporte ao kernel estiver disponível. Necessário reinicialização.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">Início</string>\n    <string name=\"patch_warnning\">A instalação apresenta riscos. Por favor, certifique-se de fazer backup de seus dados.</string>\n    <string name=\"patch_title\">Patch</string>\n    <string name=\"kpm_author\">Autor</string>\n    <string name=\"kpm_desc\">Descrição</string>\n    <string name=\"kpm_args\">Argumentos</string>\n    <string name=\"su_title\">SuperUsuário</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Ativar esta opção permitirá que o APatch restaure quaisquer arquivos modificados pelos módulos deste app.</string>\n    <string name=\"su_refresh\">Atualizar</string>\n    <string name=\"apm_reboot_to_apply\">Reinicie para entrar em vigor</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot\">Reiniciar</string>\n    <string name=\"settings\">Configurações</string>\n    <string name=\"reboot_recovery\">Reiniciar em modo Recovery</string>\n    <string name=\"reboot_bootloader\">Reiniciar em modo Bootloader</string>\n    <string name=\"reboot_download\">Reiniciar em modo Download</string>\n    <string name=\"reboot_edl\">Reiniciar em modo EDL</string>\n    <string name=\"about\">Sobre</string>\n    <string name=\"home_learn_apatch\">Saiba mais sobre o APatch</string>\n    <string name=\"home_click_to_learn_apatch\">Conheça os recursos do APatch e como usá-lo</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Veja o código-fonte no %1$s<p/>Participe do nosso canal do %2$s<p/>Participe do nosso grupo do %3$s]]></string>\n    <string name=\"send_log\">Reportar registros</string>\n    <string name=\"safe_mode\">Modo de segurança</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"patch_set_superkey\">Definir SuperKey</string>\n    <string name=\"home_patch_set_key_desc\">Apenas credencial para KernelPatch</string>\n    <string name=\"home_patch_next_step\">Próximo passo</string>\n    <string name=\"home_not_installed\">Não instalado</string>\n    <string name=\"home_click_to_install\">Clique para instalar</string>\n    <string name=\"home_working\">Em execução 😋</string>\n    <string name=\"home_install_unknown\">Não instalado ou autenticado</string>\n    <string name=\"home_installing\">Instalando</string>\n    <string name=\"home_need_update\">Nova versão disponível</string>\n    <string name=\"kpatch_version\">Versão: %s</string>\n    <string name=\"apatch_version\">Versão: %s</string>\n    <string name=\"home_su_path\">Su executável</string>\n    <string name=\"apatch_version_update\">Versão: %s -&gt; %s</string>\n    <string name=\"home_apatch_version\">Versão do APatch</string>\n    <string name=\"home_auth_key_title\">Inserir SuperKey</string>\n    <string name=\"home_auth_key_desc\">Iniciar após a certificação</string>\n    <string name=\"home_ap_cando_install\">Instalar</string>\n    <string name=\"home_ap_cando_update\">Atualizar</string>\n    <string name=\"home_ap_cando_uninstall\">Desinstalar</string>\n    <string name=\"home_kernel\">Versão do kernel</string>\n    <string name=\"home_manager_version\">Versão do gerenciador</string>\n    <string name=\"home_fingerprint\">Impressão digital</string>\n    <string name=\"home_selinux_status\">Status do SELinux</string>\n    <string name=\"home_selinux_status_disabled\">Desativado</string>\n    <string name=\"home_selinux_status_enforcing\">Impondo</string>\n    <string name=\"home_selinux_status_permissive\">Permissivo</string>\n    <string name=\"home_selinux_status_unknown\">Desconhecido</string>\n    <string name=\"kpm\">KPMódulo</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch não instalado</string>\n    <string name=\"kpm_unload\">Descarregar</string>\n    <string name=\"kpm_load\">Carregar</string>\n    <string name=\"kpm_load_toast_succ\">Carregado com sucesso</string>\n    <string name=\"kpm_load_toast_failed\">Erro ao carregar</string>\n    <string name=\"kpm_unload_confirm\">Descarregar o módulo %s?</string>\n    <string name=\"kpm_apm_empty\">Nenhum módulo carregado</string>\n    <string name=\"kpm_version\">Versão</string>\n    <string name=\"kpm_license\">Licença</string>\n    <string name=\"su_selinux_via_hook\">ignorar via hook</string>\n    <string name=\"su_pkg_excluded_label\">excluir</string>\n    <string name=\"su_pkg_excluded_setting_title\">Excluir modificações</string>\n    <string name=\"su_show_system_apps\">Mostrar apps do sistema</string>\n    <string name=\"su_hide_system_apps\">Ocultar apps do sistema</string>\n    <string name=\"apm\">APMódulo</string>\n    <string name=\"apm_failed_to_enable\">Não foi possível ativar o módulo %s</string>\n    <string name=\"apm_failed_to_disable\">Não foi possível desativar o módulo %s</string>\n    <string name=\"apm_empty\">Nenhum módulo instalado</string>\n    <string name=\"apm_remove\">Desinstalar</string>\n    <string name=\"apm_install\">Instalar</string>\n    <string name=\"apm_uninstall_confirm\">Desinstalar o módulo %s?</string>\n    <string name=\"apm_uninstall_success\">%s desinstalado</string>\n    <string name=\"apm_uninstall_failed\">Não foi possível desinstalar %s</string>\n    <string name=\"apm_version\">Versão</string>\n    <string name=\"apm_author\">Autor</string>\n    <string name=\"apm_desc\">Descrição</string>\n    <string name=\"apm_overlay_fs_not_available\">Os módulos estão indisponíveis porque OverlayFS está desabilitado pelo kernel!</string>\n    <string name=\"apm_magisk_conflict\">Os módulos estão indisponíveis devido a um conflito com Magisk!</string>\n    <string name=\"apm_changelog\">Registro de alterações</string>\n    <string name=\"apm_update\">Atualizar</string>\n    <string name=\"apm_downloading\">Baixando módulo %s</string>\n    <string name=\"apm_start_downloading\">Começando a baixar %s</string>\n    <string name=\"apm_new_version_available\">Nova versão %s está disponível, clique para atualizar.</string>\n    <string name=\"clear_super_key\">Limpar SuperKey</string>\n    <string name=\"apm_not_installed\">AndroidPatch não instalado</string>\n    <string name=\"settings_app_language\">Idioma</string>\n    <string name=\"system_default\">Padrão do sistema</string>\n    <string name=\"patch\">Patch</string>\n    <string name=\"settings_global_namespace_mode\">Modo de namespace global</string>\n    <string name=\"settings_global_namespace_mode_summary\">Todas as sessões root usam o namespace de montagem global</string>\n    <string name=\"kpatch_version_update\">Versão: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">Informações</string>\n    <string name=\"home_ap_cando_reboot\">Reiniciar</string>\n    <string name=\"patch_item_error\">!!ERRO!!</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_bootimg_slot\">slot:</string>\n    <string name=\"patch_item_bootimg_dev\">dispositivo:</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Versão:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Hora:</string>\n    <string name=\"patch_item_kpimg_config\">Configuração:</string>\n    <string name=\"patch_item_new_extra_kpm\">Incorporar novo</string>\n    <string name=\"patch_item_existed_extra_kpm\">Existia</string>\n    <string name=\"patch_item_extra_name\">Nome:</string>\n    <string name=\"patch_item_extra_version\">Versão:</string>\n    <string name=\"patch_item_extra_author\">Autor:</string>\n    <string name=\"patch_item_extra_kpm_license\">Licença:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Descrição:</string>\n    <string name=\"patch_select_bootimg_btn\">Selecionar boot</string>\n    <string name=\"patch_embed_kpm_btn\">Incorporar KPM</string>\n    <string name=\"patch_start_patch_btn\">Iniciar</string>\n    <string name=\"patch_config_title\">Patches</string>\n    <string name=\"patch_mode_bootimg_patch\">Modo: Patch</string>\n    <string name=\"patch_mode_patch_and_install\">Modo: Patch e instalação</string>\n    <string name=\"patch_mode_uninstall_patch\">Modo: Desinstalar KPatch</string>\n    <string name=\"patch_start_unpatch_btn\">UnPatch</string>\n    <string name=\"patch_item_extra_args\">Argumentos:</string>\n    <string name=\"patch_item_extra_event\">Evento:</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"settings_clear_super_key_dialog\">Você realmente deseja continuar?</string>\n    <string name=\"patch_item_set_skey_label\">A SuperKey deve ter de 8 a 63 caracteres e incluir números e letras, mas sem caracteres especiais.</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nome do novo gerenciador</string>\n    <string name=\"hide_apatch_dialog_summary\">Ele será usado como o novo nome do app mostrado na launcher</string>\n    <string name=\"hide_apatch_manager\">Ocultar app do APatch</string>\n    <string name=\"hide_apatch_manager_summary\">Instala o app oculto com ID aleatório e nome personalizado</string>\n    <string name=\"hide_apatch_manager_failure\">Falha ao ocultar. Por favor, reporte o bug!</string>\n    <string name=\"kpm_embed\">Incorporar</string>\n    <string name=\"kpm_add_kpm\">Adicionar KPM</string>\n    <string name=\"kpm_install\">Instalar</string>\n    <string name=\"failure\">Falha</string>\n    <string name=\"setting_reset_su_new_path\">Novo caminho completo</string>\n    <string name=\"success\">Sucesso</string>\n    <string name=\"setting_reset_su_path\">Redefinir caminho su</string>\n    <string name=\"settings_check_update_summary\">Verifique automaticamente se há atualizações ao abrir o app</string>\n    <string name=\"settings_check_update\">Verificar por atualizações</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Instalar no slot inativo (Após o OTA)</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Seu dispositivo será **FORÇADO** a inicializar no slot inativo atual após uma reinicialização!\n\\nSó use esta opção após a conclusão do OTA.\n\\nDeseja continuar?</string>\n    <string name=\"home_dialog_auth_fail_title\">Falha na autenticação</string>\n    <string name=\"mode_select_page_select_file\">Selecionar imagem boot para patch</string>\n    <string name=\"mode_select_page_title\">Instalar</string>\n    <string name=\"mode_select_page_patch_and_install\">Patch e instalação</string>\n    <string name=\"home_dialog_auth_fail_content\">Não foi possível autenticar a SuperKey, portanto o APatch não pode funcionar corretamente. \\nAqui estão alguns possíveis motivos para a falha de autenticação:\\n1. Você não fez patch do boot.img com KernelPatch.\\n2. O boot.img corrigido não foi flashado.\\n3. A SuperKey está incorreta ou contém caracteres especiais.\\n4. Seu dispositivo não oferece suporte ao APatch e KernelPatch.\\n\\nPor favor, verifique e tente novamente. Se ainda houver problemas, você pode fazer perguntas na página de problemas do repositório oficial.</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Feedback ou sugestão</string>\n    <string name=\"home_more_menu_about\">Sobre</string>\n    <string name=\"apm_webui_open\">Abrir</string>\n    <string name=\"enable_web_debugging\">Ativar depuração do WebView</string>\n    <string name=\"settings_donot_store_superkey_summary\">Autentique a SuperKey sempre que o gerenciador iniciar</string>\n    <string name=\"enable_web_debugging_summary\">Pode ser usado para depurar o WebUI. Por favor, ative somente quando necessário.</string>\n    <string name=\"settings_donot_store_superkey\">Não armazenar a SuperKey no local</string>\n    <string name=\"home_new_apatch_found\">Nova versão %s está disponível, clique para atualizar.</string>\n    <string name=\"patch_mode_install_to_next_slot\">Modo: Instalar no slot inativo (Após o OTA)</string>\n    <string name=\"home_device_info\">Dispositivo</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Desinstalar AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Desinstalar tudo</string>\n    <string name=\"home_install_unknown_summary\">Clique para instalar</string>\n    <string name=\"home_system_version\">Versão do sistema</string>\n    <string name=\"home_kpatch_version\">Versão do KernelPatch</string>\n    <string name=\"home_dialog_uninstall_title\">Desinstalar</string>\n    <string name=\"settings_night_theme_enabled\">Ativar tema escuro</string>\n    <string name=\"settings_use_system_color_theme\">Tema de cores do sistema</string>\n    <string name=\"settings_use_system_color_theme_summary\">Use um tema de cores gerado pelo sistema com base no plano de fundo atual</string>\n    <string name=\"settings_custom_color_theme\">Tema de cores</string>\n    <string name=\"green_theme\">Verde</string>\n    <string name=\"deep_orange_theme\">Laranja profundo</string>\n    <string name=\"lime_theme\">Verde-limão</string>\n    <string name=\"orange_theme\">Laranja</string>\n    <string name=\"teal_theme\">Verde-azulado</string>\n    <string name=\"kpm_control_failed\">Operação falhou!</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Mude automaticamente para o tema escuro com base nas configurações do sistema</string>\n    <string name=\"blue_theme\">Azul</string>\n    <string name=\"cyan_theme\">Ciano</string>\n    <string name=\"light_blue_theme\">Azul claro</string>\n    <string name=\"light_green_theme\">Verde claro</string>\n    <string name=\"pink_theme\">Rosa</string>\n    <string name=\"purple_theme\">Roxo</string>\n    <string name=\"red_theme\">Vermelho</string>\n    <string name=\"sakura_theme\">Sakura</string>\n    <string name=\"about_app_version\">Versão %1$s</string>\n    <string name=\"about_telegram_group\">Grupo do Telegram</string>\n    <string name=\"about_powered_by\">Fornecido por %1$s</string>\n    <string name=\"yellow_theme\">Amarelo</string>\n    <string name=\"about_telegram_channel\">Canal do Telegram</string>\n    <string name=\"kpm_control\">Controlar</string>\n    <string name=\"kpm_control_dialog_content\">Parâmetros de controle de entrada:</string>\n    <string name=\"kpm_control_paramters\">Parâmetros</string>\n    <string name=\"kpm_control_outMsg\">Mensagem</string>\n    <string name=\"kpm_control_ok\">Operação bem-sucedida!</string>\n    <string name=\"settings_night_mode_follow_sys\">Seguir tema escuro do sistema</string>\n    <string name=\"amber_theme\">Âmbar</string>\n    <string name=\"blue_grey_theme\">Cinza-azulado</string>\n    <string name=\"indigo_theme\">Azul-anil</string>\n    <string name=\"brown_theme\">Marrom</string>\n    <string name=\"deep_purple_theme\">Roxo profundo</string>\n    <string name=\"about_app_desc\">Solução root do kernel com uma única imagem despojada, oferecendo a capacidade de montar módulos do sistema e interceptar funções do kernel.</string>\n    <string name=\"kpm_control_dialog_title\">Controlar KPMódulo</string>\n    <string name=\"save_log\">Salvar registros</string>\n    <string name=\"apm_action\">Ação</string>\n    <string name=\"crash_handle_copied\">Registro de falhas copiado.</string>\n    <string name=\"crash_handle_title\">O app travou…</string>\n    <string name=\"crash_handle_copy\">Copiar registro de falhas</string>\n    <string name=\"log_saved\">Registros salvos</string>\n    <string name=\"settings_lite_mode\">Ativar Modo lite</string>\n    <string name=\"settings_lite_mode_mode_summary\">As funções do APMódulo podem apresentar falhas após serem ativadas, mas em alguns casos ainda podem evitar a detecção. Reinicialização necessária.</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Use OverlayFS para montar os APMódulos em vez do Magic Mount, quando houver suporte no kernel. Reinicialização necessária.</string>\n    <string name=\"settings_force_overlayfs_mode\">Forçar o uso do OverlayFS</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">Acasă</string>\n    <string name=\"patch_warnning\">Instalarea implică riscuri. Asigură-te că datele tale sunt salvate.</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot\">Repornește</string>\n    <string name=\"settings\">Setări</string>\n    <string name=\"reboot_recovery\">Repornește la Recovery</string>\n    <string name=\"reboot_bootloader\">Repornește la Bootloader</string>\n    <string name=\"reboot_download\">Repornește la Download</string>\n    <string name=\"reboot_edl\">Repornește la EDL</string>\n    <string name=\"about\">Despre</string>\n    <string name=\"home_learn_apatch\">Invata APatch</string>\n    <string name=\"about_source_code\">Vezi codul sursă la %1$s<br/> Alătură-te canalului nostru %2$s <p/>Devin-o membrul grupului %3$s</string>\n    <string name=\"send_log\">Trimite log-uri</string>\n    <string name=\"clear_super_key\">Șterge cheia</string>\n    <string name=\"patch_set_superkey\">Setează Superkey</string>\n    <string name=\"home_patch_set_key_desc\">Doar acreditări pentru KernelPatch</string>\n    <string name=\"home_patch_next_step\">Pasul următor</string>\n    <string name=\"home_not_installed\">Neinstalat</string>\n    <string name=\"home_install_unknown\">Necunoscut</string>\n    <string name=\"home_click_to_install\">Apasă pentru a instala</string>\n    <string name=\"home_working\">Funcțional</string>\n    <string name=\"home_installing\">Instalare</string>\n    <string name=\"home_need_update\">Versiune nouă disponibilă</string>\n    <string name=\"kpatch_version\">Versiune: %s</string>\n    <string name=\"apatch_version\">Versiune:\n\\n%s</string>\n    <string name=\"apatch_version_update\">Versiune:\n\\n%s -&gt; %s</string>\n    <string name=\"home_su_path\">Executable su</string>\n    <string name=\"home_apatch_version\">Versiune APatch</string>\n    <string name=\"home_auth_key_title\">Introdu Superkey</string>\n    <string name=\"home_auth_key_desc\">Pornește după certificare</string>\n    <string name=\"home_ap_cando_install\">Instalează</string>\n    <string name=\"home_ap_cando_update\">Actualizează</string>\n    <string name=\"home_ap_cando_uninstall\">Dezinstalează</string>\n    <string name=\"patch_title\">Patch</string>\n    <string name=\"home_kernel\">Versiune de kernel</string>\n    <string name=\"home_fingerprint\">Amprentă</string>\n    <string name=\"home_selinux_status_enforcing\">Obligatoriu</string>\n    <string name=\"home_selinux_status_permissive\">Permisiv</string>\n    <string name=\"home_selinux_status_unknown\">Necunoscut</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch neinstalat</string>\n    <string name=\"kpm_load\">Încarcă</string>\n    <string name=\"kpm_load_toast_succ\">Încărcare reușită</string>\n    <string name=\"kpm_load_toast_failed\">Încărcare nereușită</string>\n    <string name=\"kpm_unload_confirm\">Anulezi încărcarea modulului \\\"%s\\\"?</string>\n    <string name=\"kpm_unload\">Anulează încărcarea</string>\n    <string name=\"kpm_apm_empty\">Niciun modul încărcat</string>\n    <string name=\"kpm_version\">Versiune</string>\n    <string name=\"kpm_license\">Licență</string>\n    <string name=\"kpm_author\">Autor</string>\n    <string name=\"kpm_desc\">Descriere</string>\n    <string name=\"kpm_args\">Argumente</string>\n    <string name=\"su_title\">Super-utilizator</string>\n    <string name=\"su_selinux_via_hook\">ocolire prin hook</string>\n    <string name=\"su_pkg_excluded_setting_title\">Exclude Modificarile</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Activarea acestei opțiuni va permite APatch să restaureze orice fișiere modificate de către modulele pentru această aplicație.</string>\n    <string name=\"su_show_system_apps\">Arată aplicațiile de sistem</string>\n    <string name=\"su_hide_system_apps\">Ascunde aplicațiile de sistem</string>\n    <string name=\"su_refresh\">Reîmprospătează</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"apm_not_installed\">AndroidPatch nu este instalat</string>\n    <string name=\"apm_failed_to_enable\">Nu se poate porni modulul \\\"%s\\\"</string>\n    <string name=\"apm_empty\">Niciun modul instalat</string>\n    <string name=\"apm_remove\">Elimină</string>\n    <string name=\"apm_install\">Instalează</string>\n    <string name=\"apm_uninstall_confirm\">Dezinstalezi modulul \\\"%s\\\"?</string>\n    <string name=\"apm_uninstall_success\">%s dezinstalat</string>\n    <string name=\"apm_uninstall_failed\">Nu s-a putut dezinstala %s</string>\n    <string name=\"apm_version\">Versiune</string>\n    <string name=\"apm_new_version_available\">Versiunea noua disponibila: %s, apasă pentru a actualiza.</string>\n    <string name=\"apm_author\">Autor</string>\n    <string name=\"apm_desc\">Descriere</string>\n    <string name=\"apm_overlay_fs_not_available\">Modulele nu sunt disponibile deoarece OverlayFS este dezactivat de kernel!</string>\n    <string name=\"apm_magisk_conflict\">Modulele nu sunt disponibile din cauza unui conflict cu Magisk!</string>\n    <string name=\"apm_reboot_to_apply\">Repornește pentru a intra în vigoare</string>\n    <string name=\"apm_changelog\">Jurnalul modificărilor</string>\n    <string name=\"apm_update\">Actualizează</string>\n    <string name=\"apm_downloading\">Descărcarea modulului \\\"%s\\\"…</string>\n    <string name=\"apm_start_downloading\">Începe descărcarea %s</string>\n    <string name=\"home_click_to_learn_apatch\">Afla despre funcționalitațile din APatch și cum să le folosești</string>\n    <string name=\"safe_mode\">Mod sigur</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"home_manager_version\">Versiunea de manager</string>\n    <string name=\"home_selinux_status\">Stare SELinux</string>\n    <string name=\"home_selinux_status_disabled\">Dezactivat</string>\n    <string name=\"su_pkg_excluded_label\">exclude</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"apm_failed_to_disable\">Nu se poate opri modulul \\\"%s\\\"</string>\n    <string name=\"settings_app_language\">Limbă</string>\n    <string name=\"system_default\">Implicit de sistem</string>\n    <string name=\"patch\">Interval</string>\n    <string name=\"settings_global_namespace_mode\">Modul namespace global</string>\n    <string name=\"settings_global_namespace_mode_summary\">Toate sesiunile root folosesc spațiul de nume de montare global</string>\n    <string name=\"success\">Succes</string>\n    <string name=\"failure\">Eșec</string>\n    <string name=\"settings_clear_super_key_dialog\">Ești sigur ca vrei să continui?</string>\n    <string name=\"settings_check_update\">Verifică pentru actualizări</string>\n    <string name=\"settings_check_update_summary\">Verificare automată a actualizarilor la deschiderea aplicației</string>\n    <string name=\"home_install_unknown_summary\">Click pentru instalare</string>\n    <string name=\"kpatch_version_update\">Versiune: %s -&gt; %s</string>\n    <string name=\"home_kpatch_info_title\">Informații</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_ap_cando_reboot\">Restart</string>\n    <string name=\"save_log\">Salvează log-urile</string>\n    <string name=\"patch_config_title\">selectia</string>\n    <string name=\"patch_mode_bootimg_patch\">Mod: Patch</string>\n    <string name=\"patch_mode_patch_and_install\">Mod: Patch și instalează</string>\n    <string name=\"patch_mode_uninstall_patch\">Mod: Dezinstalează KPatch</string>\n    <string name=\"patch_select_bootimg_btn\">Selectați boot</string>\n    <string name=\"patch_mode_install_to_next_slot\">Modalitate: Instalați în slotul inactiv (După OTA)</string>\n    <string name=\"patch_embed_kpm_btn\">Încorporați KPM</string>\n    <string name=\"patch_start_patch_btn\">Incepe</string>\n    <string name=\"patch_start_unpatch_btn\">UnPatch</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Versiune:</string>\n    <string name=\"patch_item_kpimg_config\">Configurație:</string>\n    <string name=\"patch_item_new_extra_kpm\">Incorporeaza nou</string>\n    <string name=\"patch_item_kpimg_comile_time\">Timp:</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_error\">!!EROARE!!</string>\n    <string name=\"patch_item_bootimg_slot\">slot:</string>\n    <string name=\"patch_item_kernel\">Nucleu:</string>\n    <string name=\"patch_item_bootimg_dev\">dispozitiv</string>\n    <string name=\"mode_select_page_title\">Instaleaza</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Dispozitivul dvs. va fi **Forțat** să pornească în slotul inactiv curent după o repornire!\n\\nFolosiți această opțiune numai după terminarea OTA.\n\\nContinua?</string>\n    <string name=\"purple_theme\">Mov</string>\n    <string name=\"red_theme\">Roșu</string>\n    <string name=\"sakura_theme\">Sakura</string>\n    <string name=\"hide_apatch_manager\">Ascunde APatch Manager</string>\n    <string name=\"hide_apatch_manager_summary\">Instalați o nouă aplicație de proxy cu un ID aleatoriu și o etichetă personalizată a aplicației</string>\n    <string name=\"enable_web_debugging_summary\">Poate fi folosit pentru a depana WebUI. Vă rugăm să activați numai când aveți nevoie.</string>\n    <string name=\"settings_donot_store_superkey\">Nu stocați Cheia Super local</string>\n    <string name=\"settings_donot_store_superkey_summary\">Autentificați Cheia Super de fiecare dată când managerul pornește</string>\n    <string name=\"home_new_apatch_found\">Versiune noua disponibila: %s, apasă pentru a actualiza.</string>\n    <string name=\"mode_select_page_patch_and_install\">Aplică Modificarea și instalează</string>\n    <string name=\"mode_select_page_select_file\">Selectați o imagine de pornire pentru modificare</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Instalați în slot inactiv (după OTA)</string>\n    <string name=\"home_dialog_auth_fail_title\">Autentificare nereusita</string>\n    <string name=\"teal_theme\">Verde-țiu</string>\n    <string name=\"yellow_theme\">Galben</string>\n    <string name=\"about_app_version\">Versiunea %1$s</string>\n    <string name=\"enable_web_debugging\">Activați depanarea WebView</string>\n    <string name=\"setting_reset_su_path\">Resetați calea</string>\n    <string name=\"setting_reset_su_new_path\">Cale noua deplina</string>\n    <string name=\"amber_theme\">Tema amber</string>\n    <string name=\"blue_grey_theme\">Tema albastru gri</string>\n    <string name=\"cyan_theme\">Cian</string>\n    <string name=\"brown_theme\">Tema maro</string>\n    <string name=\"deep_orange_theme\">Tema portocaliu adânc</string>\n    <string name=\"apm_action\">Actiune</string>\n    <string name=\"settings_custom_color_theme\">Tema de culoare</string>\n    <string name=\"blue_theme\">Tema albastru</string>\n    <string name=\"deep_purple_theme\">Tema mov adânc</string>\n    <string name=\"green_theme\">Verde</string>\n    <string name=\"indigo_theme\">Indigo</string>\n    <string name=\"light_blue_theme\">Albastru deschis</string>\n    <string name=\"light_green_theme\">Verde deschis</string>\n    <string name=\"lime_theme\">Lime</string>\n    <string name=\"orange_theme\">Portocaliu</string>\n    <string name=\"pink_theme\">Roz</string>\n    <string name=\"apm_webui_open\">Deschis</string>\n    <string name=\"home_dialog_auth_fail_content\">Nu se poate autentifica Cheia Super, prin urmare APatch nu poate funcționa corect.\\nAici sunt câteva motive posibile pentru eșecul autentificării:\\n1. Nu ați modificat fișierul boot.img utilizând KernelPatch.\\n2. Imaginea de pornire boot.img nu a fost integrată.\\n3. Cheia Super este greșită sau conține caractere speciale.\\n4. Dispozitivul dvs. nu acceptă APatch și KernelPatch.\\n\\nVă rugăm să verificați și să încercați din nou. Dacă există încă probleme, puteți oricând să puneți întrebări pe pagina de probleme a repozitorului oficial.</string>\n    <string name=\"settings_use_system_color_theme_summary\">Utilizați o temă de culoare generată de sistem bazat pe fundalul actual</string>\n    <string name=\"home_device_info\">Dispozitiv</string>\n    <string name=\"kpm_add_kpm\">Adaugă KPM</string>\n    <string name=\"kpm_install\">Instalează</string>\n    <string name=\"settings_night_mode_follow_sys\">Urmați Tema întunecată al sistemului</string>\n    <string name=\"patch_item_extra_version\">Versiune:</string>\n    <string name=\"patch_item_extra_author\">Autor:</string>\n    <string name=\"patch_item_extra_args\">Argumente:</string>\n    <string name=\"kpm_control_paramters\">Parametri</string>\n    <string name=\"kpm_control_outMsg\">Mesaj</string>\n    <string name=\"kpm_control_ok\">Operațiune reusită!</string>\n    <string name=\"kpm_control_failed\">Operațiune ieșuată!</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Schimbați automat la tema întunecată bazat pe setările sistemului</string>\n    <string name=\"settings_night_theme_enabled\">\"Activează tema Întunecată \"</string>\n    <string name=\"settings_use_system_color_theme\">Tema de culoare a sistemului</string>\n    <string name=\"patch_item_existed_extra_kpm\">Existent</string>\n    <string name=\"patch_item_extra_kpm_license\">Licență:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Descripție:</string>\n    <string name=\"patch_item_extra_event\">Eveniment:</string>\n    <string name=\"patch_item_skey\">Cheie Super</string>\n    <string name=\"patch_item_set_skey_label\">Lungimea cheii super trebuie să fie între 8-63 caractere și să include numere si litere, dar nu caractere speciale.</string>\n    <string name=\"home_system_version\">Versiune de sistem</string>\n    <string name=\"home_kpatch_version\">Versiune KernelPatch</string>\n    <string name=\"kpm_control\">Verifica</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Nume nou manager</string>\n    <string name=\"hide_apatch_dialog_summary\">Va fi folosit ca noua etichetă a aplicației afișată în launcher</string>\n    <string name=\"hide_apatch_manager_failure\">Nu s-a ascuns, vă rugăm să raportați eroarea!</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Feedback sau sugestie</string>\n    <string name=\"about_telegram_channel\">Canalul Telegram</string>\n    <string name=\"home_more_menu_about\">Despre</string>\n    <string name=\"home_dialog_uninstall_title\">Dezinstaleaza</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Elimina AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Dezinstalează tot</string>\n    <string name=\"kpm_control_dialog_title\">Controlați KPModule</string>\n    <string name=\"kpm_control_dialog_content\">Indicați parametrii de verificare:</string>\n    <string name=\"about_telegram_group\">Grupul Telegram</string>\n    <string name=\"about_app_desc\">Soluție Kernel Root cu doar o imagine goală a kernel-ului, oferind abilitatea de a monta modulul de sistem și de a lega funcția kernel.</string>\n    <string name=\"about_powered_by\">Produs de %1$s</string>\n    <string name=\"kpm_embed\">Încorporează</string>\n    <string name=\"patch_item_extra_name\">Nume:</string>\n    <string name=\"log_saved\">Jurnal salvat</string>\n    <string name=\"crash_handle_title\">Aplicația s-a blocat…</string>\n    <string name=\"crash_handle_copy\">Copiază jurnalul de eroare</string>\n    <string name=\"crash_handle_copied\">Jurnal de eroare copiat în clipboard.</string>\n    <string name=\"settings_lite_mode\">Activați mod Lite</string>\n    <string name=\"settings_lite_mode_mode_summary\">Funcții APModule pot prezenta eșecuri după ce sunt pornite, dar în câteva cazuri ele pot în continuare sa evadeze detecție. Repornire nevoită.</string>\n    <string name=\"settings_force_overlayfs_mode\">Forțează utilizarea de OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Utilizați OverlayFS sa montați APModules în loc de Magic Mount când suport de kernel este disponibil. Repornire nevoită.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">Главная</string>\n    <string name=\"super_key\">СуперКлюч</string>\n    <string name=\"patch_warnning\">Пожалуйста, убедитесь, что у вас есть резервная копия ваших данных. Установка сопряжена с рисками.</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"home_not_installed\">Не установлено</string>\n    <string name=\"home_install_unknown\">Не установлено или не авторизовано</string>\n    <string name=\"home_click_to_install\">Нажмите чтобы установить</string>\n    <string name=\"home_working\">Работает 😋</string>\n    <string name=\"home_installing\">Установка</string>\n    <string name=\"home_need_update\">Доступна новая версия</string>\n    <string name=\"kpatch_version\">Версия: %s</string>\n    <string name=\"apatch_version\">Версия: %s</string>\n    <string name=\"apatch_version_update\">Версия: %s → %s</string>\n    <string name=\"home_su_path\">Исполняемый файл su</string>\n    <string name=\"home_apatch_version\">Версия APatch</string>\n    <string name=\"home_kernel\">Версия ядра</string>\n    <string name=\"home_manager_version\">Версия менеджера</string>\n    <string name=\"home_fingerprint\">Отпечаток</string>\n    <string name=\"home_selinux_status\">Состояние SELinux</string>\n    <string name=\"home_selinux_status_disabled\">Отключено</string>\n    <string name=\"home_selinux_status_enforcing\">Принудительный</string>\n    <string name=\"home_selinux_status_permissive\">Разрешающий</string>\n    <string name=\"home_selinux_status_unknown\">Неизвестно</string>\n    <string name=\"su_title\">SuperUser</string>\n    <string name=\"apm_failed_to_enable\">Не удалось включить модуль \\\"%s\\\"</string>\n    <string name=\"apm_failed_to_disable\">Не удалось отключить модуль \\\"%s\\\"</string>\n    <string name=\"apm_empty\">Модуль не установлен</string>\n    <string name=\"kpm\">Модули KP</string>\n    <string name=\"apm\">Модули AP</string>\n    <string name=\"apm_remove\">Удалить</string>\n    <string name=\"kpm_load\">Загрузить</string>\n    <string name=\"apm_install\">Установить</string>\n    <string name=\"reboot\">Перезагрузить</string>\n    <string name=\"settings\">Настройки</string>\n    <string name=\"reboot_recovery\">Перезагрузить в режим Recovery</string>\n    <string name=\"reboot_bootloader\">Перезагрузить в Bootloader</string>\n    <string name=\"reboot_download\">Перезагрузить в Download</string>\n    <string name=\"reboot_edl\">Перезагрузить в EDL</string>\n    <string name=\"about\">О приложении</string>\n    <string name=\"apm_uninstall_confirm\">Удалить модуль \\\"%s\\\"?</string>\n    <string name=\"apm_uninstall_success\">%s удален</string>\n    <string name=\"apm_uninstall_failed\">Не удалось удалить %s</string>\n    <string name=\"apm_version\">Версия</string>\n    <string name=\"apm_author\">Автор</string>\n    <string name=\"apm_desc\">Описание</string>\n    <string name=\"apm_overlay_fs_not_available\">Модули недоступны, так как OverlayFS отключен в ядре!</string>\n    <string name=\"su_refresh\">Обновить</string>\n    <string name=\"su_show_system_apps\">Показать системные приложения</string>\n    <string name=\"su_hide_system_apps\">Скрыть системные приложения</string>\n    <string name=\"send_log\">Отправить журналы</string>\n    <string name=\"safe_mode\">Безопасный режим</string>\n    <string name=\"apm_reboot_to_apply\">Перезагрузите, чтобы изменения вступили в силу</string>\n    <string name=\"apm_magisk_conflict\">Модули недоступны из-за конфликта с Magisk!</string>\n    <string name=\"home_learn_apatch\">Узнать больше про APatch</string>\n    <string name=\"home_click_to_learn_apatch\">Узнайте о возможностях APatch и о том, как его использовать</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Посмотрите исходный код на %1$s<p/>Присоединяйтесь к нашему каналу %2$s</p>Присоединяйтесь к нашей группе %3$s]]></string>\n    <string name=\"apm_update\">Обновить</string>\n    <string name=\"apm_downloading\">Скачивание модуля \\\"%s\\\"…</string>\n    <string name=\"apm_start_downloading\">Начало скачивания %s</string>\n    <string name=\"apm_new_version_available\">Доступна новая версия %s, нажмите для обновления.</string>\n    <string name=\"apm_changelog\">Список изменений</string>\n    <string name=\"patch_set_superkey\">Установить СуперКлюч</string>\n    <string name=\"kpm_load_toast_failed\">Загрузка не удалась</string>\n    <string name=\"home_auth_key_desc\">Начать после сертификации</string>\n    <string name=\"home_patch_set_key_desc\">Ключ только для KernelPatch</string>\n    <string name=\"home_patch_next_step\">Далее</string>\n    <string name=\"home_auth_key_title\">Введите СуперКлюч</string>\n    <string name=\"patch_title\">Патч</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch не установлен</string>\n    <string name=\"kpm_load_toast_succ\">Загружено успешно</string>\n    <string name=\"kpm_unload\">Выгрузить</string>\n    <string name=\"kpm_apm_empty\">Модуль не загружен</string>\n    <string name=\"kpm_version\">Версия</string>\n    <string name=\"kpm_license\">Лицензия</string>\n    <string name=\"kpm_author\">Автор</string>\n    <string name=\"kpm_desc\">Описание</string>\n    <string name=\"kpm_args\">Аргументы</string>\n    <string name=\"su_selinux_via_hook\">обход через хук</string>\n    <string name=\"su_pkg_excluded_label\">исключён</string>\n    <string name=\"su_pkg_excluded_setting_title\">Запретить изменения</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Включение этой опции позволит APatch восстановить любые файлы этого приложения, которые были модифицированы модулями.</string>\n    <string name=\"home_ap_cando_install\">Установить</string>\n    <string name=\"home_ap_cando_update\">Обновить</string>\n    <string name=\"home_ap_cando_uninstall\">Деинсталлировать</string>\n    <string name=\"kpm_unload_confirm\">Выгрузить модуль \\\"%s\\\"?</string>\n    <string name=\"clear_super_key\">Стереть СуперКлюч</string>\n    <string name=\"apm_not_installed\">AndroidPatch не установлен</string>\n    <string name=\"settings_app_language\">Язык</string>\n    <string name=\"system_default\">Как в системе</string>\n    <string name=\"patch\">Патч</string>\n    <string name=\"settings_global_namespace_mode\">Режим глобального пространства имён</string>\n    <string name=\"settings_global_namespace_mode_summary\">Все сеансы суперпользователя root используют монтирование глобального пространства имён</string>\n    <string name=\"kpatch_version_update\">Версия: %s → %s</string>\n    <string name=\"home_kpatch_info_title\">Подробнее</string>\n    <string name=\"home_ap_cando_reboot\">Перезагрузить</string>\n    <string name=\"patch_config_title\">Патчи</string>\n    <string name=\"patch_mode_uninstall_patch\">Режим: Удаление KPatch</string>\n    <string name=\"patch_select_bootimg_btn\">Выберите boot</string>\n    <string name=\"patch_embed_kpm_btn\">Встроить KPM</string>\n    <string name=\"patch_start_patch_btn\">Начать</string>\n    <string name=\"patch_start_unpatch_btn\">Отмена патча</string>\n    <string name=\"patch_item_error\">!!ОШИБКА!!</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_bootimg_slot\">слот:</string>\n    <string name=\"patch_item_bootimg_dev\">устройство:</string>\n    <string name=\"patch_item_kernel\">Ядро</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_comile_time\">\"Время:\"</string>\n    <string name=\"patch_item_kpimg_config\">\"Настройка:\"</string>\n    <string name=\"patch_item_new_extra_kpm\">Встроить новый</string>\n    <string name=\"patch_item_existed_extra_kpm\">Встраиваемый</string>\n    <string name=\"patch_item_extra_kpm_desciption\">\"Описание:\"</string>\n    <string name=\"patch_item_extra_args\">\"Аргументы:\"</string>\n    <string name=\"patch_item_extra_event\">\"Событие:\"</string>\n    <string name=\"patch_item_skey\">СуперКлюч</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"patch_mode_bootimg_patch\">Режим: Патч</string>\n    <string name=\"patch_mode_patch_and_install\">Режим: Патчить и установить</string>\n    <string name=\"patch_item_kpimg_version\">\"Версия:\"</string>\n    <string name=\"patch_item_extra_name\">Название:</string>\n    <string name=\"patch_item_extra_version\">\"Версия:\"</string>\n    <string name=\"patch_item_extra_author\">\"Автор:\"</string>\n    <string name=\"patch_item_extra_kpm_license\">\"Лицензия:\"</string>\n    <string name=\"settings_clear_super_key_dialog\">Вы действительно хотите продолжить?</string>\n    <string name=\"patch_item_set_skey_label\">Длина СуперКлюч должна быть не менее 8 символов и включать только цифры и буквы.</string>\n    <string name=\"failure\">Ошибка</string>\n    <string name=\"kpm_install\">Установить</string>\n    <string name=\"kpm_embed\">Встроить</string>\n    <string name=\"kpm_add_kpm\">Добавить KPM</string>\n    <string name=\"success\">Успешно</string>\n    <string name=\"hide_apatch_manager\">Скрыть менеджер APatch</string>\n    <string name=\"hide_apatch_manager_failure\">Не удалось скрыть. Пожалуйста, сообщите об ошибке!</string>\n    <string name=\"hide_apatch_dialog_summary\">Оно будет использоваться как новое название приложения</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Новое название менеджера</string>\n    <string name=\"setting_reset_su_path\">Изменить путь к su</string>\n    <string name=\"hide_apatch_manager_summary\">Установите прокси-приложение со случайным ID пакета и польз. ярлыком приложения</string>\n    <string name=\"setting_reset_su_new_path\">Новый полный путь</string>\n    <string name=\"cyan_theme\">Бирюзовая</string>\n    <string name=\"pink_theme\">Розовая</string>\n    <string name=\"lime_theme\">Лаймовая</string>\n    <string name=\"mode_select_page_select_file\">Выберите образ boot, который следует пропатчить</string>\n    <string name=\"settings_donot_store_superkey\">Не хранить СуперКлюч в памяти устройства</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Ваше устройство будет **ПРИНУДЕТЕЛЬНО** загружено в текущий неактивный слот после перезагрузки!\\nИспользуйте эту опцию только после успешной установки OTA.\\nПродолжить?</string>\n    <string name=\"kpm_control\">Управление</string>\n    <string name=\"mode_select_page_patch_and_install\">Пропатчить и установить</string>\n    <string name=\"settings_donot_store_superkey_summary\">Вам придётся вводить СуперКлюч каждый раз при открытии менеджера</string>\n    <string name=\"home_dialog_auth_fail_content\">Не удалось проверить суперключ, поэтому APatch не может работать.\\nВот некоторые возможные причины этой ошибки:\\n1. Вы не пропатчили boot.img с помощью KernelPatch.\\n2. Вы забыли прошить патченный boot.img\\n3. Неверный СуперКлюч.\\n4. Ваше устройство не поддерживает APatch и KernelPatch.\\n\\nПожалуйста, установите APatch повторно и проверьте, правильный ли суперключ вы вводите. Если это не помогло, сообщите нам об ошибке или задайте вопрос в Issues официального репозитория.</string>\n    <string name=\"home_more_menu_about\">О приложении</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Удалить AndroidPatch</string>\n    <string name=\"kpm_control_dialog_title\">Управление KPModule</string>\n    <string name=\"kpm_control_ok\">Операция выполнена успешно!</string>\n    <string name=\"orange_theme\">Оранжевая</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Автоматически переключаться на тёмную тему, соблюдая системные настройки</string>\n    <string name=\"about_app_desc\">Решение для получения прав суперпользователя, работающее на уровне ядра, предоставляющее возможность монтировать модули системы и модифицировать функции ядра.</string>\n    <string name=\"about_telegram_channel\">Канал в Telegram</string>\n    <string name=\"about_telegram_group\">Группа в Telegram</string>\n    <string name=\"about_powered_by\">Основано на %1$s</string>\n    <string name=\"home_install_unknown_summary\">Нажмите, чтобы установить</string>\n    <string name=\"home_kpatch_version\">Версия KernelPatch</string>\n    <string name=\"home_new_apatch_found\">Доступна новая версия: %s, Нажмите здесь для обновления.</string>\n    <string name=\"mode_select_page_title\">Установить</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Установить в неактивный слот (после OTA)</string>\n    <string name=\"home_dialog_auth_fail_title\">Ошибка авторизации</string>\n    <string name=\"home_dialog_uninstall_all\">Полное удаление</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Обратная связь и предложения</string>\n    <string name=\"home_dialog_uninstall_title\">Удалить</string>\n    <string name=\"kpm_control_dialog_content\">Введите параметры контроля:</string>\n    <string name=\"kpm_control_paramters\">Параметры</string>\n    <string name=\"kpm_control_outMsg\">Сообщение</string>\n    <string name=\"kpm_control_failed\">Операция не удалась!</string>\n    <string name=\"settings_night_mode_follow_sys\">Придерживаться тёмной темы системы</string>\n    <string name=\"settings_use_system_color_theme\">Системная цветовая тема</string>\n    <string name=\"settings_use_system_color_theme_summary\">Использовать цветовую тему, созданную системой на основе текущих обоев</string>\n    <string name=\"settings_custom_color_theme\">Цветовая тема</string>\n    <string name=\"deep_orange_theme\">Тёмно-оранжевая</string>\n    <string name=\"deep_purple_theme\">Тёмно-фиолетовая</string>\n    <string name=\"light_blue_theme\">Голубая</string>\n    <string name=\"light_green_theme\">Салатовая</string>\n    <string name=\"purple_theme\">Фиолетовая</string>\n    <string name=\"red_theme\">Красная</string>\n    <string name=\"sakura_theme\">Сакура</string>\n    <string name=\"teal_theme\">Морская</string>\n    <string name=\"yellow_theme\">Жёлтая</string>\n    <string name=\"green_theme\">Зелёная</string>\n    <string name=\"indigo_theme\">Индиго</string>\n    <string name=\"patch_mode_install_to_next_slot\">Режим: Установить в неактивный слот (После OTA)</string>\n    <string name=\"about_app_version\">Версия %1$s</string>\n    <string name=\"apm_webui_open\">Открыть</string>\n    <string name=\"settings_check_update\">Проверьте наличие обновлений</string>\n    <string name=\"settings_check_update_summary\">Автоматическая проверка обновлений при открытии приложения</string>\n    <string name=\"home_device_info\">Устройство</string>\n    <string name=\"home_system_version\">Версия системы</string>\n    <string name=\"settings_night_theme_enabled\">Включить темную тему</string>\n    <string name=\"enable_web_debugging\">Включить отладку WebView</string>\n    <string name=\"amber_theme\">Янтарная</string>\n    <string name=\"brown_theme\">Коричневая</string>\n    <string name=\"blue_grey_theme\">Сине-серая</string>\n    <string name=\"blue_theme\">Синяя</string>\n    <string name=\"enable_web_debugging_summary\">Используется для отладки WebUI. Пожалуйста, включайте только при необходимости.</string>\n    <string name=\"save_log\">Сохранить журналы</string>\n    <string name=\"apm_action\">Действие</string>\n    <string name=\"crash_handle_copy\">Скопировать журнал сбоев</string>\n    <string name=\"crash_handle_copied\">Журнал сбоев скопирован в буфер обмена.</string>\n    <string name=\"log_saved\">Логи сохранены</string>\n    <string name=\"crash_handle_title\">Сбой приложения…</string>\n    <string name=\"settings_lite_mode\">Включить режим Lite</string>\n    <string name=\"settings_lite_mode_mode_summary\">Функции APModule могут проявлять сбои после включения, но в некоторых случаях они все еще могут эффективно избегать обнаружения. Требуется перезагрузка.</string>\n    <string name=\"settings_force_overlayfs_mode\">Принудительное использование OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Используйте OverlayFS для монтирования APModules вместо Magic Mount, когда поддержка ядра доступна. Требуется перезагрузка.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-si/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">මුල් පිටුව</string>\n    <string name=\"reboot\">Restart කරන්න</string>\n    <string name=\"about\">APatch පිළිබඳ</string>\n    <string name=\"super_key\">මුරපදය</string>\n    <string name=\"patch_set_superkey\">නව මුර පදයක් සෑදීම</string>\n    <string name=\"home_patch_set_key_desc\">ඔබගේ මුරපදය ඇතුළත් කරන්න</string>\n    <string name=\"home_patch_next_step\">ඉදිරියට</string>\n    <string name=\"home_not_installed\">ස්ථාපනය වී නොමැත</string>\n    <string name=\"home_click_to_install\">ස්ථාපනය කරන්න</string>\n    <string name=\"home_need_update\">නව අනුවාදයක් තිබේ</string>\n    <string name=\"home_ap_cando_install\">ස්ථාපනය කරන්න</string>\n    <string name=\"home_ap_cando_uninstall\">ඉවත් කරන්න</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch ස්ථාපනය කර නොමැත</string>\n    <string name=\"kpm_author\">කතෲ</string>\n    <string name=\"apm_not_installed\">AndroidPatch ස්ථාපනය කර නොමැත</string>\n    <string name=\"apm_empty\">කිසිම module එකක් නොමැත</string>\n    <string name=\"apm_install\">ස්ථාපනය කරන්න</string>\n    <string name=\"apm_uninstall_confirm\">මෙම මොඩියුලය ඉවත් කිරීමට අවශ්‍ය ද %s ?</string>\n    <string name=\"apm_uninstall_success\">%s ඉවත් කරන ලදී</string>\n    <string name=\"apm_uninstall_failed\">ඉවත් කිරීමට නොහැකි විය: %s</string>\n    <string name=\"apm_failed_to_disable\">මෙම මොඩියුලය ක්‍රියාවිරහිත කිරීමට නොහැකි විය: %s</string>\n    <string name=\"apm_reboot_to_apply\">Apply කිරීම සඳහා reboot කිරීම අනිවාර්ය වේ</string>\n    <string name=\"apm_new_version_available\">නව අනුවාදය ස්ථාපනයට ඔබන්න, %s.</string>\n    <string name=\"home_learn_apatch\">AndroidPatch ගැන ඉගෙන ගන්න</string>\n    <string name=\"home_click_to_learn_apatch\">මෙතන Click කරන්න</string>\n    <string name=\"patch_warnning\">Install කරද්දි මොකක්ම හරි අවුලක් ආවොත් ඔයාගේ Data lost වේවි. ඒක නිසා වැදගත් දේවල් Backup කරගෙනම ඉන්න.</string>\n    <string name=\"send_log\">Log යවන්න</string>\n    <string name=\"clear_super_key\">මුරපදය මකා දමන්න</string>\n    <string name=\"home_install_unknown\">හඳුනා ගැනීමට නොහැක</string>\n    <string name=\"home_auth_key_desc\">මුරපදය ඇතුළත් කරන්න</string>\n    <string name=\"home_working\">වැඩ කරමින් තිබේ</string>\n    <string name=\"su_hide_system_apps\">System Apps පෙන්වීම නතර කරන්න</string>\n    <string name=\"home_installing\">ස්ථාපනය කරමින්</string>\n    <string name=\"su_show_system_apps\">System Apps ද පෙන්වන්න</string>\n    <string name=\"home_auth_key_title\">මුරපදය</string>\n    <string name=\"apm_overlay_fs_not_available\">ඔයාගේ Kernel එකේ OverlayFS කියන function එක enable වෙලා නැහැ. මේකට අපිටම කියලා OverlayFS enable කරපු Kernel එකක් compile කරගන්න ඕනි 😕!</string>\n    <string name=\"apm_remove\">ඉවත් කරන්න</string>\n    <string name=\"apm_magisk_conflict\">Magisk හි මොඩියුල්ස් සමග ගැටෙන නිසා, මෙම විශේෂාංගය තාවකාලිකව ක්‍රියා විරහිත කර ඇත!</string>\n    <string name=\"apm_failed_to_enable\">මෙම මොඩියුලය ක්‍රියාත්මක කිරීමට නොහැකි විය: %s</string>\n    <string name=\"safe_mode\">ආරක්ෂාකාරී mode එක</string>\n    <string name=\"reboot_edl\">EDL Mode එකට</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"kpm_load_toast_succ\">සාර්ථකව එකතු කරන ලදී</string>\n    <string name=\"home_selinux_status\">SELinux තත්වය</string>\n    <string name=\"apm_update\">යාවත්කාලීන කරන්න</string>\n    <string name=\"about_source_code\">මූල කේතය බලන්න %1$s<br/> අපේ ටෙලිග්‍රෑම් චැනලයට එකතු වන්න %2$s</string>\n    <string name=\"settings\">සැකසුම්</string>\n    <string name=\"reboot_recovery\">Recovery එකට</string>\n    <string name=\"reboot_bootloader\">Fastboot mode එකට</string>\n    <string name=\"reboot_download\">Download mode එකට</string>\n    <string name=\"kpatch_version\">අනුවාදය: %s</string>\n    <string name=\"apatch_version_update\">අනුවාදය: %s -&gt; %s</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"home_su_path\">රූට්:%s</string>\n    <string name=\"home_ap_cando_update\">යාවත්කාලීන කරන්න</string>\n    <string name=\"home_selinux_status_disabled\">ඕෆ් කරන්න</string>\n    <string name=\"home_selinux_status_unknown\">හඳුනාගත නොහැක</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"kpm_load\">එකතු කරන්න</string>\n    <string name=\"kpm_load_toast_failed\">එකතු කිරීමට නොහැකි විය</string>\n    <string name=\"kpm_unload_confirm\">මෙම \\\"%s\\\" මොඩියුල් එක ඉවත් කිරීමට අවශ්‍ය ද?</string>\n    <string name=\"kpm_unload\">ඉවත් කරන්න</string>\n    <string name=\"kpm_apm_empty\">දැනට කිසිඳු මොඩියුල් එකක් භාවිතා කර නැත</string>\n    <string name=\"kpm_license\">බලපත්‍රය</string>\n    <string name=\"kpm_desc\">අවරෝහණ</string>\n    <string name=\"su_title\">රූට්</string>\n    <string name=\"su_pkg_excluded_setting_summary\">මොඩියුල්ස් සඳහා</string>\n    <string name=\"home_apatch_version\">APatch අනුවාදය</string>\n    <string name=\"home_kernel\">කර්නල් එක</string>\n    <string name=\"home_manager_version\">කළමනාකරණයේ අනුවාදය</string>\n    <string name=\"home_fingerprint\">ආරක්ෂක සළකුණ</string>\n    <string name=\"su_refresh\">නැවත අලුත් කරන්න</string>\n    <string name=\"apm\">මොඩියුල්ස්</string>\n    <string name=\"system_default\">Android හි භාෂාවම</string>\n    <string name=\"apm_version\">අනුවාදය</string>\n    <string name=\"apm_desc\">අවරෝහණ</string>\n    <string name=\"apm_changelog\">අලුත් දේවල්</string>\n    <string name=\"apm_downloading\">\\\"%s\\\" මොඩියුලය බාගත වෙමින්…</string>\n    <string name=\"apm_start_downloading\">බාගත කිරීම ආරම්භ කළා %s</string>\n    <string name=\"settings_app_language\">භාෂාව</string>\n    <string name=\"kpm_version\">අනුවාදය</string>\n    <string name=\"apatch_version\">අනුවාදය: %s</string>\n    <string name=\"patch_title\">පැච් කරන්න</string>\n    <string name=\"apm_author\">කතෲ</string>\n    <string name=\"patch\">පැච් කරන්න</string>\n    <string name=\"kpm_args\">Args</string>\n    <string name=\"setting_reset_su_new_path\">නව සම්පූර්ණ මාර්ගය</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">දැන් ඔෆ් වෙලා ඔන් උනාම **බලහත්කාරයෙන්ම** අක්‍රීය වෙලා තියන ස්ලොට් එක්කට තමා ඔන් වෙන්නේ!\\nOTA එක ඉවර උනාම විතරක් මේක පාවිච්චි කරන්න හොදේ.\\nඉස්සරහට කරන් යන්නද?</string>\n    <string name=\"home_install_unknown_summary\">Install කිරීමට ක්ලික් කරන්න</string>\n    <string name=\"patch_item_skey\">සුපිරි යතුර</string>\n    <string name=\"patch_item_kernel\">කර්නලය</string>\n    <string name=\"patch_item_extra_kpm_license\">බලපත්‍රය:</string>\n    <string name=\"su_pkg_excluded_setting_title\">වෙනස් කිරීම් අතෑරලා දාන්න</string>\n    <string name=\"home_dialog_auth_fail_content\">Super Key එක සත්‍යාපනය කරන්න බෑ, ඒ හින්දා APatch හරියට වැඩ කරන්නේ නෑ.\\nසත්‍යාපනය අවුල් වෙන්න හේතු ටිකක් මෙන්න:\\n1. ඔයා boot image එක KernelPatch එක්ක පැච් කර නැ.\\n2. පැච් කරපු boot image එක flash වෙලා නෑ.\\n3. Super key එක වැරදි.\\n4. ඔබගේ උපාංගය APatch සහ KernelPatch වලට හරියන්නේ නෑ වගේ .\\n\\nතව පාරක් ට්‍රයි කරලා බලන්න. තවමත් ඒත් හරියන්නේ නැත්තං , ඔයාට හැම වෙලේම නිල ගැටළු ඇසීමේ පිටුවෙන් ප්‍රශ්න ඇසීමට හැකිය.</string>\n    <string name=\"indigo_theme\">ඉන්ඩිගෝ Theme</string>\n    <string name=\"light_blue_theme\">ලා නිල් Theme</string>\n    <string name=\"patch_item_bootimg_dev\">උපාංගය:</string>\n    <string name=\"patch_item_extra_version\">අනුවාදය:</string>\n    <string name=\"patch_item_extra_author\">කතෘ:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">විස්තරය:</string>\n    <string name=\"patch_item_extra_args\">Args:</string>\n    <string name=\"kpm_control\">පාලනය කරන්න</string>\n    <string name=\"success\">සාර්ථකයි</string>\n    <string name=\"failure\">අසාර්ථක වීම</string>\n    <string name=\"settings_global_namespace_mode\">Global නාම අවකාශයේ Mode</string>\n    <string name=\"settings_clear_super_key_dialog\">ඇත්තටම ඉදිරියට යාමට අවශ්‍යද?</string>\n    <string name=\"settings_global_namespace_mode_summary\">සියලුම root සැසි ගෝලීය මවුන්ට් නාම අවකාශය භාවිතා කරයි</string>\n    <string name=\"settings_check_update\">අප්ඩේට් චෙක් කරන්න</string>\n    <string name=\"settings_check_update_summary\">යෙදුම open කිරීමේදී Update සඳහා ස්වයංක්‍රීයව පරීක්ෂා කරන්න</string>\n    <string name=\"patch_select_bootimg_btn\">Boot කරන්න තෝරන්න</string>\n    <string name=\"patch_embed_kpm_btn\">KPM යොදන්න</string>\n    <string name=\"patch_start_patch_btn\">\"යං \"</string>\n    <string name=\"patch_item_bootimg\">බුටිම්</string>\n    <string name=\"patch_start_unpatch_btn\">UnPatch</string>\n    <string name=\"patch_item_error\">!!අවුලක්!!</string>\n    <string name=\"patch_item_bootimg_slot\">ස්ලොට්</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">අනුවාදය:</string>\n    <string name=\"patch_item_kpimg_comile_time\">වේලාව:</string>\n    <string name=\"patch_item_extra_name\">නම:</string>\n    <string name=\"home_system_version\">පද්ධතියේ අනුවාදය</string>\n    <string name=\"home_kpatch_version\">KernelPatch අනුවාදය</string>\n    <string name=\"kpm_embed\">Embed</string>\n    <string name=\"su_selinux_via_hook\">Hook වලින් බයිපාස්</string>\n    <string name=\"settings_use_system_color_theme\">සිස්ටම් පාටපාට Theme</string>\n    <string name=\"settings_custom_color_theme\">පාට Theme</string>\n    <string name=\"deep_orange_theme\">Deep Orange Theme</string>\n    <string name=\"light_green_theme\">ලා කොළ Theme</string>\n    <string name=\"lime_theme\">Lime Theme</string>\n    <string name=\"orange_theme\">තැඹිලි Theme</string>\n    <string name=\"purple_theme\">දම් Theme</string>\n    <string name=\"red_theme\">රතු Theme</string>\n    <string name=\"sakura_theme\">සකුරා Theme</string>\n    <string name=\"teal_theme\">Teal Theme</string>\n    <string name=\"yellow_theme\">කහ Theme</string>\n    <string name=\"save_log\">Logs සටහන් සුරකින්න</string>\n    <string name=\"kpatch_version_update\">අනුවාදය: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">තොරතුරු</string>\n    <string name=\"home_ap_cando_reboot\">රී බුට් කරන්න</string>\n    <string name=\"patch_config_title\">Patches</string>\n    <string name=\"patch_mode_bootimg_patch\">Mode: පැච්</string>\n    <string name=\"patch_mode_patch_and_install\">Mode: පැච් සහ ඉන්ස්ට්‍රොල් කරන්න</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mode : ඊළඟ slot වෙත ස්ථාපනය කරන්න (OTA න් පසු)</string>\n    <string name=\"patch_mode_uninstall_patch\">Mode: KPatch අයින් කරන්න</string>\n    <string name=\"patch_item_kpimg_config\">කොන්ෆිග්:</string>\n    <string name=\"patch_item_new_extra_kpm\">අලුතින් දාන්න</string>\n    <string name=\"patch_item_existed_extra_kpm\">තිබ්බා</string>\n    <string name=\"patch_item_extra_event\">සිදුවීම:</string>\n    <string name=\"patch_item_set_skey_label\">Supper Key යෙහි අඩුම තරමින් අකුරු 8 ක් දාන්න ඕන, අංකයි අකුරු දෙකම දාන්න ඕන.</string>\n    <string name=\"home_selinux_status_enforcing\">බලාත්මක කිරීම</string>\n    <string name=\"home_selinux_status_permissive\">අවසරයි</string>\n    <string name=\"home_device_info\">උපාංගය</string>\n    <string name=\"kpm_add_kpm\">KPM ඒකතුකරන්න</string>\n    <string name=\"kpm_install\">දාන්න</string>\n    <string name=\"su_pkg_excluded_label\">exclude</string>\n    <string name=\"hide_apatch_manager_summary\">අහඹු පැකේජ ID සහ කස්නටම් app ලෙබලයක් සමග අලුත් මැනේජර් app එක්ක දාන්න</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">අලුත් මැනේජර් ගේ නම</string>\n    <string name=\"hide_apatch_dialog_summary\">මෙය භාවිතා කරන නව යෙදුම් ලේබලය ලෙස භාවිතා කරනු ඇත</string>\n    <string name=\"hide_apatch_manager_failure\">හංගන්න බෑ වගේනේ, කරුණාකර අවුල වාර්තා කරන්න!</string>\n    <string name=\"setting_reset_su_path\">Su patch රීසෙට් කරන්න</string>\n    <string name=\"settings_donot_store_superkey\">Super Key එක phone එකේ කොහේවත් තියාගන්න එපා</string>\n    <string name=\"home_new_apatch_found\">නව අනුවාදයක් තිබේ: %s, උත්ශ්‍රේණියට ඔබන්න</string>\n    <string name=\"home_dialog_auth_fail_title\">සත්‍යාපනය වැරදි වගේ</string>\n    <string name=\"kpm_control_dialog_content\">ඉන්පුට් control parameters:</string>\n    <string name=\"kpm_control_ok\">වැඩේ ගොඩ ලොක්කා!</string>\n    <string name=\"kpm_control_failed\">වැඩේ කෙලවුනා!</string>\n    <string name=\"settings_use_system_color_theme_summary\">Wallpaper එකත් එක්කම වෙනස් වෙන පද්ධති පාටක් ගන්න</string>\n    <string name=\"amber_theme\">ඇම්බර් තේමාව</string>\n    <string name=\"blue_grey_theme\">BlueGrey Theme</string>\n    <string name=\"blue_theme\">නිල් Theme</string>\n    <string name=\"brown_theme\">දුඹුරු Theme</string>\n    <string name=\"cyan_theme\">Cyan Theme</string>\n    <string name=\"settings_donot_store_superkey_summary\">මැනේජර් ආරම්භ කරන හැම වෙලේම Super Key එක ඉල්ලන්න</string>\n    <string name=\"mode_select_page_title\">දාන්න</string>\n    <string name=\"apm_action\">අක්ෂන්</string>\n    <string name=\"mode_select_page_patch_and_install\">පැච් එකත් එක්ක දාන්න</string>\n    <string name=\"mode_select_page_select_file\">Boot image එක තෝරන්න පැච් කරන්න</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">අවුලක් කියන්න හෝ යෝජනා කරන්න</string>\n    <string name=\"home_more_menu_about\">මේ ගැන</string>\n    <string name=\"home_dialog_uninstall_title\">අයින් කරන්න</string>\n    <string name=\"home_dialog_uninstall_ap_only\">AndroidPatch අයින් කරන්න</string>\n    <string name=\"home_dialog_uninstall_all\">ඔක්කම අයින් කරන්න</string>\n    <string name=\"kpm_control_dialog_title\">Control KPModule</string>\n    <string name=\"kpm_control_paramters\">Parameters</string>\n    <string name=\"kpm_control_outMsg\">පණිවිඩ</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">පද්ධතියේ සැකසුම සමඟ ඔටෝම අඳුරු තේමාවට මාරු වෙන්න</string>\n    <string name=\"pink_theme\">රෝස Theme</string>\n    <string name=\"about_app_version\">අනුවාදය %1$s</string>\n    <string name=\"settings_night_theme_enabled\">Dark theme එකදාමු</string>\n    <string name=\"deep_purple_theme\">Deep Purple Theme</string>\n    <string name=\"green_theme\">කොළ Theme</string>\n    <string name=\"hide_apatch_manager\">APatch මැනේජර් හංගන්න</string>\n    <string name=\"enable_web_debugging\">WebView නිදොස්කරණය දාන්න</string>\n    <string name=\"apm_webui_open\">බලමු</string>\n    <string name=\"enable_web_debugging_summary\">WebUI නිදොස් කිරීමට භාවිතා කළ හැක, කරුණාකර අවශ්‍ය විට විතරක් දාගන්න.</string>\n    <string name=\"mode_select_page_install_inactive_slot\">අක්‍රිය ස්ලොට් වලට දාන්න (OTA පස්සේ)</string>\n    <string name=\"settings_night_mode_follow_sys\">සිස්ටම් dark theme වගේ වෙන්න</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"kpm_embed\">Bygg in</string>\n    <string name=\"home\">Hem</string>\n    <string name=\"patch_warnning\">Installationen kommer med risker. Vänligen försäkra dig om att din data är säkerhetskopierad.</string>\n    <string name=\"success\">Lyckades</string>\n    <string name=\"failure\">Misslyckades</string>\n    <string name=\"reboot\">Starta om</string>\n    <string name=\"settings\">Inställningar</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"reboot_recovery\">Starta om till Recovery-läge</string>\n    <string name=\"about\">Om</string>\n    <string name=\"settings_app_language\">Språk</string>\n    <string name=\"system_default\">Systemstandard</string>\n    <string name=\"settings_check_update\">Sök efter uppdatering</string>\n    <string name=\"home_learn_apatch\">Lär dig APatch</string>\n    <string name=\"reboot_edl\">Starta om till EDL</string>\n    <string name=\"settings_clear_super_key_dialog\">Vill du verkligen fortsätta?</string>\n    <string name=\"settings_check_update_summary\">Sök automatiskt efter uppdateringar när appen öppnas</string>\n    <string name=\"settings_global_namespace_mode_summary\">Alla root-sessioner använder det globala namnutrymme</string>\n    <string name=\"safe_mode\">Säkert läge</string>\n    <string name=\"send_log\">Skicka logg</string>\n    <string name=\"save_log\">Spara logg</string>\n    <string name=\"about_source_code\">&lt;p&gt; Visa källkod vid %1$s&lt;p/&gt;Gå med i vår kanal %%2$s&lt;p/&gt;Gå med i vår grupp %3$s</string>\n    <string name=\"home_patch_set_key_desc\">Endast inloggningsuppgifter för KernelPatch</string>\n    <string name=\"home_installing\">Installerar</string>\n    <string name=\"home_patch_next_step\">Nästa steg</string>\n    <string name=\"home_working\">Jobbar 😋</string>\n    <string name=\"home_install_unknown_summary\">Klicka för att installera</string>\n    <string name=\"home_click_to_install\">Klicka för att installera</string>\n    <string name=\"home_install_unknown\">Inte installerad eller autentiserad</string>\n    <string name=\"kpatch_version\">Version: %s</string>\n    <string name=\"apatch_version\">Version: %s</string>\n    <string name=\"home_need_update\">Ny version tillgänglig</string>\n    <string name=\"apatch_version_update\">Version: %s -&gt; %s</string>\n    <string name=\"kpatch_version_update\">Version: %s -&gt; %s</string>\n    <string name=\"home_auth_key_title\">Ange SuperKey</string>\n    <string name=\"home_kpatch_info_title\">Info</string>\n    <string name=\"home_ap_cando_install\">Installera</string>\n    <string name=\"home_ap_cando_update\">Uppdatera</string>\n    <string name=\"home_ap_cando_uninstall\">Avinstallera</string>\n    <string name=\"home_ap_cando_reboot\">Starta om</string>\n    <string name=\"home_auth_key_desc\">Börja efter certifiering</string>\n    <string name=\"patch_mode_uninstall_patch\">Läge: Avinstallera KPatch</string>\n    <string name=\"patch_mode_patch_and_install\">Mode: Patch och installera</string>\n    <string name=\"patch_mode_install_to_next_slot\">Läge: Installera till nästa plats (Efter OTA)</string>\n    <string name=\"patch_item_error\">!!FEL!!</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_embed_kpm_btn\">Integrera KPM</string>\n    <string name=\"patch_item_bootimg_dev\">enhet:</string>\n    <string name=\"patch_item_kernel\">Kärna</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Version:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Tid:</string>\n    <string name=\"patch_item_kpimg_config\">Konfig:</string>\n    <string name=\"patch_item_extra_name\">Namn:</string>\n    <string name=\"patch_item_extra_version\">Version:</string>\n    <string name=\"patch_item_extra_author\">Upphovsman:</string>\n    <string name=\"patch_item_extra_kpm_license\">Licens:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Beskrivning:</string>\n    <string name=\"patch_item_extra_args\">Argument:</string>\n    <string name=\"patch_item_extra_event\">Händelse:</string>\n    <string name=\"home_kernel\">Kärna</string>\n    <string name=\"patch_item_skey\">Super-tangent</string>\n    <string name=\"patch_item_set_skey_label\">Super-tangentens längd borde vara minst 8 tecken och ska inkludera både nummer och bokstäver</string>\n    <string name=\"home_fingerprint\">Fingeravtryck</string>\n    <string name=\"home_selinux_status_disabled\">Av</string>\n    <string name=\"home_selinux_status\">Status för SELinux</string>\n    <string name=\"home_selinux_status_permissive\">Tillåtande</string>\n    <string name=\"home_selinux_status_unknown\">Okänd</string>\n    <string name=\"home_device_info\">Enhet</string>\n    <string name=\"kpm\">KP-modul</string>\n    <string name=\"kpm_load\">Ladda</string>\n    <string name=\"home_system_version\">Version på systemet</string>\n    <string name=\"home_apatch_version\">Version på APatch</string>\n    <string name=\"kpm_add_kpm\">Lägg till KPM</string>\n    <string name=\"kpm_install\">Installera</string>\n    <string name=\"kpm_load_toast_failed\">Laddningen misslyckades</string>\n    <string name=\"kpm_unload_confirm\">Avlägsna modulen \\\"%s\\\"?</string>\n    <string name=\"kpm_control\">Kontroll</string>\n    <string name=\"kpm_version\">Version</string>\n    <string name=\"kpm_license\">Licens</string>\n    <string name=\"kpm_author\">Upphovsman</string>\n    <string name=\"kpm_apm_empty\">Ingen modul har laddats</string>\n    <string name=\"kpm_desc\">Beskr.</string>\n    <string name=\"kpm_args\">Argument</string>\n    <string name=\"su_title\">Superanvändare</string>\n    <string name=\"su_pkg_excluded_label\">exkludera</string>\n    <string name=\"su_pkg_excluded_setting_title\">Exkludera modifieringar</string>\n    <string name=\"su_show_system_apps\">Visa system-appar</string>\n    <string name=\"su_hide_system_apps\">Dölj system-appar</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Att aktivera det här alternativet kommer att tillåta APatch att återställa alla modifierade filer den här applikationens moduler.</string>\n    <string name=\"su_refresh\">Uppdatera</string>\n    <string name=\"apm\">AP-modul</string>\n    <string name=\"apm_remove\">Ta bort</string>\n    <string name=\"apm_install\">Installera</string>\n    <string name=\"apm_not_installed\">AndroidPatch är inte installerad</string>\n    <string name=\"apm_empty\">Ingen modul är installerad</string>\n    <string name=\"apm_failed_to_disable\">Kunde inte slå av modulen \\\"%s\\\"</string>\n    <string name=\"apm_version\">Version</string>\n    <string name=\"apm_author\">Upphovsman</string>\n    <string name=\"apm_desc\">Beskr.</string>\n    <string name=\"apm_uninstall_success\">%s avinstallerat</string>\n    <string name=\"apm_uninstall_confirm\">Avinstallera modulen \\\"%s\\\"?</string>\n    <string name=\"apm_uninstall_failed\">Kunde inte avinstallera %s</string>\n    <string name=\"apm_changelog\">Ändringslogg</string>\n    <string name=\"apm_update\">Uppdatering</string>\n    <string name=\"apm_magisk_conflict\">Modulerna är otillgängliga på grund av en konflikt med Magisk.</string>\n    <string name=\"apm_overlay_fs_not_available\">Modulerna är otillgängliga eftersom att OverlayFS är inaktiverat av kärnan.</string>\n    <string name=\"apm_downloading\">Hämtar modulen \\\"%s\\\"…</string>\n    <string name=\"apm_start_downloading\">Påbörja hämtningen av %s</string>\n    <string name=\"apm_new_version_available\">Klicka för att installera den nya versionen, %s.</string>\n    <string name=\"apm_webui_open\">Öppna</string>\n    <string name=\"setting_reset_su_path\">Återställ genväg för su</string>\n    <string name=\"setting_reset_su_new_path\">ny fullständig genväg</string>\n    <string name=\"hide_apatch_manager_failure\">Döljningen misslyckades, vänligen rapportera buggen!</string>\n    <string name=\"hide_apatch_dialog_summary\">Det kommer att användas som en ny app-etikett som visas i startprogrammet</string>\n    <string name=\"enable_web_debugging\">Aktivera felsökning för WebView</string>\n    <string name=\"mode_select_page_patch_and_install\">Patcha och installera</string>\n    <string name=\"home_dialog_auth_fail_title\">Autentiseringen misslyckades</string>\n    <string name=\"home_more_menu_about\">Om</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Återgivning eller förslag</string>\n    <string name=\"kpm_control_ok\">Åtgärden lyckades!</string>\n    <string name=\"kpm_control_failed\">Åtgärden misslyckades!</string>\n    <string name=\"settings_night_mode_follow_sys\">Följ systemets mörka tema</string>\n    <string name=\"blue_theme\">Blått tema</string>\n    <string name=\"blue_grey_theme\">Blågrått tema</string>\n    <string name=\"light_blue_theme\">Ljusblått tema</string>\n    <string name=\"green_theme\">Grönt tema</string>\n    <string name=\"about_app_version\">Version %1$s</string>\n    <string name=\"about_telegram_group\">Grupp på Telegram</string>\n    <string name=\"about_powered_by\">Drivs av %1$s</string>\n    <string name=\"apm_action\">Åtgärd</string>\n    <string name=\"mode_select_page_title\">Installera</string>\n    <string name=\"home_new_apatch_found\">Ny version tillgänglig: %s, Klicka på mig för att uppgradera</string>\n    <string name=\"home_dialog_uninstall_title\">Avinstallera</string>\n    <string name=\"kpm_control_paramters\">Parametrar</string>\n    <string name=\"kpm_control_outMsg\">Meddelande</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Ta bort AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Avinstallera allt</string>\n    <string name=\"kpm_control_dialog_title\">Kontrollera KP-modulen</string>\n    <string name=\"kpm_control_dialog_content\">Mata in kontroll-parametrar:</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Installera till en icke aktiv plats (Efter OTA)</string>\n    <string name=\"home_dialog_auth_fail_content\">Autentiseringen av super-tangenten kunde inte genomföras, därav kommer inte APatch att fungera korrekt.\\nHär är några möjliga orsaker till varför autentiseringen misslyckades:\\n1. Du har inte patchat avbilden för boot med KernelPatch.\\n2. Den patchade avbilden för boot har inte flashats.\\n3. Fel Super-tangent.\\n4. Din enhet har inte stöd för APatch och KernelPatch.\\n\\nVänligen kontrollera och försök igen. Om det fortfarande skulle uppstå problem så kan du alltid ställa frågor på sidan för filförrådets sida för problem-rapportering.</string>\n    <string name=\"settings_custom_color_theme\">Färgtema</string>\n    <string name=\"settings_use_system_color_theme_summary\">Använd ett färgschema som genereras av systemet med den nuvarande bakgrundsbilden</string>\n    <string name=\"brown_theme\">Brunt tema</string>\n    <string name=\"sakura_theme\">Sakura-tema</string>\n    <string name=\"yellow_theme\">Gult tema</string>\n    <string name=\"light_green_theme\">Ljusgrönt tema</string>\n    <string name=\"about_telegram_channel\">Kanal på Telegram</string>\n    <string name=\"home_click_to_learn_apatch\">Lär dig om funktionerna i APatch och hur du använder</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"patch_start_patch_btn\">Starta</string>\n    <string name=\"patch_mode_bootimg_patch\">Läge: Patchning</string>\n    <string name=\"patch_select_bootimg_btn\">Välj uppstart</string>\n    <string name=\"patch_start_unpatch_btn\">Ta bort patch</string>\n    <string name=\"log_saved\">Logg sparad</string>\n    <string name=\"patch\">Patch</string>\n    <string name=\"reboot_bootloader\">Starta om till Bootloader</string>\n    <string name=\"reboot_download\">Starta om till Nedladdning</string>\n    <string name=\"super_key\">SuperNyckel</string>\n    <string name=\"clear_super_key\">Rensa SuperNyckel</string>\n    <string name=\"patch_set_superkey\">Sätt SuperNyckel</string>\n    <string name=\"home_not_installed\">Inte installerad</string>\n    <string name=\"patch_title\">Patch</string>\n    <string name=\"patch_config_title\">Patchar</string>\n    <string name=\"patch_item_new_extra_kpm\">Bädda in ny</string>\n    <string name=\"patch_item_existed_extra_kpm\">Existerade</string>\n    <string name=\"su_selinux_via_hook\">bypass genom hook</string>\n    <string name=\"pink_theme\">Rosa tema</string>\n    <string name=\"purple_theme\">Lila tema</string>\n    <string name=\"settings_donot_store_superkey\">Spara inte supernycklen i local</string>\n    <string name=\"settings_use_system_color_theme\">System färgtema</string>\n    <string name=\"settings_night_theme_enabled\">Aktivera mörkt tema</string>\n    <string name=\"teal_theme\">Blågrönt tema</string>\n    <string name=\"red_theme\">Rött tema</string>\n    <string name=\"cyan_theme\">Cyan tema</string>\n    <string name=\"deep_orange_theme\">Djuporanget tema</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-ta/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"patch_item_extra_kpm_license\">உரிமம்:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">விளக்கம்:</string>\n    <string name=\"patch_item_extra_args\">ஆர்க்ச்:</string>\n    <string name=\"patch_item_extra_event\">நிகழ்வு:</string>\n    <string name=\"kpm_unload_confirm\">\\\"%s\\\" தொகுதியை இறக்கவா?</string>\n    <string name=\"kpm_author\">நூலாசிரியர்</string>\n    <string name=\"apm\">Apmodule</string>\n    <string name=\"home_dialog_auth_fail_title\">ஏற்பு தோல்வியடைந்தது</string>\n    <string name=\"crash_handle_copied\">இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்ட செயலிழப்பு பதிவு.</string>\n    <string name=\"home\">வீடு</string>\n    <string name=\"failure\">தோல்வி</string>\n    <string name=\"success\">செய்</string>\n    <string name=\"patch_warnning\">நிறுவல் அபாயங்களுடன் வருகிறது. உங்கள் தரவு காப்புப் பிரதி எடுக்கப்படுவதை உறுதிசெய்க.</string>\n    <string name=\"patch\">இணைப்பு</string>\n    <string name=\"settings_app_language\">மொழி</string>\n    <string name=\"system_default\">கணினி இயல்புநிலை</string>\n    <string name=\"kernel_patch\">கர்னல்பாட்ச்</string>\n    <string name=\"reboot\">மறுதொடக்கம் செய்யுங்கள்</string>\n    <string name=\"settings\">அமைப்புகள்</string>\n    <string name=\"reboot_recovery\">மீட்புக்கு மறுதொடக்கம் செய்யுங்கள்</string>\n    <string name=\"reboot_bootloader\">துவக்க ஏற்றிக்கு மறுதொடக்கம் செய்யுங்கள்</string>\n    <string name=\"reboot_download\">பதிவிறக்கம் செய்ய மறுதொடக்கம் செய்யுங்கள்</string>\n    <string name=\"reboot_edl\">EDL க்கு மறுதொடக்கம் செய்யுங்கள்</string>\n    <string name=\"about\">பற்றி</string>\n    <string name=\"settings_global_namespace_mode\">உலகளாவிய பெயர்வெளி பயன்முறை</string>\n    <string name=\"settings_global_namespace_mode_summary\">அனைத்து ரூட் அமர்வுகளும் உலகளாவிய மவுண்ட் பெயர்வெளியைப் பயன்படுத்துகின்றன</string>\n    <string name=\"settings_check_update\">புதுப்பிப்பைச் சரிபார்க்கவும்</string>\n    <string name=\"settings_check_update_summary\">பயன்பாட்டைத் திறக்கும்போது புதுப்பிப்புகளை தானாகவே சரிபார்க்கவும்</string>\n    <string name=\"home_learn_apatch\">அப்பாச்சி கற்றுக்கொள்ளுங்கள்</string>\n    <string name=\"home_click_to_learn_apatch\">அப்பாட்சின் நற்பொருத்தங்கள் மற்றும் எவ்வாறு பயன்படுத்துவது என்பது பற்றி அறிக</string>\n    <string name=\"send_log\">பதிவுகள் அனுப்பவும்</string>\n    <string name=\"save_log\">பதிவுகளை சேமிக்கவும்</string>\n    <string name=\"settings_clear_super_key_dialog\">நீங்கள் உண்மையில் தொடர விரும்புகிறீர்களா?</string>\n    <string name=\"log_saved\">பதிவுகள் சேமிக்கப்பட்டன</string>\n    <string name=\"safe_mode\">பாதுகாப்பான பயன்முறை</string>\n    <string name=\"super_key\">சூப்பர்கி</string>\n    <string name=\"clear_super_key\">தெளிவான சூப்பர்கி</string>\n    <string name=\"patch_set_superkey\">சூப்பர்கி அமைக்கவும்</string>\n    <string name=\"home_not_installed\">நிறுவப்படவில்லை</string>\n    <string name=\"home_patch_set_key_desc\">கர்னல் பேட்சிற்கான சான்றுகள் மட்டுமே</string>\n    <string name=\"home_patch_next_step\">அடுத்த அடி</string>\n    <string name=\"home_install_unknown\">நிறுவப்படவில்லை அல்லது அங்கீகரிக்கப்படவில்லை</string>\n    <string name=\"home_install_unknown_summary\">நிறுவ சொடுக்கு செய்க</string>\n    <string name=\"home_click_to_install\">நிறுவ சொடுக்கு செய்க</string>\n    <string name=\"home_need_update\">புதிய பதிப்பு கிடைக்கிறது</string>\n    <string name=\"home_working\">வேலை</string>\n    <string name=\"home_installing\">நிறுவுகிறது</string>\n    <string name=\"kpatch_version\">பதிப்பு: %s</string>\n    <string name=\"apatch_version\">பதிப்பு: %s</string>\n    <string name=\"apatch_version_update\">பதிப்பு: %s -&gt; %s</string>\n    <string name=\"kpatch_version_update\">பதிப்பு: %s -&gt; %s</string>\n    <string name=\"home_auth_key_title\">சூப்பர்கி உள்ளிடவும்</string>\n    <string name=\"kpatch_shadow_path_title\">கேஒட்டு</string>\n    <string name=\"home_auth_key_desc\">சான்றிதழுக்குப் பிறகு தொடங்கவும்</string>\n    <string name=\"home_kpatch_info_title\">தகவல்</string>\n    <string name=\"home_ap_cando_install\">நிறுவவும்</string>\n    <string name=\"home_ap_cando_update\">புதுப்பிப்பு</string>\n    <string name=\"home_ap_cando_uninstall\">நிறுவல் நீக்க</string>\n    <string name=\"home_ap_cando_reboot\">மறுதொடக்கம் செய்யுங்கள்</string>\n    <string name=\"patch_title\">இணைப்பு</string>\n    <string name=\"patch_config_title\">திட்டுகள்</string>\n    <string name=\"patch_mode_bootimg_patch\">பயன்முறை: இணைப்பு</string>\n    <string name=\"patch_mode_patch_and_install\">பயன்முறை: இணைப்பு மற்றும் நிறுவவும்</string>\n    <string name=\"patch_mode_install_to_next_slot\">பயன்முறை: செயலற்ற ச்லாட்டுக்கு நிறுவவும் (OTA க்குப் பிறகு)</string>\n    <string name=\"patch_mode_uninstall_patch\">பயன்முறை: kpatch ஐ நிறுவல் நீக்குதல்</string>\n    <string name=\"patch_select_bootimg_btn\">துவக்கத்தைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"patch_embed_kpm_btn\">கே.பி.எம்</string>\n    <string name=\"patch_start_patch_btn\">தொடங்கு</string>\n    <string name=\"patch_start_unpatch_btn\">Unpatch</string>\n    <string name=\"patch_item_error\">!! பிழை !!</string>\n    <string name=\"patch_item_bootimg\">துவக்க</string>\n    <string name=\"patch_item_bootimg_slot\">ச்லாட்:</string>\n    <string name=\"patch_item_bootimg_dev\">சாதனம்:</string>\n    <string name=\"patch_item_kernel\">கர்னல்</string>\n    <string name=\"patch_item_kpimg_version\">பதிப்பு:</string>\n    <string name=\"patch_item_kpimg_comile_time\">நேரம்:</string>\n    <string name=\"patch_item_kpimg_config\">கட்டமைப்பு:</string>\n    <string name=\"patch_item_new_extra_kpm\">புதியது</string>\n    <string name=\"patch_item_existed_extra_kpm\">இருந்தது</string>\n    <string name=\"patch_item_extra_name\">பெயர்:</string>\n    <string name=\"patch_item_extra_version\">பதிப்பு:</string>\n    <string name=\"patch_item_extra_author\">ஆசிரியர்:</string>\n    <string name=\"patch_item_skey\">சூப்பர்கி</string>\n    <string name=\"patch_item_set_skey_label\">சூப்பர்கி 8-63 எழுத்துக்கள் நீளமாக இருக்க வேண்டும் மற்றும் எண்கள் மற்றும் கடிதங்களை உள்ளடக்கியிருக்க வேண்டும், ஆனால் சிறப்பு எழுத்துக்கள் இல்லை.</string>\n    <string name=\"home_kernel\">கர்னல்</string>\n    <string name=\"home_manager_version\">மேலாளர் பதிப்பு</string>\n    <string name=\"home_fingerprint\">கைரேகை</string>\n    <string name=\"home_selinux_status\">செலினக்ச் நிலை</string>\n    <string name=\"home_selinux_status_disabled\">முடக்கப்பட்டது</string>\n    <string name=\"home_selinux_status_enforcing\">செயல்படுத்துதல்</string>\n    <string name=\"home_selinux_status_permissive\">இசைவு</string>\n    <string name=\"home_selinux_status_unknown\">தெரியவில்லை</string>\n    <string name=\"home_device_info\">சாதனம்</string>\n    <string name=\"home_system_version\">கணினி பதிப்பு</string>\n    <string name=\"home_kpatch_version\">கர்னல்பாட்ச் பதிப்பு</string>\n    <string name=\"home_su_path\">இயங்கக்கூடிய சு</string>\n    <string name=\"home_apatch_version\">அபட்க் பதிப்பு</string>\n    <string name=\"kpm\">Kpmodule</string>\n    <string name=\"kpm_kp_not_installed\">கர்னல்பாட்ச் நிறுவப்படவில்லை</string>\n    <string name=\"kpm_add_kpm\">கே.பி.எம் சேர்க்கவும்</string>\n    <string name=\"kpm_load\">சுமை</string>\n    <string name=\"kpm_install\">நிறுவவும்</string>\n    <string name=\"kpm_embed\">உட்பொதிக்கப்பட்டது</string>\n    <string name=\"kpm_load_toast_succ\">சுமை செய்</string>\n    <string name=\"kpm_load_toast_failed\">சுமை தோல்வியடைந்தது</string>\n    <string name=\"kpm_unload\">இறக்கவும்</string>\n    <string name=\"kpm_control\">கட்டுப்பாடு</string>\n    <string name=\"kpm_apm_empty\">எந்த தொகுதி ஏற்றப்படவில்லை</string>\n    <string name=\"kpm_version\">பதிப்பு</string>\n    <string name=\"kpm_license\">உரிமம்</string>\n    <string name=\"kpm_desc\">டெச்க்</string>\n    <string name=\"kpm_args\">ஆர்க்ச்</string>\n    <string name=\"su_title\">சூப்பர் யூசர்</string>\n    <string name=\"su_selinux_via_hook\">கொக்கி வழியாக பைபாச்</string>\n    <string name=\"su_pkg_excluded_label\">விலக்கு</string>\n    <string name=\"su_pkg_excluded_setting_title\">மாற்றங்களை விலக்கு</string>\n    <string name=\"su_pkg_excluded_setting_summary\">இந்த விருப்பத்தின் தொகுதிகள் மூலம் மாற்றியமைக்கப்பட்ட எந்த கோப்புகளையும் மீட்டெடுக்க இந்த விருப்பத்தை இயக்குவது அபேக் அனுமதிக்கும்.</string>\n    <string name=\"su_show_system_apps\">கணினி பயன்பாடுகளைக் காட்டு</string>\n    <string name=\"su_hide_system_apps\">கணினி பயன்பாடுகளை மறைக்கவும்</string>\n    <string name=\"su_refresh\">புதுப்பி</string>\n    <string name=\"apm_not_installed\">AndroidPatch நிறுவப்படவில்லை</string>\n    <string name=\"apm_failed_to_enable\">\\\"%s\\\" தொகுதியை இயக்க முடியவில்லை</string>\n    <string name=\"apm_failed_to_disable\">\\\"%s\\\" தொகுதியை அணைக்க முடியவில்லை</string>\n    <string name=\"apm_empty\">எந்த தொகுதி நிறுவப்படவில்லை</string>\n    <string name=\"apm_remove\">அகற்று</string>\n    <string name=\"apm_install\">நிறுவவும்</string>\n    <string name=\"apm_uninstall_confirm\">\\\"%s\\\" தொகுதியை நிறுவல் நீக்கவா?</string>\n    <string name=\"apm_uninstall_success\">%s நிறுவல் நீக்கப்பட்டது</string>\n    <string name=\"apm_uninstall_failed\">%s நிறுவல் நீக்க முடியவில்லை</string>\n    <string name=\"apm_version\">பதிப்பு</string>\n    <string name=\"apm_author\">நூலாசிரியர்</string>\n    <string name=\"apm_desc\">டெச்க்</string>\n    <string name=\"apm_overlay_fs_not_available\">கர்னலால் மேலடுக்குகள் முடக்கப்பட்டிருப்பதால் தொகுதிகள் கிடைக்கவில்லை!</string>\n    <string name=\"apm_magisk_conflict\">மேகிசுடனான மோதல் காரணமாக தொகுதிகள் கிடைக்கவில்லை!</string>\n    <string name=\"apm_reboot_to_apply\">நடைமுறைக்கு வர மறுதொடக்கம் செய்யுங்கள்</string>\n    <string name=\"apm_changelog\">மாற்றபதிவு</string>\n    <string name=\"apm_downloading\">\\\"%s\\\" தொகுதி பதிவிறக்குகிறது…</string>\n    <string name=\"apm_start_downloading\">%s பதிவிறக்கத் தொடங்குங்கள்</string>\n    <string name=\"apm_new_version_available\">புதிய பதிப்பு %s கிடைக்கின்றன, மேம்படுத்த சொடுக்கு செய்க.</string>\n    <string name=\"hide_apatch_manager\">அபாட்ச் மேலாளரை மறைக்கவும்</string>\n    <string name=\"hide_apatch_manager_summary\">சீரற்ற அடையாளம் மற்றும் தனிப்பயன் சிட்டை மூலம் புதிய மேலாளர் பயன்பாட்டை நிறுவவும்</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">புதிய மேலாளர் பெயர்</string>\n    <string name=\"hide_apatch_dialog_summary\">இது துவக்கத்தில் காட்டப்பட்டுள்ள புதிய பயன்பாட்டு லேபிளாக பயன்படுத்தப்படும்</string>\n    <string name=\"apm_update\">புதுப்பிப்பு</string>\n    <string name=\"hide_apatch_manager_failure\">மறைக்கத் தவறிவிட்டது. பிழையைப் புகாரளிக்கவும்!</string>\n    <string name=\"setting_reset_su_path\">சு பாதையை மீட்டமைக்கவும்</string>\n    <string name=\"setting_reset_su_new_path\">புதிய முழு பாதை</string>\n    <string name=\"apm_webui_open\">திற</string>\n    <string name=\"apm_action\">செயல்</string>\n    <string name=\"enable_web_debugging\">வெப்வியூ பிழைத்திருத்தத்தை இயக்கவும்</string>\n    <string name=\"enable_web_debugging_summary\">WebUI ஐ பிழைத்திருத்த பயன்படுத்தலாம். தேவைப்படும்போது மட்டுமே இயக்கவும்.</string>\n    <string name=\"settings_donot_store_superkey\">சூப்பர்கீவை உள்ளக சேமிக்க வேண்டாம்</string>\n    <string name=\"settings_donot_store_superkey_summary\">மேலாளர் தொடங்கும் ஒவ்வொரு முறையும் சூப்பர்கியை அங்கீகரிக்கவும்</string>\n    <string name=\"home_new_apatch_found\">புதிய பதிப்பு %s கிடைக்கின்றன, மேம்படுத்த சொடுக்கு செய்க.</string>\n    <string name=\"mode_select_page_title\">நிறுவவும்</string>\n    <string name=\"mode_select_page_patch_and_install\">இணைப்பு மற்றும் நிறுவவும்</string>\n    <string name=\"mode_select_page_select_file\">இணைப்புக்கு துவக்க படத்தைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"mode_select_page_install_inactive_slot\">செயலற்ற ச்லாட்டுக்கு நிறுவவும் (OTA க்குப் பிறகு)</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">மறுதொடக்கத்திற்குப் பிறகு தற்போதைய செயலற்ற ச்லாட்டுக்கு துவக்க உங்கள் சாதனம் ** கட்டாயப்படுத்தப்படும் **! \\nOTA முடிந்ததும் மட்டுமே இந்த விருப்பத்தைப் பயன்படுத்தவும். \\nதொடரவா?</string>\n    <string name=\"home_dialog_auth_fail_content\">சூப்பர்கியை அங்கீகரிக்க முடியவில்லை, எனவே அப்பாட்ச் சரியாக வேலை செய்ய முடியாது. \\nஅங்கீகார தோல்விக்கான சில காரணங்கள் இங்கே: \\n1. நீங்கள் boot.img ஐ கர்னல்பாட்ச் மூலம் இணைக்கவில்லை. \\n2. இணைக்கப்பட்ட துவக்க. ஐ.எம்.சி ஒளிரவில்லை. \\n3. சூப்பர்ச்கி தவறானது அல்லது சிறப்பு எழுத்துக்கள் உள்ளன. \\n4. உங்கள் சாதனம் அபாட்ச் மற்றும் கர்னல்பாட்சை ஆதரிக்காது. \\n\\nதயவுசெய்து சரிபார்த்து மீண்டும் முயற்சிக்கவும். இன்னும் சிக்கல்கள் இருந்தால், அதிகாரப்பூர்வ களஞ்சியத்தின் சிக்கல்கள் பக்கத்தில் நீங்கள் எப்போதும் கேள்விகளைக் கேட்கலாம்.</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">கருத்து அல்லது பரிந்துரை</string>\n    <string name=\"home_more_menu_about\">பற்றி</string>\n    <string name=\"home_dialog_uninstall_title\">நிறுவல் நீக்க</string>\n    <string name=\"home_dialog_uninstall_ap_only\">AndroidPatch ஐ அகற்றவும்</string>\n    <string name=\"home_dialog_uninstall_all\">அனைத்தையும் நிறுவல் நீக்கவும்</string>\n    <string name=\"kpm_control_dialog_title\">Kpmodule ஐக் கட்டுப்படுத்துங்கள்</string>\n    <string name=\"kpm_control_dialog_content\">உள்ளீட்டு கட்டுப்பாட்டு அளவுருக்கள்:</string>\n    <string name=\"kpm_control_paramters\">அளவுருக்கள்</string>\n    <string name=\"kpm_control_outMsg\">செய்தி</string>\n    <string name=\"kpm_control_ok\">செயல்பாடு செய் பெற்றது!</string>\n    <string name=\"kpm_control_failed\">செயல்பாடு தோல்வியடைந்தது!</string>\n    <string name=\"settings_night_mode_follow_sys\">கணினியின் இருண்ட கருப்பொருளைப் பின்பற்றுங்கள்</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">கணினி அமைப்புகளின் அடிப்படையில் தானாக இருண்ட கருப்பொருளுக்கு மாறவும்</string>\n    <string name=\"settings_night_theme_enabled\">இருண்ட கருப்பொருளை இயக்கவும்</string>\n    <string name=\"settings_use_system_color_theme\">கணினி வண்ண கருப்பொருள்</string>\n    <string name=\"settings_use_system_color_theme_summary\">தற்போதைய வால்பேப்பரின் அடிப்படையில் கணினியால் உருவாக்கப்பட்ட வண்ண கருப்பொருளைப் பயன்படுத்தவும்</string>\n    <string name=\"settings_custom_color_theme\">வண்ண கருப்பொருள்</string>\n    <string name=\"amber_theme\">அம்பர்</string>\n    <string name=\"blue_grey_theme\">நீல சாம்பல்</string>\n    <string name=\"blue_theme\">நீலம்</string>\n    <string name=\"brown_theme\">பழுப்பு</string>\n    <string name=\"deep_orange_theme\">ஆழமான ஆரஞ்சு</string>\n    <string name=\"cyan_theme\">சியான்</string>\n    <string name=\"deep_purple_theme\">ஆழமான ஊதா</string>\n    <string name=\"green_theme\">பச்சை</string>\n    <string name=\"indigo_theme\">இண்டிகோ</string>\n    <string name=\"light_blue_theme\">வெளிர் நீலம்</string>\n    <string name=\"light_green_theme\">வெளிர் பச்சை</string>\n    <string name=\"lime_theme\">சுண்ணாம்பு</string>\n    <string name=\"orange_theme\">ஆரஞ்சு</string>\n    <string name=\"pink_theme\">இளஞ்சிவப்பு</string>\n    <string name=\"purple_theme\">ஊதா</string>\n    <string name=\"red_theme\">சிவப்பு</string>\n    <string name=\"sakura_theme\">சகுரா</string>\n    <string name=\"teal_theme\">டீல்</string>\n    <string name=\"yellow_theme\">மஞ்சள்</string>\n    <string name=\"about_app_version\">பதிப்பு %1$s</string>\n    <string name=\"about_app_desc\">அகற்றப்பட்ட கர்னல் படத்துடன் மட்டுமே கர்னல் ரூட் தீர்வு, பெருகிவரும் கணினி தொகுதி மற்றும் கர்னல் செயல்பாட்டை ஊக்கிங் செய்யும் திறனை வழங்குகிறது.</string>\n    <string name=\"about_telegram_channel\">தந்தி சேனல்</string>\n    <string name=\"about_telegram_group\">தந்தி குழு</string>\n    <string name=\"about_powered_by\">%1$s ஆல் இயக்கப்படுகிறது</string>\n    <string name=\"crash_handle_title\">பயன்பாடு செயலிழந்தது…</string>\n    <string name=\"crash_handle_copy\">செயலிழப்பு பதிவை நகலெடுக்கவும்</string>\n    <string name=\"android_patch\">ஆண்ட்ராய்டுஒட்டு</string>\n    <string name=\"about_source_code\"><![CDATA[<p>மூலக் குறியீட்டை %1$s<p/>எங்கள் %2$s சேனலில் சேர்<p/>எங்கள் %3$s குழுவில் சேர்]]></string>\n    <string name=\"patch_item_kpimg\">கேபிபட</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-th/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"patch_warnning\">APatch</string>\n    <string name=\"home_learn_apatch\">เรียนรู้เกี่ยวกับ APatch</string>\n    <string name=\"reboot\">รีบูต</string>\n    <string name=\"settings\">ตั้งค่า</string>\n    <string name=\"send_log\">Send logs</string>\n    <string name=\"home_auth_key_desc\">เริ่มทำงานหลังจากได้รับการรับรอง</string>\n    <string name=\"home_click_to_learn_apatch\">เรียนรู้เกี่ยวกับคุณสมบัติ APatch และวิธีการใช้</string>\n    <string name=\"home_installing\">กำลังติดตั้ง</string>\n    <string name=\"home_ap_cando_uninstall\">ถอนการติดตั้ง</string>\n    <string name=\"home_ap_cando_install\">ติดตั้ง</string>\n    <string name=\"home_click_to_install\">คลิกเพื่อติดตั้ง</string>\n    <string name=\"home_need_update\">มีอัปเดตพร้อมใช้งาน</string>\n    <string name=\"home_selinux_status\">สถานะ SELinux</string>\n    <string name=\"patch_set_superkey\">ตั้ง SuperKey</string>\n    <string name=\"home_ap_cando_update\">อัพเดท</string>\n    <string name=\"home_selinux_status_disabled\">ปิด</string>\n    <string name=\"home_working\">กำลังทำงาน</string>\n    <string name=\"home_patch_next_step\">ขั้นตอนต่อไป</string>\n    <string name=\"home_not_installed\">ไม่ได้ติดตั้ง</string>\n    <string name=\"home_manager_version\">เวอร์ชัน</string>\n    <string name=\"kpm_load\">โหลด</string>\n    <string name=\"kpm_load_toast_succ\">โหลดสำเร็จ</string>\n    <string name=\"kpm_unload_confirm\">คุณแน่ใจหรือไม่ว่าต้องการยกเลิกการโหลดโมดูล %s?</string>\n    <string name=\"kpm_desc\">คำอธิบาย</string>\n    <string name=\"kpm_version\">เวอร์ชัน</string>\n    <string name=\"kpm_author\">ผู้เขียน</string>\n    <string name=\"kpm_load_toast_failed\">โหลดไม่สำเร็จ</string>\n    <string name=\"kpm_unload\">ยกเลิกการโหลด</string>\n    <string name=\"kpm_license\">ใบอนุญาต</string>\n    <string name=\"kpm_apm_empty\">ไม่มีการโหลดโมดูล</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"apm_reboot_to_apply\">รีบูตเพื่อให้มีผล</string>\n    <string name=\"apm_uninstall_success\">กำลังดาวน์โหลดโมดูล: %s…</string>\n    <string name=\"apm_install\">APModule</string>\n    <string name=\"apm_remove\">ถอนการติดตั้ง</string>\n    <string name=\"apm_uninstall_confirm\">กำลังดาวน์โหลดโมดูล: %s…</string>\n    <string name=\"apm_version\">APModule</string>\n    <string name=\"su_pkg_excluded_setting_summary\">การเปิดใช้งานตัวเลือกนี้จะช่วยให้ APatch กู้คืนไฟล์ที่ถูกปรับเปลี่ยนโดยโมดูลสำหรับแอปพลิเคชันนี้</string>\n    <string name=\"apm_start_downloading\">เริ่มดาวน์โหลด: %s</string>\n    <string name=\"apm_overlay_fs_not_available\">0.0019ไม่มี OverlayFS โมดูลไม่สามารถทำงานได้.</string>\n    <string name=\"su_show_system_apps\">แสดงแอประบบ</string>\n    <string name=\"apm_failed_to_disable\">ไม่สามารถปิดการใช้งานโมดูล: %s</string>\n    <string name=\"apm_uninstall_failed\">กำลังดาวน์โหลดโมดูล: %s…</string>\n    <string name=\"apm_failed_to_enable\">ไม่สามารถเปิดใช้งานโมดูล: %s</string>\n    <string name=\"su_hide_system_apps\">ซ่อนแอประบบ</string>\n    <string name=\"apm_magisk_conflict\">โมดูลถูกปิดใช้งานเนื่องจากขัดแย้งกับ Magisk\\'s.</string>\n    <string name=\"apm_new_version_available\">รุ่นใหม่: %s พร้อมใช้งาน</string>\n    <string name=\"apm_empty\">ไม่มีการติดตั้งโมดูล</string>\n    <string name=\"apm_author\">ผู้เขียน</string>\n    <string name=\"home\">สำเร็จ</string>\n    <string name=\"about\">เกี่ยวกับ</string>\n    <string name=\"safe_mode\">โหมดปลอดภัย</string>\n    <string name=\"reboot_recovery\">รีบูตเข้าสู่โหมดการกู้คืน</string>\n    <string name=\"su_refresh\">รีเฟรช</string>\n    <string name=\"apatch_version\">เวอร์ชัน: %s</string>\n    <string name=\"apatch_version_update\">เวอร์ชัน: %s -&gt; %s</string>\n    <string name=\"kpm_kp_not_installed\">ไม่ได้ติดตั้ง KernelPatch</string>\n    <string name=\"kpatch_version\">เวอร์ชัน: %s</string>\n    <string name=\"apm_not_installed\">ไม่ได้ติดตั้ง Android Patch</string>\n    <string name=\"apm_desc\">อธิบาย</string>\n    <string name=\"apm_changelog\">บันทึกการเปลี่ยนแปลง</string>\n    <string name=\"apm_update\">อัปเดต</string>\n    <string name=\"apm_downloading\">กำลังดาวน์โหลดโมดูล: %s…</string>\n    <string name=\"home_install_unknown\">ไม่ทราบ</string>\n    <string name=\"home_fingerprint\">ลายนิ้วมือ</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"kernel_patch\">APatch</string>\n    <string name=\"android_patch\">&lt;![CDATA[&lt;p&gt;View source code at %1$s&lt;br/&gt;Join our %2$s channel</string>\n    <string name=\"reboot_bootloader\">รีบูตเข้าสู่บูตโหลดเดอร์</string>\n    <string name=\"reboot_download\">รีบูตเข้าสู่โหมดดาวน์โหลด</string>\n    <string name=\"reboot_edl\">รีบูตเข้าสู่โหมด EDL</string>\n    <string name=\"about_source_code\">&lt;![CDATA[&lt;p&gt;View source code at %1$s&lt;br/&gt;Join our %2$s channel</string>\n    <string name=\"home_patch_set_key_desc\">ข้อมูลรับรองสำหรับ KernelPatch เท่านั้น</string>\n    <string name=\"home_apatch_version\">เวอร์ชั่น APatch</string>\n    <string name=\"patch_title\">แพทซ์</string>\n    <string name=\"home_kernel\">Kernel</string>\n    <string name=\"kpm_args\">Args</string>\n    <string name=\"su_title\">Superuser</string>\n    <string name=\"clear_super_key\">ล้าง คีย์</string>\n    <string name=\"home_su_path\">su: %s</string>\n    <string name=\"home_auth_key_title\">ใส่ SuperKey</string>\n    <string name=\"home_selinux_status_enforcing\">Enforcing</string>\n    <string name=\"home_selinux_status_permissive\">Permissive</string>\n    <string name=\"home_selinux_status_unknown\">ไม่ทราบ</string>\n    <string name=\"su_pkg_excluded_setting_title\">ยกเว้นการปรับเปลี่ยน</string>\n    <string name=\"su_selinux_via_hook\">bypass via hook</string>\n    <string name=\"su_pkg_excluded_label\">exclude</string>\n    <string name=\"settings_app_language\">ภาษา</string>\n    <string name=\"patch\">APatch</string>\n    <string name=\"system_default\">ค่าเริ่มต้นของระบบ</string>\n    <string name=\"settings_global_namespace_mode\">โหมดเนมสเปซทั่วโลก</string>\n    <string name=\"settings_global_namespace_mode_summary\">ทุกเซสชันรูทใช้เนมสเปซการเมานต์แบบทั่วโลก</string>\n    <string name=\"success\">APatch</string>\n    <string name=\"failure\">APatch</string>\n    <string name=\"home_kpatch_info_title\">รายละเอียด</string>\n    <string name=\"home_ap_cando_reboot\">รีบูต</string>\n    <string name=\"patch_config_title\">แพทช์</string>\n    <string name=\"patch_mode_bootimg_patch\">โหมด : แพทช์</string>\n    <string name=\"patch_mode_patch_and_install\">โหมด : แพทช์ และติดตั้ง</string>\n    <string name=\"patch_mode_uninstall_patch\">โหมด : ถอนการติดตั้ง Kpatch</string>\n    <string name=\"patch_select_bootimg_btn\">เลือกการบูต</string>\n    <string name=\"patch_embed_kpm_btn\">ฝัง KPM</string>\n    <string name=\"patch_start_patch_btn\">เริ่ม</string>\n    <string name=\"patch_start_unpatch_btn\">เลิกแพทช์</string>\n    <string name=\"patch_item_error\">!!ข้อผิดพลาด!!</string>\n    <string name=\"patch_item_bootimg\">บูตอิมเมจ</string>\n    <string name=\"patch_item_bootimg_dev\">อุปกรณ์ :</string>\n    <string name=\"patch_item_kernel\">เคอเนล</string>\n    <string name=\"patch_mode_install_to_next_slot\">โหมด: ติดตั้งในช่องถัดไป (หลังจาก OTA)</string>\n    <string name=\"settings_clear_super_key_dialog\">คุณต้องการดำเนินการต่อหรือไม่?</string>\n    <string name=\"settings_check_update_summary\">ตรวจสอบการอัปเดตโดยอัตโนมัติเมื่อเปิดแอป</string>\n    <string name=\"settings_check_update\">ตรวจสอบการอัพเดท</string>\n    <string name=\"home_install_unknown_summary\">คลิกเพื่อติดตั้ง</string>\n    <string name=\"kpatch_version_update\">เวอร์ชั่น: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">แพทซ์ เคอเนล</string>\n    <string name=\"patch_item_bootimg_slot\">ช่อง:</string>\n    <string name=\"patch_item_kpimg_version\">เวอร์ชั่น:</string>\n    <string name=\"patch_item_kpimg_config\">กำหนดค่า:</string>\n    <string name=\"patch_item_kpimg_comile_time\">เวลา:</string>\n    <string name=\"save_log\">บันทึกเหตุการณ์</string>\n    <string name=\"patch_item_set_skey_label\">ความยาวของคีย์ควรอย่างน้อย 8 ตัวอักษรและรวมถึงตัวเลขและตัวอักษร</string>\n    <string name=\"patch_item_extra_name\">ชื่อ:</string>\n    <string name=\"patch_item_extra_version\">เวอร์ชั่น:</string>\n    <string name=\"patch_item_extra_kpm_license\">ใบอนุญาต:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">คำอธิบาย:</string>\n    <string name=\"kpm_add_kpm\">เพิ่ม KPM</string>\n    <string name=\"home_device_info\">อุปกรณ์</string>\n    <string name=\"kpm_install\">ติดตั้ง</string>\n    <string name=\"about_app_version\">เวอร์ชั่น %1$s</string>\n    <string name=\"log_saved\">บันทึกข้อมูลแล้ว</string>\n    <string name=\"hide_apatch_manager_failure\">ไม่สามารถซ่อนได้ กรุณารายงานจุดบกพร่อง!</string>\n    <string name=\"setting_reset_su_path\">การรีเซ็ตจำนวนการเข้าสู่ระบบที่ล้มเหลว</string>\n    <string name=\"setting_reset_su_new_path\">เริ่มต้นใหม่</string>\n    <string name=\"mode_select_page_select_file\">คลิกเครื่่องหมายถูกต้องเพื่อยืนยัน</string>\n    <string name=\"settings_night_mode_follow_sys\">ใช้งานธีมมืดของระบบ</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">สลับไปใช้ธีมมืดโดยอัตโนมัติด้วยการตั้งค่าของระบบ</string>\n    <string name=\"settings_night_theme_enabled\">เปิดใช้งานธีมมืด</string>\n    <string name=\"settings_use_system_color_theme\">ธีมสีของระบบ</string>\n    <string name=\"cyan_theme\">ธีมสีฟ้า</string>\n    <string name=\"light_blue_theme\">ธีมสีฟ้าอ่อน</string>\n    <string name=\"about_telegram_channel\">ช่องทางเทเลอกรม</string>\n    <string name=\"about_telegram_group\">กลุ่มเทเลแกรม</string>\n    <string name=\"crash_handle_title\">แอปขัดข้อง..</string>\n    <string name=\"crash_handle_copied\">คัดลอกไฟล์ความผิดพลาดไปยังคลิปบอร์ดแล้ว</string>\n    <string name=\"crash_handle_copy\">คัดลอกไฟล์ความผิดพลาด</string>\n    <string name=\"patch_item_extra_author\">ผู้เขียน:</string>\n    <string name=\"patch_item_skey\">สุดยอดกุญแจ</string>\n    <string name=\"kpm_embed\">ฝัง</string>\n    <string name=\"enable_web_debugging_summary\">สามารถใช้เพื่อดีบัก WebUI ได้ โปรดเปิดใช้งานเฉพาะเมื่อจำเป็นเท่านั้น</string>\n    <string name=\"patch_item_extra_event\">เหตุการณ์:</string>\n    <string name=\"home_system_version\">เวอร์ชันระบบ</string>\n    <string name=\"hide_apatch_manager\">ซ่อนตัวจัดการ APatch</string>\n    <string name=\"hide_apatch_manager_summary\">ติดตั้งแอปผู้จัดการใหม่ด้วยรหัสแพ็กเกจสุ่มและป้ายชื่อแอปที่กำหนดเอง</string>\n    <string name=\"settings_donot_store_superkey_summary\">ตรวจสอบสิทธิ์ซุปเปอร์คีย์ทุกครั้งที่ผู้จัดการเริ่มต้น</string>\n    <string name=\"settings_donot_store_superkey\">ห้ามเก็บซุปเปอร์คีย์ไว้ในเครื่อง</string>\n    <string name=\"mode_select_page_title\">ติดตั้ง</string>\n    <string name=\"mode_select_page_patch_and_install\">ยืนยันและติดตั้ง</string>\n    <string name=\"home_new_apatch_found\">มีเวอร์ชันใหม่แล้ว: ,คลิกเพื่ออัปเกรด</string>\n    <string name=\"about_powered_by\">ปฎิบัติการโดย %1$s</string>\n    <string name=\"patch_item_kpimg\">เคพิงค์</string>\n    <string name=\"patch_item_existed_extra_kpm\">มีอยู่</string>\n    <string name=\"patch_item_new_extra_kpm\">ฝังใหม่</string>\n    <string name=\"home_kpatch_version\">เวอร์ชันเคอร์เนลแพตช์</string>\n    <string name=\"home_dialog_uninstall_title\">ถอนการติดตั้ง</string>\n    <string name=\"home_dialog_uninstall_ap_only\">ลบข้อมูลแอนดรอยด์</string>\n    <string name=\"kpm_control_dialog_title\">การควบคุม KPModule</string>\n    <string name=\"kpm_control_outMsg\">ข้อความ</string>\n    <string name=\"kpm_control_ok\">การดำเนินการสำเร็จ!</string>\n    <string name=\"kpm_control_paramters\">ฟังก์ชัน</string>\n    <string name=\"blue_grey_theme\">ธีมสีน้ำเงินเทา</string>\n    <string name=\"brown_theme\">ธีมสีน้ำตาล</string>\n    <string name=\"deep_purple_theme\">ธีมสีม่วงเข้ม</string>\n    <string name=\"green_theme\">ธีมสีเขียว</string>\n    <string name=\"indigo_theme\">ธีมส้มเหลือง</string>\n    <string name=\"light_green_theme\">ธีมสีเขียวอ่อน</string>\n    <string name=\"orange_theme\">ธีมสีส้ม</string>\n    <string name=\"lime_theme\">ธีมเขียวมะนาว</string>\n    <string name=\"pink_theme\">ธีมสีชมพู</string>\n    <string name=\"purple_theme\">ธีมสีม่วง</string>\n    <string name=\"sakura_theme\">ธีมซากุระ</string>\n    <string name=\"red_theme\">ธีมสีแดง</string>\n    <string name=\"teal_theme\">ธีมสีน้ำเงินอมเขียว</string>\n    <string name=\"yellow_theme\">ธีมสีเหลือง</string>\n    <string name=\"about_app_desc\">โซลูชันรูทเคอร์เนลที่มีเพียงอิมเมจเคอร์เนลแบบสตริปเท่านั้น ซึ่งให้ความสามารถในการติดตั้งโมดูลระบบและเชื่อมต่อฟังก์ชันเคอร์เนล</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">สอบถามข้อมูลเพิ่มเติมได้หรือมีปัญญาทางเทคนิค</string>\n    <string name=\"home_more_menu_about\">เกี่ยวกับ</string>\n    <string name=\"kpm_control_failed\">การดำเนินการล้มเหลว!</string>\n    <string name=\"blue_theme\">ธีมสีฟ้า</string>\n    <string name=\"apm_action\">การกระทำ</string>\n    <string name=\"home_dialog_auth_fail_title\">การตรวจสอบสิทธิ์ล้มเหลว</string>\n    <string name=\"kpm_control_dialog_content\">จัดเตรียมไปยังฟังก์ชัน</string>\n    <string name=\"home_dialog_uninstall_all\">ถอนการติดตั้งทั้งหมด</string>\n    <string name=\"patch_item_extra_args\">อาร์กส์</string>\n    <string name=\"kpm_control\">ควบคุม</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">ชื่อผู้จัดการคนใหม่</string>\n    <string name=\"hide_apatch_dialog_summary\">จะถูกใช้เป็นป้ายแอปใหม่ที่แสดงในตัวเรียกใช้งาน</string>\n    <string name=\"apm_webui_open\">เปิด</string>\n    <string name=\"enable_web_debugging\">เปิดใช้งานการดีบักเว็บวิว</string>\n    <string name=\"mode_select_page_install_inactive_slot\">ติดตั้งลงในพื้นที่ที่ไม่ได้ใช้งาน (หลัง OTA)</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">อุปกรณ์ของคุณจะถูก **บังคับ** ให้รีเซ็ตไปยังพื้นที่ไม่ได้ใช้งานปัจจุบันหลังจากรีเซ็ต!\\n\\nใช้ตัวเลือกนี้เฉพาะหลังจาก OTA เสร็จสิ้นเท่านั้น\\n\\nดำเนินการต่อหรือไม่</string>\n    <string name=\"settings_use_system_color_theme_summary\">ใช้ธีมสีที่สร้างโดยระบบด้วยวอลเปเปอร์ปัจจุบัน</string>\n    <string name=\"settings_custom_color_theme\">ธีมสี</string>\n    <string name=\"amber_theme\">ธีมสีเหลือง</string>\n    <string name=\"deep_orange_theme\">ธีมสีส้มเข้ม</string>\n    <string name=\"home_dialog_auth_fail_content\">ไม่สามารถตรวจสอบสิทธิ์ซูเปอร์คีย์ได้ ดังนั้น APatch จึงไม่สามารถทำงานได้อย่างถูกต้อง\\n\\nต่อไปนี้คือสาเหตุที่เป็นไปได้บางประการที่ทำให้การตรวจสอบสิทธิ์ล้มเหลว:\\n\\n1. คุณไม่ได้รีเซ็ตการบูตด้วย KernelPatch\\n\\n2. รีเซ็ตการบูตที่เนิ่มใหม่แล้วไม่ได้ถูกต้อง\\n\\n3. ซูเปอร์คีย์ไม่ถูกต้อง\\n\\n4. อุปกรณ์ของคุณไม่รองรับ APatch และ KernelPatch\\n\\nโปรดตรวจสอบและลองอีกครั้ง หากยังคงมีปัญหาอยู่ คุณสามารถถามคำถามได้เสมอที่หน้าปัญหาของที่เก็บข้อมูลอย่างเป็นทางการ</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-tr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"apm_reboot_to_apply\">Değişikleri uygulamak için yeniden başlatın</string>\n    <string name=\"android_patch\">AndroidPatch</string>\n    <string name=\"kpm_unload_confirm\">\\\"%s\\\" modülü boşaltılsın mı?</string>\n    <string name=\"apm_uninstall_success\">\\\"%s\\\" kaldırıldı</string>\n    <string name=\"send_log\">Günlükleri gönder</string>\n    <string name=\"apm_install\">Kur</string>\n    <string name=\"home_auth_key_desc\">Sertifikasyondan sonra başlar</string>\n    <string name=\"kpatch_version\">Sürüm: %s</string>\n    <string name=\"apm_remove\">Kaldır</string>\n    <string name=\"patch_warnning\">Kurulum işlemi risklidir. Lütfen verilerinizi yedeklediğinizden emin olun.</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch kurulu değil</string>\n    <string name=\"home_patch_set_key_desc\">KernelPatch için tek gerekli veri</string>\n    <string name=\"home_install_unknown\">Kurulmadı veya kimliği doğrulanmadı</string>\n    <string name=\"apm_uninstall_confirm\">\\\"%s\\\" modülü kaldırılsın mı?</string>\n    <string name=\"su_pkg_excluded_setting_title\">Değişiklikleri hariç tut</string>\n    <string name=\"reboot_download\">İndirme modunda yeniden başlat</string>\n    <string name=\"home_click_to_learn_apatch\">APatch\\'in özelliklerini ve nasıl kullanılacağını öğrenin</string>\n    <string name=\"apm_version\">Sürüm</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Bu seçeneğin etkinleştirilmesi APatch\\'in bu uygulamanın modülleri tarafından değiştirilmiş herhangi bir dosyayı geri yüklemesine izin verecektir.</string>\n    <string name=\"reboot_edl\">EDL modunda yeniden başlat</string>\n    <string name=\"home_installing\">Kuruluyor</string>\n    <string name=\"apm_start_downloading\">İndirme başladı: \\\"%s\\\"</string>\n    <string name=\"su_pkg_excluded_label\">dahil etme</string>\n    <string name=\"su_title\">SU</string>\n    <string name=\"apm\">AP Modül</string>\n    <string name=\"kpm_desc\">Açıklama</string>\n    <string name=\"su_selinux_via_hook\">kanca ile bypass et</string>\n    <string name=\"home_ap_cando_uninstall\">Kaldır</string>\n    <string name=\"kpm_args\">Argümanlar</string>\n    <string name=\"home_fingerprint\">Parmak izi</string>\n    <string name=\"apatch_version\">Sürüm: %s</string>\n    <string name=\"apm_overlay_fs_not_available\">OverlayFS, kernel tarafından devre dışı bırakıldığından modüllere erişilemiyor!</string>\n    <string name=\"kpm_version\">Sürüm</string>\n    <string name=\"su_refresh\">Yenile</string>\n    <string name=\"safe_mode\">Güvenli mod</string>\n    <string name=\"su_show_system_apps\">Sistem uygulamalarını göster</string>\n    <string name=\"home_ap_cando_install\">Kur</string>\n    <string name=\"super_key\">Süper Anahtar</string>\n    <string name=\"reboot_recovery\">Kurtarma modunda yeniden başlat</string>\n    <string name=\"home_learn_apatch\">APatch\\'i öğrenin</string>\n    <string name=\"apm_failed_to_disable\">\\\"%s \\\"modülü devre dışı bırakılamadı</string>\n    <string name=\"kernel_patch\">KernelPatch</string>\n    <string name=\"home_click_to_install\">Kurmak için tıklayın</string>\n    <string name=\"home_selinux_status_unknown\">Bilinmiyor</string>\n    <string name=\"home_apatch_version\">APatch sürümü</string>\n    <string name=\"about\">Hakkında</string>\n    <string name=\"home_selinux_status_permissive\">Serbest</string>\n    <string name=\"reboot\">Yeniden başlat</string>\n    <string name=\"home_need_update\">Yeni sürüm mevcut</string>\n    <string name=\"home_selinux_status\">SELinux durumu</string>\n    <string name=\"apm_changelog\">Değişiklik listesi</string>\n    <string name=\"apm_uninstall_failed\">%s kaldırılamadı</string>\n    <string name=\"kpm_author\">Geliştirici</string>\n    <string name=\"apm_failed_to_enable\">\\\"%s\\\" modülü etkinleştirilemedi</string>\n    <string name=\"home\">Ana sayfa</string>\n    <string name=\"patch_set_superkey\">Süper Anahtar\\'ı ayarla</string>\n    <string name=\"apm_downloading\">\\\"%s\\\"modülü indiriliyor…</string>\n    <string name=\"su_hide_system_apps\">Sistem uygulamalarını gizle</string>\n    <string name=\"home_su_path\">su programı</string>\n    <string name=\"apm_magisk_conflict\">Magisk ile çakıştığı için modüllere erişilemiyor!</string>\n    <string name=\"apm_desc\">Açıklama</string>\n    <string name=\"home_ap_cando_update\">Güncelle</string>\n    <string name=\"kpm_load_toast_failed\">Yüklenemedi</string>\n    <string name=\"kpm_unload\">Yüklemeyi kaldır</string>\n    <string name=\"home_selinux_status_disabled\">Devredışı</string>\n    <string name=\"settings\">Ayarlar</string>\n    <string name=\"apm_new_version_available\">Yeni %s sürümü mevcut, yükseltmek için tıklayın.</string>\n    <string name=\"apatch_version_update\">Sürüm: %s -&gt; %s</string>\n    <string name=\"home_working\">Çalışıyor 😋</string>\n    <string name=\"apm_empty\">Hiç modül kurulmadı</string>\n    <string name=\"kpm_load\">Yükle</string>\n    <string name=\"home_patch_next_step\">Sonraki adım</string>\n    <string name=\"home_auth_key_title\">Süper Anahtarı girin</string>\n    <string name=\"apm_update\">Güncelle</string>\n    <string name=\"home_kernel\">Kernel versiyon</string>\n    <string name=\"home_not_installed\">Kurulu değil</string>\n    <string name=\"kpm\">KP Modül</string>\n    <string name=\"home_selinux_status_enforcing\">Enforcing</string>\n    <string name=\"kpm_license\">Lisans</string>\n    <string name=\"reboot_bootloader\">Önyükleyici modunda yeniden başlat</string>\n    <string name=\"kpm_apm_empty\">Yüklü modül yok</string>\n    <string name=\"about_source_code\"><![CDATA[<p>%1$s üzerinden kaynak koduna göz atın<p/>%2$s kanalımıza katılın<p/>%2$s grubumuza katılın]]></string>\n    <string name=\"home_manager_version\">Yönetici sürümü</string>\n    <string name=\"kpm_load_toast_succ\">Başarıyla yüklendi</string>\n    <string name=\"apm_author\">Geliştirici</string>\n    <string name=\"patch_title\">Yamala</string>\n    <string name=\"clear_super_key\">Süper Anahtarı Sil</string>\n    <string name=\"apm_not_installed\">AndroidPatch kurulu değil</string>\n    <string name=\"settings_app_language\">Dil</string>\n    <string name=\"system_default\">Sistem varsayılanı</string>\n    <string name=\"patch\">Yamala</string>\n    <string name=\"settings_global_namespace_mode\">Küresel ad alanı modu</string>\n    <string name=\"settings_global_namespace_mode_summary\">Tüm root oturumları global bağlama ad alanını kullanır</string>\n    <string name=\"settings_clear_super_key_dialog\">Gerçekten devam etmek istiyor musunuz?</string>\n    <string name=\"kpatch_version_update\">Sürüm: %s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_ap_cando_reboot\">Yeniden başlat</string>\n    <string name=\"patch_config_title\">Yamalar</string>\n    <string name=\"patch_mode_bootimg_patch\">Mod: Yama</string>\n    <string name=\"patch_mode_patch_and_install\">Mod: Güncelle</string>\n    <string name=\"patch_select_bootimg_btn\">Önyüklemeyi seç</string>\n    <string name=\"home_kpatch_info_title\">Bilgi</string>\n    <string name=\"patch_item_bootimg\">önyükleme kalıbı</string>\n    <string name=\"patch_item_existed_extra_kpm\">Var olan</string>\n    <string name=\"patch_mode_uninstall_patch\">Mod: Yama kaldır</string>\n    <string name=\"patch_item_bootimg_slot\">yuva:</string>\n    <string name=\"patch_item_extra_name\">Ad:</string>\n    <string name=\"patch_item_bootimg_dev\">aygıt:</string>\n    <string name=\"patch_start_patch_btn\">Başlat</string>\n    <string name=\"patch_item_kernel\">Çekirdek</string>\n    <string name=\"patch_item_extra_version\">Sürüm:</string>\n    <string name=\"patch_embed_kpm_btn\">KPM göm</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_extra_author\">Yazar:</string>\n    <string name=\"patch_item_extra_kpm_license\">Lisans:</string>\n    <string name=\"patch_item_extra_args\">Argümanlar:</string>\n    <string name=\"patch_start_unpatch_btn\">Yamayı kaldır</string>\n    <string name=\"patch_item_kpimg_version\">Sürüm:</string>\n    <string name=\"patch_item_error\">!!HATA!!</string>\n    <string name=\"patch_item_kpimg_comile_time\">Zaman:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Açıklama:</string>\n    <string name=\"patch_item_kpimg_config\">Yapılandırma:</string>\n    <string name=\"patch_item_new_extra_kpm\">Yeni göm</string>\n    <string name=\"patch_item_extra_event\">Olay:</string>\n    <string name=\"patch_item_skey\">SüperAnahtar</string>\n    <string name=\"patch_item_set_skey_label\">SüperAnahtarın uzunluğu 8-63 karakter uzunluğunda olmalı ve rakam ve harf içermeli, fakat özel karakter içermemelidir.</string>\n    <string name=\"hide_apatch_manager\">APatch Yöneticisini Gizle</string>\n    <string name=\"hide_apatch_dialog_summary\">Başlatıcıda gösterilen yeni uygulama etiketi olarak kullanılacaktır</string>\n    <string name=\"kpm_add_kpm\">KPM ekle</string>\n    <string name=\"kpm_embed\">Göm</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Yeni yönetici adı</string>\n    <string name=\"hide_apatch_manager_failure\">Gizlenemedi. Lütfen hatayı bildirin!</string>\n    <string name=\"kpm_install\">Kur</string>\n    <string name=\"hide_apatch_manager_summary\">Rastgele bir paket kimliği ve özel bir uygulama etiketiyle bir proxy uygulaması yükle.</string>\n    <string name=\"setting_reset_su_path\">\\\"su\\\" programı yolunu sıfırla</string>\n    <string name=\"setting_reset_su_new_path\">Yeni tam yol</string>\n    <string name=\"success\">Başarılı</string>\n    <string name=\"failure\">Başarısız</string>\n    <string name=\"home_new_apatch_found\">Yeni sürüm var: %s, Yükseltmek için tıklayın</string>\n    <string name=\"settings_check_update\">Güncellemeleri denetle</string>\n    <string name=\"patch_mode_install_to_next_slot\">Mod: Aktif olmayan yuvaya kur (OTA\\'dan sonra)</string>\n    <string name=\"mode_select_page_patch_and_install\">Yama ve Kur</string>\n    <string name=\"mode_select_page_select_file\">Yama yapılacak bir boot (önyükleme) imajı seçin.</string>\n    <string name=\"home_dialog_auth_fail_title\">Kimlik doğrulama başarısız</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Geri bildirim veya öneri</string>\n    <string name=\"home_more_menu_about\">Hakkında</string>\n    <string name=\"mode_select_page_title\">Kur</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Etkin olmayan yuvaya kur (OTA\\'dan sonra)</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Aygıtınız yeniden başlatıldıktan sonra geçerli etkin olmayan yuvaya önyükleme yapmaya **ZORLANACAK**!\n\\nBu seçeneği yalnızca OTA tamamlandıktan sonra kullanın.\n\\nDevam edilsin mi?</string>\n    <string name=\"home_dialog_auth_fail_content\">SuperKey doğrulanamadığından APatch düzgün çalışamıyor.\\nDoğrulama başarısızlığının bazı olası nedenleri şunlardır:\\n1. boot.img dosyasını KernelPatch ile yamalamadınız.\\n2. Yamalı boot.img dosyası yazılmadı.\\n3. SuperKey hatalı ya da özel karakterler içeriyor.\\n4. Cihazınız APatch ve KernelPatch desteklemiyor.\\n\\nLütfen bu maddeleri gözden geçirin ve tekrar deneyin. Hala sorun varsa, resmi deponun sorunlar sayfasından her zaman soru sorabilirsiniz.</string>\n    <string name=\"settings_check_update_summary\">Uygulama açıldığında güncellemeleri otomatik olarak denetle</string>\n    <string name=\"apm_webui_open\">Aç</string>\n    <string name=\"enable_web_debugging\">Web Görünümü Hata Ayıklamayı Etkinleştir</string>\n    <string name=\"settings_donot_store_superkey_summary\">SuperKey her zaman yönetici başlar</string>\n    <string name=\"enable_web_debugging_summary\">Web arayüzünde hata ayıklamak için kullanılabilir, lütfen yalnızca gerektiğinde etkinleştirin.</string>\n    <string name=\"settings_donot_store_superkey\">Süper anahtarı yerel olarak saklama</string>\n    <string name=\"home_system_version\">Sistem sürümü</string>\n    <string name=\"home_dialog_uninstall_all\">Hepsini kaldır</string>\n    <string name=\"home_install_unknown_summary\">Kurmak için tıklayın</string>\n    <string name=\"home_device_info\">Aygıt</string>\n    <string name=\"home_kpatch_version\">KernelPatch sürümü</string>\n    <string name=\"home_dialog_uninstall_title\">Kaldır</string>\n    <string name=\"home_dialog_uninstall_ap_only\">AndroidPatch\\'i kaldır</string>\n    <string name=\"kpm_control\">Denetim</string>\n    <string name=\"kpm_control_outMsg\">Mesaj</string>\n    <string name=\"kpm_control_failed\">İşlem başarısız!</string>\n    <string name=\"settings_night_theme_enabled\">Koyu temayı etkinleştir</string>\n    <string name=\"settings_custom_color_theme\">Renk teması</string>\n    <string name=\"light_blue_theme\">Açık mavi</string>\n    <string name=\"kpm_control_paramters\">Parametreler</string>\n    <string name=\"kpm_control_ok\">İşlem başarılı!</string>\n    <string name=\"settings_use_system_color_theme\">Sistem Renk Teması</string>\n    <string name=\"blue_theme\">Mavi</string>\n    <string name=\"brown_theme\">Kahverengi</string>\n    <string name=\"cyan_theme\">Camgöbeği</string>\n    <string name=\"deep_orange_theme\">Koyu Turuncu</string>\n    <string name=\"deep_purple_theme\">Koyu mor</string>\n    <string name=\"indigo_theme\">Çivit Mavisi</string>\n    <string name=\"light_green_theme\">Açık yeşil</string>\n    <string name=\"lime_theme\">Açık yeşil</string>\n    <string name=\"orange_theme\">Turuncu</string>\n    <string name=\"pink_theme\">\"Pembe \"</string>\n    <string name=\"purple_theme\">Mor</string>\n    <string name=\"red_theme\">Kırmızı</string>\n    <string name=\"sakura_theme\">Kiraz Çiçeği</string>\n    <string name=\"teal_theme\">Cam göbeği</string>\n    <string name=\"yellow_theme\">Sarı</string>\n    <string name=\"about_app_version\">Sürüm %1$s</string>\n    <string name=\"about_app_desc\">Yalnızca sadeleştirilmiş bir çekirdek kalıbına sahip çekirdek root çözümü, sistem modülünü bağlama ve çekirdek işlevini kancalama olanağı sağlar.</string>\n    <string name=\"about_telegram_channel\">Telegram kanalı</string>\n    <string name=\"about_telegram_group\">Telegram grubu</string>\n    <string name=\"about_powered_by\">%1$s desteğiyle</string>\n    <string name=\"kpm_control_dialog_title\">KPModule Denetimi</string>\n    <string name=\"kpm_control_dialog_content\">Giriş denetim parametreleri:</string>\n    <string name=\"settings_night_mode_follow_sys\">Sistemin koyu temasını kullan</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Sistem ayarına göre otomatik olarak koyu temaya geç</string>\n    <string name=\"settings_use_system_color_theme_summary\">Geçerli duvar kağıdı ile sistem tarafından oluşturulan bir renk teması kullanın</string>\n    <string name=\"amber_theme\">Kehribar</string>\n    <string name=\"blue_grey_theme\">Mavi gri</string>\n    <string name=\"green_theme\">\"Yeşil \"</string>\n    <string name=\"save_log\">Günlükleri kaydet</string>\n    <string name=\"apm_action\">Eylem</string>\n    <string name=\"log_saved\">Günlükler kaydedildi</string>\n    <string name=\"crash_handle_title\">Uygulama çöktü…</string>\n    <string name=\"crash_handle_copy\">Çökme raporunu kopyala</string>\n    <string name=\"crash_handle_copied\">Çökme raporu panoya kopyalandı.</string>\n    <string name=\"settings_lite_mode\">Lite modunu etkinleştir.</string>\n    <string name=\"settings_lite_mode_mode_summary\">APModule işlevleri etkinleştirildikten sonra hatalar gösterebilir, ancak bazı durumlarda tespiti etkili bir şekilde engelleyebilir. Yeniden başlatma gereklidir.</string>\n    <string name=\"settings_force_overlayfs_mode\">OverlayFS kullanımını zorla</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Kernel desteği mevcut olduğunda, Magic Mount yerine APModule’leri bağlamak için OverlayFS kullan. Yeniden başlatma gereklidir.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">Головна</string>\n    <string name=\"kernel_patch\">Заплатка ядра</string>\n    <string name=\"android_patch\">Заплатка для Android</string>\n    <string name=\"reboot\">Перезавантаження</string>\n    <string name=\"settings\">Налаштування</string>\n    <string name=\"reboot_recovery\">Перезавантаження в режим відновлення</string>\n    <string name=\"reboot_bootloader\">Перезавантаження в завантажувач</string>\n    <string name=\"reboot_download\">Перезавантаження в режим завантаження</string>\n    <string name=\"about\">Про</string>\n    <string name=\"home_learn_apatch\">Дізнайтеся більше про APatch</string>\n    <string name=\"safe_mode\">Безпечний режим</string>\n    <string name=\"super_key\">СуперКлюч</string>\n    <string name=\"clear_super_key\">Очистити SuperKey</string>\n    <string name=\"patch_set_superkey\">Встановити SuperKey</string>\n    <string name=\"home_patch_set_key_desc\">Пароль для KernelPatch</string>\n    <string name=\"home_patch_next_step\">Наступний крок</string>\n    <string name=\"home_not_installed\">Не встановлено</string>\n    <string name=\"home_install_unknown\">Не встановлено або автентифіковано</string>\n    <string name=\"home_click_to_install\">Натисніть щоб встановити</string>\n    <string name=\"home_working\">Працює😋</string>\n    <string name=\"home_installing\">Встановлення</string>\n    <string name=\"kpatch_version\">Версія: %s</string>\n    <string name=\"apatch_version\">Версія: %s</string>\n    <string name=\"home_su_path\">Виконуваний файл su</string>\n    <string name=\"home_auth_key_title\">Введіть SuperKey</string>\n    <string name=\"home_ap_cando_update\">Оновити</string>\n    <string name=\"patch_title\">Залатати</string>\n    <string name=\"home_manager_version\">Версія менеджера</string>\n    <string name=\"home_fingerprint\">Відбиток</string>\n    <string name=\"home_selinux_status\">Статус SELinux</string>\n    <string name=\"home_selinux_status_disabled\">Вимкнено</string>\n    <string name=\"home_selinux_status_enforcing\">Примусовий</string>\n    <string name=\"home_selinux_status_permissive\">Дозвільний</string>\n    <string name=\"kpm\">KPМодуль</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch не встановлено</string>\n    <string name=\"kpm_load\">Завантажити</string>\n    <string name=\"kpm_load_toast_failed\">Не вдалося встановити</string>\n    <string name=\"kpm_author\">Автор</string>\n    <string name=\"kpm_args\">Аргументи</string>\n    <string name=\"su_selinux_via_hook\">Обхід через хук</string>\n    <string name=\"su_pkg_excluded_setting_title\">Виключити зміни</string>\n    <string name=\"su_show_system_apps\">Показати системні додатки</string>\n    <string name=\"su_refresh\">Оновити</string>\n    <string name=\"apm\">Модулі</string>\n    <string name=\"apm_not_installed\">AndroidPatch не встановлено</string>\n    <string name=\"apm_failed_to_enable\">Не вдалося ввімкнути модуль \\\"%s\\\"</string>\n    <string name=\"apm_remove\">Видалити</string>\n    <string name=\"apm_author\">Автор</string>\n    <string name=\"apm_desc\">Опис</string>\n    <string name=\"apm_reboot_to_apply\">Перезавантажте, щоб зміни вступити в силу</string>\n    <string name=\"apm_changelog\">Список змін</string>\n    <string name=\"apm_update\">Оновлення</string>\n    <string name=\"apm_start_downloading\">Початок завантаження %s</string>\n    <string name=\"patch_warnning\">Інсталяція має ризики. Будь ласка, створіть резервну копію ваших даних.</string>\n    <string name=\"reboot_edl\">Перезавантаження в EDL</string>\n    <string name=\"home_click_to_learn_apatch\">Дізнайтеся більше про можливості APatch і про його використання</string>\n    <string name=\"about_source_code\"><![CDATA[<p> Перегляньте вихідний код на %1$s<p/> Приєднуйтеся до нашого каналу %2$s<p/> Приєднуйтеся до нашої групи %3$s]]></string>\n    <string name=\"send_log\">Надіслати журнали</string>\n    <string name=\"apatch_version_update\">Версія: %s → %s</string>\n    <string name=\"home_apatch_version\">Версія APatch</string>\n    <string name=\"home_need_update\">Доступне оновлення</string>\n    <string name=\"home_auth_key_desc\">Почати після сертифікації</string>\n    <string name=\"home_ap_cando_uninstall\">Видалити</string>\n    <string name=\"home_ap_cando_install\">Встановити</string>\n    <string name=\"home_kernel\">Версія ядра</string>\n    <string name=\"kpm_load_toast_succ\">Встановленно успішно</string>\n    <string name=\"home_selinux_status_unknown\">Невідомо</string>\n    <string name=\"kpm_unload\">Видалити</string>\n    <string name=\"kpm_license\">Ліцензія</string>\n    <string name=\"kpm_desc\">Опис</string>\n    <string name=\"kpm_apm_empty\">Немає модулів</string>\n    <string name=\"kpm_version\">Версія</string>\n    <string name=\"su_title\">Суперкористувач</string>\n    <string name=\"su_pkg_excluded_label\">Виключити</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Увімкнення цієї опції дозволить APatch відновлювати будь-які файли, змінені модулями цієї програми.</string>\n    <string name=\"su_hide_system_apps\">Приховати системні додатки</string>\n    <string name=\"apm_empty\">Немає встановлених модулів</string>\n    <string name=\"apm_install\">Встановити</string>\n    <string name=\"apm_uninstall_confirm\">Видалити \\\"%s\\\" модуль?</string>\n    <string name=\"apm_uninstall_success\">%s видалено</string>\n    <string name=\"apm_uninstall_failed\">Не вдалося видалити %s</string>\n    <string name=\"apm_version\">Версія</string>\n    <string name=\"apm_overlay_fs_not_available\">Модулі недоступні, оскільки OverlayFS вимкнено ядром!</string>\n    <string name=\"apm_magisk_conflict\">Модулі недоступні через конфлікт з Magisk!</string>\n    <string name=\"apm_downloading\">Завантаження модуля \\\"%s\\\"…</string>\n    <string name=\"kpm_unload_confirm\">Видалити модуль \\\"%s\\\"?</string>\n    <string name=\"apm_new_version_available\">Доступна нова версія %s, натисніть, щоб оновити.</string>\n    <string name=\"apm_failed_to_disable\">Не вдалося вимкнути модуль \\\"%s\\\"</string>\n    <string name=\"settings_app_language\">Мова</string>\n    <string name=\"system_default\">За замовчуванням у системі</string>\n    <string name=\"patch\">Залатати</string>\n    <string name=\"settings_global_namespace_mode\">Режим глобального простору імен</string>\n    <string name=\"settings_global_namespace_mode_summary\">Усі сеанси root використовують монтування глобального простору імен</string>\n    <string name=\"kpatch_shadow_path_title\">Kpatch</string>\n    <string name=\"home_ap_cando_reboot\">Перезавантаження</string>\n    <string name=\"patch_config_title\">Латки</string>\n    <string name=\"patch_mode_bootimg_patch\">Режим: Латка</string>\n    <string name=\"patch_mode_patch_and_install\">Режим: Залатати та встановити</string>\n    <string name=\"patch_mode_uninstall_patch\">Режим: Скасування латки</string>\n    <string name=\"patch_select_bootimg_btn\">Виберіть boot</string>\n    <string name=\"patch_embed_kpm_btn\">Вбудований KPM</string>\n    <string name=\"patch_start_patch_btn\">Старт</string>\n    <string name=\"patch_start_unpatch_btn\">Скасування латки</string>\n    <string name=\"patch_item_error\">!!ПОМИЛКА!!</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_bootimg_slot\">слот:</string>\n    <string name=\"patch_item_bootimg_dev\">пристрій:</string>\n    <string name=\"patch_item_kernel\">Ядро</string>\n    <string name=\"patch_item_kpimg\">Kpimg</string>\n    <string name=\"patch_item_kpimg_version\">Версія:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Час:</string>\n    <string name=\"patch_item_kpimg_config\">Налаштування:</string>\n    <string name=\"patch_item_new_extra_kpm\">Вбудувати новий</string>\n    <string name=\"patch_item_existed_extra_kpm\">Існуючий</string>\n    <string name=\"patch_item_extra_name\">Ім\\'я:</string>\n    <string name=\"patch_item_extra_version\">Версія:</string>\n    <string name=\"patch_item_extra_author\">Автор:</string>\n    <string name=\"patch_item_extra_kpm_license\">Ліцензія:</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Опис:</string>\n    <string name=\"patch_item_extra_args\">Аргументи:</string>\n    <string name=\"patch_item_extra_event\">Подія:</string>\n    <string name=\"patch_item_set_skey_label\">SuperKey має містити 8-63 символи та містити цифри та літери, але без спеціальних символів.</string>\n    <string name=\"patch_item_skey\">СуперКлюч</string>\n    <string name=\"settings_clear_super_key_dialog\">Ви дійсно хочете продовжити?</string>\n    <string name=\"kpatch_version_update\">Версія: %s -&gt; %s</string>\n    <string name=\"home_kpatch_info_title\">Інфо</string>\n    <string name=\"settings_check_update_summary\">Автоматично перевіряти оновлення при відкритті застосунку</string>\n    <string name=\"success\">Успішно</string>\n    <string name=\"failure\">Помилка</string>\n    <string name=\"settings_check_update\">Перевірити наявність оновлень</string>\n    <string name=\"settings_donot_store_superkey\">Не зберігайте SuperKey локально</string>\n    <string name=\"patch_mode_install_to_next_slot\">Режим: встановлення в неактивний слот (після OTA)</string>\n    <string name=\"hide_apatch_manager_summary\">Встановіть проксі-додаток із випадковим ідентифікатором пакета та власною міткою додатка</string>\n    <string name=\"enable_web_debugging_summary\">Можна використовувати для налагодження WebUI. Увімкніть лише за потреби.</string>\n    <string name=\"home_new_apatch_found\">Доступна нова версія %s, натисніть, щоб оновити.</string>\n    <string name=\"home_install_unknown_summary\">Натисніть щоб встановити</string>\n    <string name=\"mode_select_page_patch_and_install\">Виправте та встановіть</string>\n    <string name=\"home_device_info\">Пристрій</string>\n    <string name=\"home_system_version\">Версія системи</string>\n    <string name=\"home_kpatch_version\">Версія KernelPatch</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Нове ім\\'я менеджера</string>\n    <string name=\"hide_apatch_dialog_summary\">Воно буде використовуватися як нове ім\\'я застосунку, яке відображатиметься на робочому столі</string>\n    <string name=\"hide_apatch_manager_failure\">Не вдалося сховатися. Будь ласка, повідомте про помилку!</string>\n    <string name=\"enable_web_debugging\">Увімкнути налагодження WebView</string>\n    <string name=\"settings_donot_store_superkey_summary\">Під час кожного запуску диспетчера перевіряйте автентичність SuperKey</string>\n    <string name=\"setting_reset_su_path\">Скинути шлях до файлу su</string>\n    <string name=\"setting_reset_su_new_path\">Новий повний шлях</string>\n    <string name=\"apm_webui_open\">Відкрити</string>\n    <string name=\"hide_apatch_manager\">Приховати APatch Manager</string>\n    <string name=\"kpm_embed\">Вставити</string>\n    <string name=\"kpm_add_kpm\">Додати KPM</string>\n    <string name=\"kpm_install\">Встановити</string>\n    <string name=\"mode_select_page_title\">Встановити</string>\n    <string name=\"home_more_menu_about\">Про</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Встановити в неактивний слот (після OTA)</string>\n    <string name=\"home_dialog_uninstall_title\">Видалити</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Видалити AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">Видалити все</string>\n    <string name=\"mode_select_page_select_file\">Виберіть образ завантаження для патчу</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Ваш пристрій буде **ПРИМУШЕНО** завантажитися в поточний неактивний слот після перезавантаження!\n\\nВикористовуйте цей параметр лише після завершення OTA.\n\\nПродовжити?</string>\n    <string name=\"home_dialog_auth_fail_content\">Неможливо автентифікувати SuperKey, тому APatch не може працювати належним чином. \\nНижче наведено кілька можливих причин помилки автентифікації. \\n1. Ви не виправили boot.img за допомогою KernelPatch. \\n2. Виправлений boot.img не був прошитий. \\n3. SuperKey неправильний або містить спеціальні символи. \\n4. Ваш пристрій не підтримує APatch і KernelPatch. \\n\\nПеревірте та повторіть спробу. Якщо проблеми все ще є, ви завжди можете поставити запитання на сторінці проблем офіційного репозиторію.</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Зворотній зв\\'язок</string>\n    <string name=\"home_dialog_auth_fail_title\">Помилка авторизації</string>\n    <string name=\"kpm_control_dialog_content\">Введіть параметри контролю:</string>\n    <string name=\"kpm_control_outMsg\">Повідомлення</string>\n    <string name=\"kpm_control_ok\">Операцію виконано успішно!</string>\n    <string name=\"kpm_control_failed\">Операцію не виконано!</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Автоматично переключатися на темну тему залежно від налаштувань системи</string>\n    <string name=\"settings_use_system_color_theme_summary\">Використовуйте колірну тему, згенеровану системою на основі поточних шпалер</string>\n    <string name=\"settings_custom_color_theme\">Кольорова тема</string>\n    <string name=\"blue_grey_theme\">Синій сірий</string>\n    <string name=\"green_theme\">Зелена</string>\n    <string name=\"brown_theme\">Коричневий</string>\n    <string name=\"indigo_theme\">Синьо-фіолетова</string>\n    <string name=\"light_blue_theme\">Світло-синя</string>\n    <string name=\"purple_theme\">Фіолетова</string>\n    <string name=\"red_theme\">Червона</string>\n    <string name=\"sakura_theme\">Сакура</string>\n    <string name=\"teal_theme\">Чирок</string>\n    <string name=\"yellow_theme\">Жовта</string>\n    <string name=\"orange_theme\">Оранжева</string>\n    <string name=\"about_telegram_channel\">Телеграм канал</string>\n    <string name=\"settings_use_system_color_theme\">Системна кольорова тема</string>\n    <string name=\"amber_theme\">Бурштин</string>\n    <string name=\"blue_theme\">Синій</string>\n    <string name=\"cyan_theme\">Блакитна</string>\n    <string name=\"deep_orange_theme\">Темно-оранджева</string>\n    <string name=\"deep_purple_theme\">Темньо-фіолетова</string>\n    <string name=\"light_green_theme\">Світло-зелена</string>\n    <string name=\"lime_theme\">Лаймова</string>\n    <string name=\"pink_theme\">Рожева</string>\n    <string name=\"kpm_control\">Керування</string>\n    <string name=\"about_app_version\">Версія %1$s</string>\n    <string name=\"about_app_desc\">Кореневе рішення ядра лише з очищеним образом ядра, що забезпечує можливість монтування системного модуля та підключення функції ядра.</string>\n    <string name=\"about_telegram_group\">Телеграм група</string>\n    <string name=\"about_powered_by\">На основі %1$s</string>\n    <string name=\"kpm_control_dialog_title\">Управління KPModule</string>\n    <string name=\"kpm_control_paramters\">Параметри</string>\n    <string name=\"settings_night_mode_follow_sys\">Дотримуйтеся темної теми системи</string>\n    <string name=\"settings_night_theme_enabled\">Увімкнути темну тему</string>\n    <string name=\"save_log\">Зберегти журнали</string>\n    <string name=\"apm_action\">Дія</string>\n    <string name=\"log_saved\">Журнали збережено</string>\n    <string name=\"crash_handle_title\">Збій програми…</string>\n    <string name=\"crash_handle_copied\">Журнал збоїв скопійовано в буфер обміну.</string>\n    <string name=\"crash_handle_copy\">Копіювати журнал збоїв</string>\n    <string name=\"settings_lite_mode\">Увімкнути спрощений режим</string>\n    <string name=\"settings_lite_mode_mode_summary\">Функції APModule можуть демонструвати збої після ввімкнення, але в деяких випадках вони все ще можуть ефективно уникати виявлення. Потрібне перезавантаження.</string>\n    <string name=\"settings_force_overlayfs_mode\">Примусове використання OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Використовуйте OverlayFS для монтування APModules замість Magic Mount, коли доступна підтримка ядра. Потрібне перезавантаження.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"home\">Trang chủ</string>\n    <string name=\"kernel_patch\">Bản vá Kernel</string>\n    <string name=\"android_patch\">Bản vá Android</string>\n    <string name=\"reboot\">Khởi động lại</string>\n    <string name=\"settings\">Cài đặt</string>\n    <string name=\"reboot_recovery\">Khởi động vào Recovery</string>\n    <string name=\"reboot_bootloader\">Khởi động vào Bootloader</string>\n    <string name=\"reboot_download\">Khởi động vào Download</string>\n    <string name=\"reboot_edl\">Khởi động vào EDL</string>\n    <string name=\"about\">Giới thiệu</string>\n    <string name=\"home_click_to_learn_apatch\">Tìm hiểu về các tính năng của AndroidPatch và cách sử dụng</string>\n    <string name=\"send_log\">Gửi nhật ký</string>\n    <string name=\"safe_mode\">Chế độ an toàn</string>\n    <string name=\"home_patch_next_step\">Bước tiếp theo</string>\n    <string name=\"home_not_installed\">Chưa cài đặt</string>\n    <string name=\"home_install_unknown\">Không xác định</string>\n    <string name=\"home_click_to_install\">Bấm để cài đặt</string>\n    <string name=\"home_working\">Đang hoạt động 😋</string>\n    <string name=\"home_installing\">Đang cài đặt</string>\n    <string name=\"home_need_update\">Có bản cập nhật mới</string>\n    <string name=\"kpatch_version\">Phiên bản: %s</string>\n    <string name=\"apatch_version_update\">Phiên bản: %s -&gt; %s</string>\n    <string name=\"home_auth_key_title\">Nhập SuperKey</string>\n    <string name=\"home_auth_key_desc\">Bắt đầu sau khi được chứng nhận</string>\n    <string name=\"home_ap_cando_install\">Tải Xuống</string>\n    <string name=\"home_ap_cando_update\">Cập nhật</string>\n    <string name=\"home_ap_cando_uninstall\">Gỡ cài đặt</string>\n    <string name=\"patch_title\">Bản vá</string>\n    <string name=\"home_manager_version\">Phiên bản trình quản lý</string>\n    <string name=\"home_fingerprint\">Vân tay</string>\n    <string name=\"home_selinux_status\">Trạng thái SELinux</string>\n    <string name=\"home_selinux_status_disabled\">Tắt</string>\n    <string name=\"home_selinux_status_enforcing\">Đang thực thi (Enforcing)</string>\n    <string name=\"home_selinux_status_permissive\">Cho phép (Permissive)</string>\n    <string name=\"home_selinux_status_unknown\">Không xác định</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch chưa được cài đặt</string>\n    <string name=\"kpm_load_toast_succ\">Tải thành công</string>\n    <string name=\"kpm_load_toast_failed\">Tải không thành công</string>\n    <string name=\"kpm_unload_confirm\">Gỡ bỏ mô-đun %s?</string>\n    <string name=\"kpm_apm_empty\">Không có mô-đun nào được tải</string>\n    <string name=\"kpm_version\">Phiên bản</string>\n    <string name=\"kpm_license\">Giấy phép</string>\n    <string name=\"kpm_load\">Tải</string>\n    <string name=\"kpm_unload\">Dỡ bỏ</string>\n    <string name=\"kpm_desc\">Mô tả</string>\n    <string name=\"su_selinux_via_hook\">Bỏ qua bằng Hook</string>\n    <string name=\"su_pkg_excluded_label\">loại trừ</string>\n    <string name=\"kpm_args\">Tham số</string>\n    <string name=\"apm_failed_to_disable\">Không thể tắt mô-đun %s</string>\n    <string name=\"apm_empty\">Không có module nào được cài đặt</string>\n    <string name=\"apm_remove\">Gỡ cài đặt</string>\n    <string name=\"apm_install\">Cài đặt</string>\n    <string name=\"apm_uninstall_confirm\">Gỡ cài đặt mô-đun %s?</string>\n    <string name=\"apm_uninstall_success\">%s đã được gỡ cài đặt</string>\n    <string name=\"apm_uninstall_failed\">Không thể gỡ cài đặt %s</string>\n    <string name=\"apm_version\">Phiên bản</string>\n    <string name=\"apm_author\">Tác giả</string>\n    <string name=\"apm_desc\">Mô tả</string>\n    <string name=\"apm_overlay_fs_not_available\">Module không khả dụng do OverlayFS bị vô hiệu hoá bởi kernel!</string>\n    <string name=\"apm_reboot_to_apply\">Khởi động lại để có hiệu lực</string>\n    <string name=\"apm_changelog\">Nhật ký thay đổi</string>\n    <string name=\"apm_update\">Cập nhật</string>\n    <string name=\"apm_downloading\">Đang tải xuống module %s…</string>\n    <string name=\"apm_start_downloading\">Bắt đầu tải xuống %s</string>\n    <string name=\"apm_new_version_available\">Đã có phiên %s bản mới, nhấn để nâng cấp phiên bản mới.</string>\n    <string name=\"patch_warnning\">Việc cài đặt đi kèm với rủi ro. Hãy đảm bảo dữ liệu của bạn đã được sao lưu.</string>\n    <string name=\"super_key\">SuperKey</string>\n    <string name=\"patch_set_superkey\">Đặt SuperKey</string>\n    <string name=\"apatch_version\">Phiên bản: %s</string>\n    <string name=\"home_learn_apatch\">Tìm hiểu AndroidPatch</string>\n    <string name=\"home_patch_set_key_desc\">Chỉ có thông tin xác thực cho KernelPatch</string>\n    <string name=\"kpm_author\">Tác giả</string>\n    <string name=\"apm_not_installed\">AndroidPatch chưa được cài đặt</string>\n    <string name=\"su_pkg_excluded_setting_title\">Loại trừ các sửa đổi</string>\n    <string name=\"su_pkg_excluded_setting_summary\">Bật tùy chọn này sẽ cho phép APatch khôi phục mọi tệp đã được các mô-đun của ứng dụng này sửa đổi.</string>\n    <string name=\"su_show_system_apps\">Hiển thị ứng dụng hệ thống</string>\n    <string name=\"su_hide_system_apps\">Ẩn ứng dụng hệ thống</string>\n    <string name=\"su_refresh\">Làm mới</string>\n    <string name=\"apm_failed_to_enable\">Không thể bật mô-đun \\\"%s\\\"</string>\n    <string name=\"clear_super_key\">Xóa SuperKey</string>\n    <string name=\"apm_magisk_conflict\">Modules không khả dụng do xung đột với Magisk!</string>\n    <string name=\"about_source_code\"><![CDATA[<p>Xem mã nguồn tại %1$s<p/>Tham gia kênh %2$s của chúng tôi<p/>Tham gia nhóm %3$s của chúng tôi]]></string>\n    <string name=\"home_su_path\">Thực thi Su</string>\n    <string name=\"home_kernel\">Phiên bản Kernel</string>\n    <string name=\"kpm\">KPModule</string>\n    <string name=\"su_title\">Superuser</string>\n    <string name=\"apm\">APModule</string>\n    <string name=\"settings_app_language\">Ngôn ngữ</string>\n    <string name=\"system_default\">Mặc định hệ thống</string>\n    <string name=\"home_apatch_version\">Phiên bản APatch</string>\n    <string name=\"patch\">Bản vá</string>\n    <string name=\"settings_global_namespace_mode\">Chế độ Global Namespace</string>\n    <string name=\"settings_global_namespace_mode_summary\">Tất cả các phiên Root sử dụng Namespace Mount Global</string>\n    <string name=\"patch_embed_kpm_btn\">Nhúng KPM</string>\n    <string name=\"patch_item_extra_event\">Sự kiện:</string>\n    <string name=\"mode_select_page_select_file\">Chọn một boot image để vá</string>\n    <string name=\"home_dialog_auth_fail_title\">Xác thực thất bại</string>\n    <string name=\"mode_select_page_install_inactive_slot\">Cài đặt vào khe không hoạt động (Sau OTA)</string>\n    <string name=\"home_dialog_auth_fail_content\">Không thể xác thực SuperKey, do đó APatch không thể hoạt động bình thường.\\n \\nDưới đây là một số lý do có thể dẫn đến lỗi xác thực: \\n1. Bạn chưa vá boot image bằng KernelPatch. \\n2. Hình ảnh khởi động được vá không được flash. \\n3. Super key sai. \\n4. Thiết bị của bạn không hỗ trợ APatch và KernelPatch. \\n \\nVui lòng kiểm tra và thử lại. Nếu vẫn còn vấn đề, bạn luôn có thể đặt câu hỏi trên trang vấn đề của kho lưu trữ chính thức.</string>\n    <string name=\"home_dialog_uninstall_all\">Gỡ cài đặt tất cả</string>\n    <string name=\"kpm_control_dialog_title\">Kiểm soát KP Mô-đun</string>\n    <string name=\"kpm_control_dialog_content\">Các thông số điều khiển đầu vào:</string>\n    <string name=\"kpm_control_paramters\">Thông số</string>\n    <string name=\"kpm_control_failed\">Lỗi hệ thống!</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">Tự động chuyển sang chủ đề tối theo thiết đặt của hệ thống</string>\n    <string name=\"settings_use_system_color_theme_summary\">Sử dụng chủ đề màu do hệ thống tạo với hình nền hiện tại</string>\n    <string name=\"settings_custom_color_theme\">Chủ đề màu sắc</string>\n    <string name=\"blue_grey_theme\">Chủ đề BlueGrey</string>\n    <string name=\"brown_theme\">Chủ đề màu nâu</string>\n    <string name=\"deep_purple_theme\">Chủ đề màu tím đậm</string>\n    <string name=\"green_theme\">Chủ đề xanh</string>\n    <string name=\"indigo_theme\">Chủ đề chàm</string>\n    <string name=\"red_theme\">Chủ đề màu đỏ</string>\n    <string name=\"sakura_theme\">Chủ đề hoa anh đào</string>\n    <string name=\"orange_theme\">Chủ đề màu cam</string>\n    <string name=\"teal_theme\">Chủ đề xanh mòng két</string>\n    <string name=\"about_app_desc\">Giải pháp Kernel Root chỉ với một image kernel đã được tước bỏ, cung cấp khả năng mount module hệ thống và hooking chức năng Kernel.</string>\n    <string name=\"success\">Thành công</string>\n    <string name=\"settings_clear_super_key_dialog\">Bạn có thực sự muốn tiếp tục không?</string>\n    <string name=\"settings_check_update\">Kiểm tra cập nhật</string>\n    <string name=\"settings_check_update_summary\">Tự động kiểm tra cập nhật khi mở ứng dụng</string>\n    <string name=\"home_install_unknown_summary\">Bấm để cài đặt</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">Thông tin</string>\n    <string name=\"home_ap_cando_reboot\">Khởi động lại</string>\n    <string name=\"patch_mode_bootimg_patch\">Chế độ: Bản vá</string>\n    <string name=\"patch_mode_patch_and_install\">Chế độ: Patch và cài đặt</string>\n    <string name=\"patch_mode_install_to_next_slot\">Chế độ: Cài đặt vào khe không hoạt động (Sau OTA)</string>\n    <string name=\"patch_mode_uninstall_patch\">Chế độ: Gỡ cài đặt KPatch</string>\n    <string name=\"patch_start_patch_btn\">Bắt đầu</string>\n    <string name=\"patch_start_unpatch_btn\">Bỏ bản vá</string>\n    <string name=\"patch_item_error\">!!LỖI!!</string>\n    <string name=\"patch_item_bootimg_slot\">chỗ:</string>\n    <string name=\"patch_item_bootimg\">bootimg</string>\n    <string name=\"patch_item_kpimg_version\">Phiên bản:</string>\n    <string name=\"patch_item_kpimg_config\">Cấu hình:</string>\n    <string name=\"patch_item_new_extra_kpm\">Nhúng mới</string>\n    <string name=\"patch_item_kernel\">Kernel</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_extra_author\">Tác giả:</string>\n    <string name=\"patch_item_extra_kpm_license\">Giấy phép:</string>\n    <string name=\"patch_item_skey\">SuperKey</string>\n    <string name=\"home_system_version\">Phiên bản hệ thống</string>\n    <string name=\"kpm_control\">Điều khiển</string>\n    <string name=\"hide_apatch_dialog_summary\">Nó sẽ được sử dụng làm nhãn ứng dụng mới hiển thị trong trình khởi chạy</string>\n    <string name=\"hide_apatch_manager_failure\">Không ẩn được. Vui lòng báo cáo lỗi!</string>\n    <string name=\"setting_reset_su_new_path\">Đường dẫn đầy đủ mới</string>\n    <string name=\"settings_donot_store_superkey_summary\">Xác thực Super Key mỗi khi mở ứng dụng quản lý</string>\n    <string name=\"about_app_version\">Phiên bản %1$s</string>\n    <string name=\"about_telegram_channel\">Kênh Telegram</string>\n    <string name=\"about_telegram_group\">Nhóm Telegram</string>\n    <string name=\"failure\">Thất bại</string>\n    <string name=\"patch_config_title\">Bản vá lỗi</string>\n    <string name=\"patch_item_bootimg_dev\">thiết bị:</string>\n    <string name=\"patch_item_kpimg_comile_time\">Thời gian:</string>\n    <string name=\"patch_item_extra_name\">Tên:</string>\n    <string name=\"patch_item_extra_version\">Phiên bản:</string>\n    <string name=\"kpm_install\">Cài đặt</string>\n    <string name=\"kpm_embed\">Nhúng</string>\n    <string name=\"hide_apatch_manager\">Ẩn Trình quản lý APatch</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">Tên người quản lý mới</string>\n    <string name=\"setting_reset_su_path\">Đặt lại đường dẫn su</string>\n    <string name=\"mode_select_page_title\">Cài đặt</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">Thiết bị của bạn sẽ **BẮT BUỘC** khởi động vào khe không hoạt động hiện tại sau khi khởi động lại!\n\\nChỉ sử dụng tùy chọn này sau khi OTA hoàn tất.\n\\nTiếp tục?</string>\n    <string name=\"deep_orange_theme\">Chủ đề màu cam đậm</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">Góp ý hoặc báo lỗi</string>\n    <string name=\"patch_item_set_skey_label\">Độ dài của SuperKey phải có ít nhất 8 ký tự và bao gồm cả số và chữ cái.</string>\n    <string name=\"home_device_info\">Thiết bị</string>\n    <string name=\"home_kpatch_version\">Phiên bản KernelPatch</string>\n    <string name=\"kpm_add_kpm\">Thêm KPM</string>\n    <string name=\"hide_apatch_manager_summary\">Cài đặt proxy mới với ID gói ngẫu nhiên và nhãn ứng dụng tùy chỉnh</string>\n    <string name=\"enable_web_debugging\">Bật gỡ lỗi WebView</string>\n    <string name=\"enable_web_debugging_summary\">Có thể được sử dụng để gỡ lỗi WebUI, Vui lòng chỉ bật khi cần.</string>\n    <string name=\"settings_donot_store_superkey\">Đừng lưu trữ Super Key</string>\n    <string name=\"home_new_apatch_found\">Phiên bản mới %s đã có sẵn, hãy nhấp để nâng cấp.</string>\n    <string name=\"settings_night_mode_follow_sys\">Theo chủ đề tối của hệ thống</string>\n    <string name=\"settings_night_theme_enabled\">Bật chủ đề tối</string>\n    <string name=\"blue_theme\">Chủ đề màu xanh</string>\n    <string name=\"cyan_theme\">Chủ đề màu lục lam</string>\n    <string name=\"pink_theme\">Chủ đề màu hồng</string>\n    <string name=\"yellow_theme\">Chủ đề màu vàng</string>\n    <string name=\"apm_webui_open\">Mở</string>\n    <string name=\"patch_select_bootimg_btn\">Chọn boot</string>\n    <string name=\"patch_item_existed_extra_kpm\">Tồn tại</string>\n    <string name=\"patch_item_extra_kpm_desciption\">Mô tả:</string>\n    <string name=\"patch_item_extra_args\">Tham số:</string>\n    <string name=\"mode_select_page_patch_and_install\">Bản vá và cài đặt</string>\n    <string name=\"home_dialog_uninstall_ap_only\">Gỡ cài đặt AndroidPatch</string>\n    <string name=\"kpm_control_outMsg\">Tin nhắn</string>\n    <string name=\"kpm_control_ok\">Hoạt động đã thành công!</string>\n    <string name=\"settings_use_system_color_theme\">Chủ đề màu hệ thống</string>\n    <string name=\"amber_theme\">Chủ đề hổ phách</string>\n    <string name=\"light_blue_theme\">Chủ đề màu xanh nhạt</string>\n    <string name=\"light_green_theme\">Chủ đề màu xanh nhạt</string>\n    <string name=\"lime_theme\">Chủ đề vôi</string>\n    <string name=\"purple_theme\">Chủ đề màu tím</string>\n    <string name=\"about_powered_by\">Được cung cấp bởi %1$s</string>\n    <string name=\"kpatch_version_update\">Phiên bản: %s -&gt; %s</string>\n    <string name=\"home_more_menu_about\">Giới thiệu</string>\n    <string name=\"home_dialog_uninstall_title\">Gỡ cài đặt</string>\n    <string name=\"save_log\">Lưu nhật ký</string>\n    <string name=\"log_saved\">Đã lưu nhật ký</string>\n    <string name=\"crash_handle_title\">Ứng dụng bị sập…</string>\n    <string name=\"crash_handle_copy\">Sao chép nhật ký sự cố</string>\n    <string name=\"crash_handle_copied\">Nhật ký sự cố đã được sao chép vào bảng tạm.</string>\n    <string name=\"apm_action\">Hoạt động</string>\n    <string name=\"settings_lite_mode\">\"Bật chế độ Lite \"</string>\n    <string name=\"settings_lite_mode_mode_summary\">Các hàm APModule có thể gặp lỗi sau khi được bật, nhưng trong một số trường hợp, chúng vẫn có thể tránh bị phát hiện. Cần khởi động lại.</string>\n    <string name=\"settings_force_overlayfs_mode\">Buộc sử dụng OverlayFS</string>\n    <string name=\"settings_force_overlayfs_mode_summary\">Sử dụng OverlayFS để gắn APModules thay vì Magic Mount khi có hỗ trợ kernel. Cần khởi động lại.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"apm\">系统模块</string>\n    <string name=\"super_key\">超级密钥</string>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"kpm\">内核模块</string>\n    <string name=\"android_patch\">系统补丁</string>\n    <string name=\"save_log\">保存日志</string>\n    <string name=\"log_saved\">日志已保存</string>\n    <string name=\"send_log\">发送日志</string>\n    <string name=\"patch_warnning\">安装过程存在风险，请确保您的数据已备份。</string>\n    <string name=\"home_patch_set_key_desc\">内核补丁的唯一授权凭证</string>\n    <string name=\"home_install_unknown\">未安装或未鉴权</string>\n    <string name=\"home_install_unknown_summary\">点此安装</string>\n    <string name=\"reboot_download\">重启至 Download</string>\n    <string name=\"home_click_to_learn_apatch\">查看 APatch 的特性和用法</string>\n    <string name=\"reboot_edl\">重启至 EDL</string>\n    <string name=\"home_installing\">安装中</string>\n    <string name=\"safe_mode\">安全模式</string>\n    <string name=\"reboot_recovery\">重启至 Recovery</string>\n    <string name=\"home_learn_apatch\">了解 APatch</string>\n    <string name=\"kernel_patch\">内核补丁</string>\n    <string name=\"home_click_to_install\">点此安装</string>\n    <string name=\"about\">关于</string>\n    <string name=\"reboot\">重启</string>\n    <string name=\"home_need_update\">新版本可升级</string>\n    <string name=\"home\">主页</string>\n    <string name=\"back\">返回</string>\n    <string name=\"search\">搜索</string>\n    <string name=\"search_apps\">搜索应用</string>\n    <string name=\"search_modules\">搜索模块</string>\n    <string name=\"learn_more\">了解更多</string>\n    <string name=\"patch_set_superkey\">设置超级密钥</string>\n    <string name=\"settings\">设置</string>\n    <string name=\"home_working\">工作中 😋</string>\n    <string name=\"home_patch_next_step\">下一步</string>\n    <string name=\"home_not_installed\">未安装</string>\n    <string name=\"reboot_bootloader\">重启至 Bootloader</string>\n    <string name=\"about_source_code\"><![CDATA[<p>在%1$s查看源码<p/>加入我们的%2$s频道<p/>加入我们的%3$s讨论组]]></string>\n    <string name=\"home_auth_key_desc\">通过验证后开始使用</string>\n    <string name=\"kpatch_version\">版本：%s</string>\n    <string name=\"home_ap_cando_uninstall\">卸载</string>\n    <string name=\"apatch_version\">版本：%s</string>\n    <string name=\"home_ap_cando_install\">安装</string>\n    <string name=\"home_apatch_version\">APatch 版本</string>\n    <string name=\"home_su_path\">可执行su路径</string>\n    <string name=\"home_ap_cando_update\">更新</string>\n    <string name=\"apatch_version_update\">版本：%s → %s</string>\n    <string name=\"home_auth_key_title\">输入超级密钥</string>\n    <string name=\"home_kernel\">内核版本</string>\n    <string name=\"patch_title\">修补</string>\n    <string name=\"home_fingerprint\">指纹</string>\n    <string name=\"home_selinux_status\">SELinux 状态</string>\n    <string name=\"home_manager_version\">管理器版本</string>\n    <string name=\"kpm_unload_confirm\">卸载“%s”模块？</string>\n    <string name=\"kpm_kp_not_installed\">未安装内核补丁</string>\n    <string name=\"kpm_version\">版本</string>\n    <string name=\"home_selinux_status_unknown\">未知</string>\n    <string name=\"home_selinux_status_permissive\">宽容模式</string>\n    <string name=\"kpm_author\">作者</string>\n    <string name=\"kpm_load_toast_failed\">加载失败</string>\n    <string name=\"kpm_unload\">卸载</string>\n    <string name=\"kpm_control\">参数</string>\n    <string name=\"home_selinux_status_disabled\">禁用</string>\n    <string name=\"kpm_load\">加载</string>\n    <string name=\"home_selinux_status_enforcing\">强制模式</string>\n    <string name=\"kpm_license\">许可</string>\n    <string name=\"kpm_apm_empty\">尚未加载模块</string>\n    <string name=\"kpm_load_toast_succ\">加载成功</string>\n    <string name=\"su_pkg_excluded_setting_title\">排除修改</string>\n    <string name=\"su_pkg_excluded_setting_summary\">针对此应用还原被模块改动的文件。</string>\n    <string name=\"su_pkg_excluded_label\">排除模块</string>\n    <string name=\"su_title\">超级用户</string>\n    <string name=\"kpm_desc\">描述</string>\n    <string name=\"su_selinux_via_hook\">劫持绕过</string>\n    <string name=\"kpm_args\">参数</string>\n    <string name=\"su_refresh\">刷新</string>\n    <string name=\"su_show_system_apps\">显示系统应用</string>\n    <string name=\"apm_failed_to_enable\">无法启用“%s”模块</string>\n    <string name=\"su_hide_system_apps\">隐藏系统应用</string>\n    <string name=\"apm_failed_to_disable\">无法禁用“%s”模块</string>\n    <string name=\"apm_empty\">尚未安装模块</string>\n    <string name=\"apm_reboot_to_apply\">重启生效</string>\n    <string name=\"apm_uninstall_success\">%s 已卸载</string>\n    <string name=\"apm_install\">安装</string>\n    <string name=\"apm_remove\">卸载</string>\n    <string name=\"apm_uninstall_confirm\">确认要卸载“%s”模块吗？</string>\n    <string name=\"metamodule_uninstall_confirm\">\"您确定要卸载模块 %s 吗？此操作将影响所有模块，并且元模块提供的某些功能（如挂载）将不再工作。  \"</string>\n    <string name=\"warning_of_meta_module_title\">需要元模块</string>\n    <string name=\"warning_of_meta_module_summary\">这个模块需要挂载一些文件。需要安装元模块，使它正常工作</string>\n    <string name=\"meta_module_disabled\">模块未挂载，因为元模块已禁用</string>\n    <string name=\"meta_module_removed\">模块未挂载，因为元模块即将删除</string>\n    <string name=\"no_meta_module_installed\">模块未挂载，因为未安装元模块</string>\n    <string name=\"apm_version\">版本</string>\n    <string name=\"apm_start_downloading\">开始下载 %s</string>\n    <string name=\"apm_overlay_fs_not_available\">模块功能不可用，因为内核禁用了 OverlayFS！</string>\n    <string name=\"apm_changelog\">更新日志</string>\n    <string name=\"apm_uninstall_failed\">无法卸载 %s</string>\n    <string name=\"apm_downloading\">正在下载“%s”模块……</string>\n    <string name=\"apm_magisk_conflict\">模块功能不可用，因与 Magisk 存在冲突！</string>\n    <string name=\"apm_desc\">描述</string>\n    <string name=\"apm_new_version_available\">有新版本 %s 可用，单击升级。</string>\n    <string name=\"apm_update\">更新</string>\n    <string name=\"apm_author\">作者</string>\n    <string name=\"clear_super_key\">清除超级密钥</string>\n    <string name=\"apm_not_installed\">尚未注入系统补丁</string>\n    <string name=\"system_default\">系统默认</string>\n    <string name=\"settings_app_language\">语言</string>\n    <string name=\"patch\">修补内核镜像</string>\n    <string name=\"settings_global_namespace_mode_summary\">所有 Root 会话均使用全局挂载命名空间</string>\n    <string name=\"settings_global_namespace_mode\">全局命名空间模式</string>\n    <string name=\"settings_clear_super_key_dialog\">你真的确定要继续吗？</string>\n    <string name=\"kpatch_version_update\">版本：%s → %s</string>\n    <string name=\"kpatch_shadow_path_title\">内核补丁</string>\n    <string name=\"home_kpatch_info_title\">信息</string>\n    <string name=\"home_ap_cando_reboot\">重启</string>\n    <string name=\"patch_config_title\">修补内核</string>\n    <string name=\"patch_mode_bootimg_patch\">修补指定内核镜像</string>\n    <string name=\"patch_mode_patch_and_install\">修补当前槽位内核</string>\n    <string name=\"patch_select_bootimg_btn\">选择 Boot 镜像</string>\n    <string name=\"patch_start_patch_btn\">开始修补</string>\n    <string name=\"patch_item_error\">‼错误‼</string>\n    <string name=\"patch_item_bootimg\">启动镜像</string>\n    <string name=\"patch_item_bootimg_slot\">槽位：</string>\n    <string name=\"patch_item_bootimg_dev\">设备：</string>\n    <string name=\"patch_item_kernel\">内核版本</string>\n    <string name=\"patch_item_kpimg\">内核补丁</string>\n    <string name=\"patch_item_kpimg_version\">版本：</string>\n    <string name=\"patch_item_kpimg_comile_time\">时间：</string>\n    <string name=\"patch_item_kpimg_config\">配置：</string>\n    <string name=\"patch_item_new_extra_kpm\">嵌入新的</string>\n    <string name=\"patch_embed_kpm_btn\">嵌入模块</string>\n    <string name=\"patch_item_extra_name\">名称:</string>\n    <string name=\"patch_item_extra_version\">版本：</string>\n    <string name=\"patch_item_extra_author\">作者：</string>\n    <string name=\"patch_item_extra_kpm_license\">许可：</string>\n    <string name=\"patch_item_extra_kpm_desciption\">描述：</string>\n    <string name=\"patch_item_extra_args\">参数：</string>\n    <string name=\"patch_item_extra_event\">事件:</string>\n    <string name=\"patch_item_skey\">超级密钥</string>\n    <string name=\"patch_item_existed_extra_kpm\">已嵌入的</string>\n    <string name=\"patch_item_set_skey_label\">超级密钥长度应在 8-63 个字符，包含数字和字母，但不包含特殊字符。</string>\n    <string name=\"patch_mode_uninstall_patch\">还原初始内核镜像</string>\n    <string name=\"patch_start_unpatch_btn\">取消修补</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">新管理器名称</string>\n    <string name=\"hide_apatch_dialog_summary\">将使用新的名称安装管理器</string>\n    <string name=\"hide_apatch_manager_failure\">隐藏失败，请提交反馈！</string>\n    <string name=\"hide_apatch_manager_summary\">安装代理应用，安装包 ID 随机且自定义应用标签</string>\n    <string name=\"hide_apatch_manager\">隐藏 APatch 管理器</string>\n    <string name=\"kpm_embed\">嵌入</string>\n    <string name=\"kpm_add_kpm\">添加内核模块</string>\n    <string name=\"kpm_install\">安装</string>\n    <string name=\"setting_reset_su_path\">重设 SU 路径</string>\n    <string name=\"setting_reset_su_new_path\">新的完整路径</string>\n    <string name=\"success\">成功</string>\n    <string name=\"failure\">失败</string>\n    <string name=\"mode_select_page_title\">安装</string>\n    <string name=\"mode_select_page_patch_and_install\">直接安装（通常选择此项）</string>\n    <string name=\"mode_select_page_select_file\">选取要修补的启动映像文件</string>\n    <string name=\"mode_select_page_install_inactive_slot\">修补另一槽位内核（用于 OTA 之后）</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">将在重启后强制切换到另一个槽位！\n\\n注意只能在 OTA 更新完成后的重启之前使用。\n\\n确定要继续吗？</string>\n    <string name=\"home_dialog_auth_fail_title\">超级密钥鉴权失败</string>\n    <string name=\"home_dialog_auth_fail_content\">超级密钥验证失败，因此 APatch 不能正常工作。\\n下面是一些可能的原因： \\n⒈ 未使用 KernelPatch 修补内核镜像 \\n⒉ KernelPatch 修补后的内核镜像未刷入 \\n⒊超级密钥输入错误或包含特殊字符\\n⒋设备不支持 APatch 以及 KernelPatch \\n\\n请检查后重试，如果问题仍然存在，可随时前往 GitHub 仓库的 issues 页面提问。</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">反馈或建议</string>\n    <string name=\"home_more_menu_about\">关于</string>\n    <string name=\"settings_check_update\">检查更新</string>\n    <string name=\"patch_mode_install_to_next_slot\">修补另一槽位内核</string>\n    <string name=\"apm_webui_open\">打开</string>\n    <string name=\"enable_web_debugging\">启用 WebView 调试</string>\n    <string name=\"home_new_apatch_found\">发现新版本：%s，单击升级。</string>\n    <string name=\"settings_check_update_summary\">应用启动时自动检测更新</string>\n    <string name=\"enable_web_debugging_summary\">可用于调试 WebUI，请仅在需要时启用。</string>\n    <string name=\"settings_donot_store_superkey\">不存储超级密钥</string>\n    <string name=\"settings_donot_store_superkey_summary\">每次打开管理器时验证超级密钥</string>\n    <string name=\"home_device_info\">设备</string>\n    <string name=\"home_system_version\">系统版本</string>\n    <string name=\"home_kpatch_version\">KernelPatch 版本</string>\n    <string name=\"home_dialog_uninstall_title\">卸载</string>\n    <string name=\"home_dialog_uninstall_ap_only\">仅卸载系统补丁</string>\n    <string name=\"home_dialog_uninstall_all\">完全卸载</string>\n    <string name=\"kpm_control_dialog_title\">调节内核模块</string>\n    <string name=\"kpm_control_dialog_content\">请输入调控参数：</string>\n    <string name=\"kpm_control_paramters\">控制参数</string>\n    <string name=\"kpm_control_outMsg\">输出信息</string>\n    <string name=\"kpm_control_ok\">操作成功！</string>\n    <string name=\"kpm_control_failed\">操作失败！</string>\n    <string name=\"settings_night_mode_follow_sys\">深色模式跟随系统</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">根据系统的深色模式自动切换</string>\n    <string name=\"settings_night_theme_enabled\">深色主题</string>\n    <string name=\"settings_use_system_color_theme\">系统颜色主题</string>\n    <string name=\"settings_use_system_color_theme_summary\">使用由系统由壁纸取色生成的主题</string>\n    <string name=\"settings_custom_color_theme\">颜色主题</string>\n    <string name=\"amber_theme\">琥珀色主题</string>\n    <string name=\"blue_theme\">蓝色主题</string>\n    <string name=\"blue_grey_theme\">蓝灰色主题</string>\n    <string name=\"brown_theme\">棕色主题</string>\n    <string name=\"cyan_theme\">青蓝色主题</string>\n    <string name=\"deep_orange_theme\">深橙色主题</string>\n    <string name=\"deep_purple_theme\">深紫色主题</string>\n    <string name=\"green_theme\">绿色主题</string>\n    <string name=\"indigo_theme\">靛蓝色主题</string>\n    <string name=\"light_blue_theme\">浅蓝色主题</string>\n    <string name=\"light_green_theme\">浅绿色主题</string>\n    <string name=\"lime_theme\">柠檬色主题</string>\n    <string name=\"orange_theme\">橙色主题</string>\n    <string name=\"pink_theme\">粉红色主题</string>\n    <string name=\"purple_theme\">紫色主题</string>\n    <string name=\"red_theme\">红色主题</string>\n    <string name=\"sakura_theme\">樱花色主题</string>\n    <string name=\"teal_theme\">青绿色主题</string>\n    <string name=\"yellow_theme\">黄色主题</string>\n    <string name=\"about_app_version\">版本 %1$s</string>\n    <string name=\"about_app_desc\">内核级 ROOT 解决方案且无需重新编译内核，同时提供挂载系统模块和 Hook 内核函数的能力。</string>\n    <string name=\"about_github\" translatable=\"false\">GitHub</string>\n    <string name=\"about_weblate\" translatable=\"false\">Weblate</string>\n    <string name=\"about_telegram_channel\">Telegram 频道</string>\n    <string name=\"about_telegram_group\">Telegram 群组</string>\n    <string name=\"about_powered_by\">由 %1$s 强力驱动</string>\n    <string name=\"apm_action\">执行</string>\n    <string name=\"crash_handle_title\">应用崩溃了…</string>\n    <string name=\"crash_handle_copy\">复制崩溃日志</string>\n    <string name=\"crash_handle_copied\">崩溃日志已复制到剪贴板。</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\" translatable=\"false\">APatch</string>\n    <string name=\"android_patch\">Android 修補</string>\n    <string name=\"patch_warnning\">安裝過程存在風險。請確保你的資料已備份。</string>\n    <string name=\"reboot_download\">重新啟動至 Download</string>\n    <string name=\"reboot_edl\">重新啟動至 EDL</string>\n    <string name=\"reboot_recovery\">重新啟動至 Recovery</string>\n    <string name=\"kernel_patch\">核心修補</string>\n    <string name=\"about\">關於</string>\n    <string name=\"reboot\">重新啟動</string>\n    <string name=\"home\">首頁</string>\n    <string name=\"settings\">設定</string>\n    <string name=\"reboot_bootloader\">重新啟動至 Bootloader</string>\n    <string name=\"apm_reboot_to_apply\">重新啟動以應用變更</string>\n    <string name=\"kpm_unload_confirm\">確定要刪除「%s」模組嗎？</string>\n    <string name=\"apm_uninstall_success\">已解除安裝 %s</string>\n    <string name=\"apm_install\">安裝</string>\n    <string name=\"kpatch_version\">版本：%s</string>\n    <string name=\"apm_remove\">解除安裝</string>\n    <string name=\"kpm_kp_not_installed\">KernelPatch 尚未安裝</string>\n    <string name=\"home_install_unknown\">未安裝或未鑒權</string>\n    <string name=\"apm_uninstall_confirm\">確定要解除安裝「%s」模組？</string>\n    <string name=\"su_pkg_excluded_setting_title\">排除修改</string>\n    <string name=\"home_click_to_learn_apatch\">學習有關 APatch 的功能及使用方式</string>\n    <string name=\"apm_version\">版本</string>\n    <string name=\"su_pkg_excluded_setting_summary\">啟用此選項將允許 APatch 還原此應用程式被模組修改的任何檔案。</string>\n    <string name=\"home_installing\">安裝中</string>\n    <string name=\"apm_start_downloading\">開始下載 %s</string>\n    <string name=\"su_pkg_excluded_label\">忽略</string>\n    <string name=\"su_title\">超級使用者</string>\n    <string name=\"kpm_desc\">說明</string>\n    <string name=\"su_selinux_via_hook\">透過 Hook 忽略請求的方式</string>\n    <string name=\"home_ap_cando_uninstall\">解除安裝</string>\n    <string name=\"kpm_args\">引數</string>\n    <string name=\"home_fingerprint\">指紋</string>\n    <string name=\"apatch_version\">版本：%s</string>\n    <string name=\"apm_overlay_fs_not_available\">裝置核心停用了 OverlayFS，你無法使用模組功能!</string>\n    <string name=\"kpm_version\">版本</string>\n    <string name=\"su_refresh\">重新整理</string>\n    <string name=\"su_show_system_apps\">顯示系統應用程式</string>\n    <string name=\"home_ap_cando_install\">安裝</string>\n    <string name=\"home_learn_apatch\">深入瞭解 APatch</string>\n    <string name=\"apm_failed_to_disable\">無法停用「%s」模組</string>\n    <string name=\"home_click_to_install\">點擊以開始安裝</string>\n    <string name=\"home_selinux_status_unknown\">未知</string>\n    <string name=\"home_selinux_status_permissive\">允許執行</string>\n    <string name=\"home_need_update\">已有新版本可供使用</string>\n    <string name=\"home_selinux_status\">SELinux 狀態</string>\n    <string name=\"apm_changelog\">《更新紀錄》</string>\n    <string name=\"apm_uninstall_failed\">無法解除安裝 %s</string>\n    <string name=\"kpm_author\">作者</string>\n    <string name=\"apm_failed_to_enable\">無法啟用「%s」模組</string>\n    <string name=\"apm_downloading\">正在下載「%s」模組……</string>\n    <string name=\"su_hide_system_apps\">隱藏系統應用程式</string>\n    <string name=\"apm_magisk_conflict\">與 Magisk 發生衝突，你無法使用模組功能!</string>\n    <string name=\"apm_desc\">說明</string>\n    <string name=\"home_ap_cando_update\">更新</string>\n    <string name=\"kpm_load_toast_failed\">匯入失敗</string>\n    <string name=\"kpm_unload\">刪除</string>\n    <string name=\"home_selinux_status_disabled\">關閉</string>\n    <string name=\"apm_new_version_available\">點擊以安裝新版本的 %s。</string>\n    <string name=\"apatch_version_update\">版本：%s → %s</string>\n    <string name=\"home_working\">運作中 😋</string>\n    <string name=\"apm_empty\">尚未安裝模組</string>\n    <string name=\"kpm_load\">匯入</string>\n    <string name=\"apm_update\">更新</string>\n    <string name=\"home_kernel\">核心版本</string>\n    <string name=\"home_selinux_status_enforcing\">強制執行</string>\n    <string name=\"kpm_license\">授權</string>\n    <string name=\"kpm_apm_empty\">尚無已匯入的模組</string>\n    <string name=\"home_manager_version\">管理器版本</string>\n    <string name=\"kpm_load_toast_succ\">匯入成功</string>\n    <string name=\"apm_author\">作者</string>\n    <string name=\"patch_title\">修補</string>\n    <string name=\"send_log\">發送日誌</string>\n    <string name=\"home_auth_key_desc\">認證通過後開始執行</string>\n    <string name=\"home_patch_set_key_desc\">執行 KernelPatch 時所需的唯一憑證</string>\n    <string name=\"apm\">AP模組</string>\n    <string name=\"safe_mode\">安全模式</string>\n    <string name=\"super_key\">超級密鑰</string>\n    <string name=\"home_apatch_version\">APatch 版本</string>\n    <string name=\"patch_set_superkey\">設定超級密鑰</string>\n    <string name=\"home_su_path\">可執行 SU 路徑</string>\n    <string name=\"home_patch_next_step\">下一步</string>\n    <string name=\"home_auth_key_title\">輸入超級密鑰</string>\n    <string name=\"home_not_installed\">尚未安裝</string>\n    <string name=\"kpm\">KP模組</string>\n    <string name=\"about_source_code\"><![CDATA[<p>在%1$s<p/> 查看原始碼加入我們的 %2$s 頻道<p/>加入我們的 %3$s 群組]]></string>\n    <string name=\"clear_super_key\">清除超級密鑰</string>\n    <string name=\"apm_not_installed\">AndroidPatch 尚未安裝</string>\n    <string name=\"system_default\">系統預設</string>\n    <string name=\"settings_app_language\">語言</string>\n    <string name=\"patch\">修補</string>\n    <string name=\"settings_global_namespace_mode_summary\">所有 Root 工作階段將會全域掛載命名空間</string>\n    <string name=\"settings_global_namespace_mode\">全域命名空間模式</string>\n    <string name=\"settings_clear_super_key_dialog\">你確定要繼續嗎？</string>\n    <string name=\"kpatch_version_update\">版本：%s -&gt; %s</string>\n    <string name=\"kpatch_shadow_path_title\">kpatch</string>\n    <string name=\"home_kpatch_info_title\">資訊</string>\n    <string name=\"home_ap_cando_reboot\">重新啟動</string>\n    <string name=\"patch_config_title\">補丁</string>\n    <string name=\"patch_mode_patch_and_install\">模式：更新</string>\n    <string name=\"patch_select_bootimg_btn\">選擇 Boot 镜像</string>\n    <string name=\"patch_embed_kpm_btn\">嵌入核心模組</string>\n    <string name=\"patch_start_patch_btn\">開始</string>\n    <string name=\"patch_item_error\">！！錯誤！！</string>\n    <string name=\"patch_item_bootimg\">Boot 鏡像</string>\n    <string name=\"patch_item_bootimg_slot\">插槽：</string>\n    <string name=\"patch_item_bootimg_dev\">裝置:</string>\n    <string name=\"patch_item_kernel\">核心</string>\n    <string name=\"patch_item_kpimg\">kpimg</string>\n    <string name=\"patch_item_new_extra_kpm\">嵌入新的</string>\n    <string name=\"patch_item_existed_extra_kpm\">已嵌入</string>\n    <string name=\"patch_item_extra_name\">名稱：</string>\n    <string name=\"patch_item_extra_version\">版本：</string>\n    <string name=\"patch_item_extra_author\">作者：</string>\n    <string name=\"patch_item_extra_kpm_license\">授權：</string>\n    <string name=\"patch_item_extra_kpm_desciption\">描述：</string>\n    <string name=\"patch_item_extra_event\">事件：</string>\n    <string name=\"patch_item_skey\">超級密鑰</string>\n    <string name=\"patch_item_set_skey_label\">超級密鑰至少需要８個字符，並且同時包含數字和字母。</string>\n    <string name=\"patch_item_extra_args\">參數：</string>\n    <string name=\"patch_mode_uninstall_patch\">模式：撤銷補丁</string>\n    <string name=\"patch_mode_bootimg_patch\">模式：修補</string>\n    <string name=\"patch_start_unpatch_btn\">取消修補</string>\n    <string name=\"patch_item_kpimg_version\">版本：</string>\n    <string name=\"patch_item_kpimg_comile_time\">時間：</string>\n    <string name=\"patch_item_kpimg_config\">設定：</string>\n    <string name=\"hide_apatch_manager\">隱藏 APatch 管理器</string>\n    <string name=\"hide_apatch_dialog_new_manager_name\">新管理器名稱</string>\n    <string name=\"hide_apatch_dialog_summary\">它將用作啟動器中顯示的新應用程式標籤</string>\n    <string name=\"hide_apatch_manager_summary\">使用隨機套件 ID 和自訂應用程式標籤安裝新的代理應用程式</string>\n    <string name=\"hide_apatch_manager_failure\">隱藏失敗，請回報bug！</string>\n    <string name=\"kpm_embed\">嵌入</string>\n    <string name=\"kpm_add_kpm\">新增 KPM</string>\n    <string name=\"kpm_install\">安裝</string>\n    <string name=\"setting_reset_su_path\">重置 su 路徑</string>\n    <string name=\"setting_reset_su_new_path\">新的完整路徑</string>\n    <string name=\"success\">成功</string>\n    <string name=\"failure\">失敗</string>\n    <string name=\"settings_check_update\">檢查更新</string>\n    <string name=\"mode_select_page_patch_and_install\">修補並安裝</string>\n    <string name=\"mode_select_page_install_inactive_slot\">安裝到非活動插槽（OTA 之後）</string>\n    <string name=\"mode_select_page_select_file\">選擇要修補的「boot image」</string>\n    <string name=\"home_dialog_auth_fail_title\">鑒權失敗</string>\n    <string name=\"enable_web_debugging\">啟用 WebView 偵錯</string>\n    <string name=\"home_more_menu_feedback_or_suggestion\">回饋或建議</string>\n    <string name=\"home_more_menu_about\">關於</string>\n    <string name=\"mode_select_page_install_inactive_slot_warning\">重新啟動後，您的裝置將**強制**啟動到目前非活動插槽！\n\\n僅在 OTA 完成之後使用此選項。\n\\n繼續？</string>\n    <string name=\"settings_check_update_summary\">開啟應用程式時自動檢查更新</string>\n    <string name=\"apm_webui_open\">打開網頁介面</string>\n    <string name=\"enable_web_debugging_summary\">可用於偵錯WebUI，請僅在需要時啟用。</string>\n    <string name=\"settings_donot_store_superkey\">停用本機儲存密鑰</string>\n    <string name=\"home_dialog_auth_fail_content\">無法驗證超級密鑰，因此 APatch 無法正常運作。 \\n以下是驗證失敗的一些可能原因： \\n1. 您尚未使用 KernelPatch 程式修補啟動映像檔。 \\n2. 修補後的啟動映像檔未刷入裝置。 \\n3. 超級密鑰錯誤。 \\n4. 您的裝置不支援 APatch 和 KernelPatch。 \\n \\n請檢查並再次嘗試。如果仍存在問題，您隨時可以在官方存放庫的議題頁面上提問。</string>\n    <string name=\"home_install_unknown_summary\">點擊以安裝</string>\n    <string name=\"home_device_info\">裝置</string>\n    <string name=\"home_new_apatch_found\">新版本可用：%s，點選升級。</string>\n    <string name=\"mode_select_page_title\">安裝</string>\n    <string name=\"home_dialog_uninstall_title\">解除安裝</string>\n    <string name=\"home_dialog_uninstall_ap_only\">僅刪除 AndroidPatch</string>\n    <string name=\"home_dialog_uninstall_all\">完全卸載</string>\n    <string name=\"home_system_version\">系統版本</string>\n    <string name=\"home_kpatch_version\">KernelPatch 版本</string>\n    <string name=\"settings_donot_store_superkey_summary\">每次管理器啟動時驗證超級密鑰</string>\n    <string name=\"patch_mode_install_to_next_slot\">模式：安裝到另一個插槽（OTA之後）</string>\n    <string name=\"kpm_control\">控制</string>\n    <string name=\"about_telegram_group\">Telegram 群組</string>\n    <string name=\"about_powered_by\">由 %1$s 提供支援</string>\n    <string name=\"kpm_control_dialog_content\">輸入控制參數：</string>\n    <string name=\"settings_night_theme_enabled\">啟用深色主題</string>\n    <string name=\"settings_use_system_color_theme_summary\">使用由系統根據月前桌布生成的顏色主題</string>\n    <string name=\"deep_purple_theme\">深紫色主題</string>\n    <string name=\"light_blue_theme\">淺藍色主題</string>\n    <string name=\"indigo_theme\">靛藍色主題</string>\n    <string name=\"about_app_desc\">核心級 ROOT 解決方案，無需重新編譯核心映像，同時提供掛載系統模組和掛鉤核心功能的能力。</string>\n    <string name=\"kpm_control_failed\">操作失敗！</string>\n    <string name=\"cyan_theme\">青色主題</string>\n    <string name=\"kpm_control_paramters\">參數</string>\n    <string name=\"kpm_control_outMsg\">訊息</string>\n    <string name=\"kpm_control_ok\">操作成功！</string>\n    <string name=\"settings_night_mode_follow_sys\">遵循系統的深色主題</string>\n    <string name=\"settings_night_mode_follow_sys_summary\">根據系統設定自動切換為深色主題</string>\n    <string name=\"settings_use_system_color_theme\">系統顏色主題</string>\n    <string name=\"settings_custom_color_theme\">顏色主題</string>\n    <string name=\"amber_theme\">琥珀色主題</string>\n    <string name=\"blue_grey_theme\">藍灰色主題</string>\n    <string name=\"brown_theme\">棕色主題</string>\n    <string name=\"deep_orange_theme\">深橙色主題</string>\n    <string name=\"green_theme\">綠色主題</string>\n    <string name=\"light_green_theme\">淺綠色主題</string>\n    <string name=\"lime_theme\">檸檬色主題</string>\n    <string name=\"orange_theme\">橙色主題</string>\n    <string name=\"pink_theme\">粉紅色主題</string>\n    <string name=\"purple_theme\">紫色主題</string>\n    <string name=\"red_theme\">紅色主題</string>\n    <string name=\"sakura_theme\">櫻花色主題</string>\n    <string name=\"teal_theme\">青綠色主題</string>\n    <string name=\"about_app_version\">版本 %1$s</string>\n    <string name=\"about_telegram_channel\">Telegram 頻道</string>\n    <string name=\"blue_theme\">藍色主題</string>\n    <string name=\"yellow_theme\">黃色主題</string>\n    <string name=\"kpm_control_dialog_title\">控制 KPModule</string>\n    <string name=\"save_log\">儲存日誌</string>\n    <string name=\"log_saved\">日誌已儲存</string>\n    <string name=\"crash_handle_title\">應用程式崩潰..</string>\n    <string name=\"crash_handle_copy\">複製崩潰日誌</string>\n    <string name=\"apm_action\">執行</string>\n    <string name=\"crash_handle_copied\">已將崩潰日誌複製到剪貼簿。</string>\n    <string name=\"settings_force_overlayfs_mode\">強制使用 OverlayFS</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/xml/backup_rules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n   Sample backup rules file; uncomment and customize as necessary.\n   See https://developer.android.com/guide/topics/data/autobackup\n   for details.\n   Note: This file is ignored for devices older that API 31\n   See https://developer.android.com/about/versions/12/backup-restore\n-->\n<full-backup-content>\n    <!--\n   <include domain=\"sharedpref\" path=\".\"/>\n   <exclude domain=\"sharedpref\" path=\"device.xml\"/>\n-->\n</full-backup-content>"
  },
  {
    "path": "app/src/main/res/xml/data_extraction_rules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n   Sample data extraction rules file; uncomment and customize as necessary.\n   See https://developer.android.com/about/versions/12/backup-restore#xml-changes\n   for details.\n-->\n<data-extraction-rules>\n    <cloud-backup>\n        <!-- TODO: Use <include> and <exclude> to control what is backed up.\n        <include .../>\n        <exclude .../>\n        -->\n    </cloud-backup>\n    <!--\n    <device-transfer>\n        <include .../>\n        <exclude .../>\n    </device-transfer>\n    -->\n</data-extraction-rules>"
  },
  {
    "path": "app/src/main/res/xml/file_paths.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<paths>\n    <cache-path name=\"cache\" path=\".\"/>\n    <root-path name=\"root\" path=\".\" />\n</paths>"
  },
  {
    "path": "app/src/main/res/xml/network_security_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<network-security-config>\n    <domain-config cleartextTrafficPermitted=\"true\">\n        <domain includeSubdomains=\"true\">127.0.0.1</domain>\n        <domain includeSubdomains=\"true\">0.0.0.0</domain>\n        <domain includeSubdomains=\"true\">::1</domain>\n    </domain-config>\n</network-security-config>"
  },
  {
    "path": "build.gradle.kts",
    "content": "plugins {\n    alias(libs.plugins.agp.app) apply false\n    alias(libs.plugins.kotlin) apply false\n    alias(libs.plugins.kotlin.compose.compiler) apply false\n}\n\nproject.ext.set(\"kernelPatchVersion\", \"0.13.0\")\n\nval androidMinSdkVersion by extra(26)\nval androidTargetSdkVersion by extra(36)\nval androidCompileSdkVersion by extra(36)\nval androidBuildToolsVersion by extra(\"36.1.0\")\nval androidCompileNdkVersion by extra(\"29.0.14206865\")\nval managerVersionCode by extra(getVersionCode())\nval managerVersionName by extra(getVersionName())\nval branchName by extra(getBranch())\nfun Project.exec(command: String) = providers.exec {\n    commandLine(command.split(\" \"))\n}.standardOutput.asText.get().trim()\n\nfun getGitCommitCount(): Int {\n    return exec(\"git rev-list --count HEAD\").trim().toInt()\n}\n\nfun getGitDescribe(): String {\n    return exec(\"git rev-parse --verify --short HEAD\").trim()\n}\n\nfun getVersionCode(): Int {\n    val commitCount = getGitCommitCount()\n    val major = 1\n    return major * 10000 + commitCount + 200\n}\n\nfun getBranch(): String {\n    return exec(\"git rev-parse --abbrev-ref HEAD\").trim()\n}\n\nfun getVersionName(): String {\n    return getGitDescribe()\n}\n\ntasks.register(\"printVersion\") {\n    doLast {\n        println(\"Version code: $managerVersionCode\")\n        println(\"Version name: $managerVersionName\")\n    }\n}\n"
  },
  {
    "path": "docs/BG/faq_bg.md",
    "content": "# ЧЗВ\n\n\n## Какво е APatch?\n\nAPatch е root решение, подобно на Magisk или KernelSU, което обединява най-доброто от двете.\nКомбинира удобния и лесен метод за инсталиране на Magisk чрез boot.img с мощните възможности за пачване на ядрото на KernelSU.\n\n## Каква е разликата между APatch и Magisk?\n\nMagisk модифицира init системата с пач в ramdisk-а на boot image-а, докато APatch пачва директно ядрото.\n\n\n## APatch срещу KernelSU\n\nKernelSU изисква изходния код на ядрото на устройството, който не винаги се предоставя от производителя. APatch работи само със стандартния boot.img.\n\n\n## APatch срещу Magisk, KernelSU\n\nAPatch позволява по избор да не се модифицира SELinux, което означава, че нишката на приложението може да бъде root-ната, без да е необходимо libsu и IPC.\n\nKernel Patch Module е включен.\n\n\n## Какво е Kernel Patch Module?\n\nНякой код се изпълнява в Kernel Space, подобно на Loadable Kernel Modules (LKM).\n\nОсвен това, KPM позволява inline-hook и syscall-table-hook в kernel space.\n\nЗа повече информация виж Как да напишем KPM\n\n## Връзка между APatch и KernelPatch\n\nAPatch зависи от KernelPatch, наследява всичките му възможности и е разширен.\n\nМожеш да инсталираш само KernelPatch, но това няма да ти позволи да използваш Magisk модули.\n\nНаучи повече за KernelPatch\n\n## Какво е SuperKey?\n\nKernelPatch добавя нов системен повик (syscall), който предоставя всички възможности на приложенията и програмите в потребителското пространство. Този syscall се нарича SuperCall.\nКогато приложение/програма се опита да извика SuperCall, трябва да предостави идентификационен ключ, наречен SuperKey.\nSuperCall може да бъде извикан успешно само ако SuperKey е правилен. Ако не е, извикващият остава незасегнат.\n\n## А какво става със SELinux?\n\nKernelPatch не модифицира SELinux контекста и го заобикаля чрез hook.\nТова позволява root достъп до нишка на Android в контекста на самото приложение, без да е необходимо да се използва libsu за стартиране на нов процес и IPC.\nТова е много удобно.\n\nОсвен това, APatch използва директно magiskpolicy за допълнителна поддръжка на SELinux.\n\n\n"
  },
  {
    "path": "docs/ar/faq_ar.md",
    "content": "# الأسئلة الشائعة (FAQ)\n\n## ما هو أباتش؟\nأباتش هو حل روت شبيه بـ ماجيسك أو كيرنل إس يو، يجمع بين أفضل ما في كليهما.  \nيستخدم طريقة التثبيت السهلة الخاصة بـ ماجيسك من خلال `boot.img`، مع قدرات تعديل النواة القوية التي يوفرها كيرنل إس يو.\n\n## ما الفرق بين أباتش وماجيسك؟\n- ماجيسك يقوم بتعديل نظام init عبر تعديل في ramdisk الخاص بملف boot image، بينما أباتش يقوم بتعديل النواة مباشرة.\n\n## أباتش مقابل كيرنل إس يو\n- كيرنل إس يو يحتاج إلى الكود المصدري للنواة الخاصة بجهازك، والذي لا توفره الشركات دائمًا.  \n  أما أباتش فيعمل فقط باستخدام ملف `boot.img` الأصلي.\n\n## أباتش مقابل ماجيسك وكيرنل إس يو\n- يسمح لك أباتش بعدم تعديل SELinux اختياريًا، مما يعني أن خيوط التطبيق (APP thread) يمكن أن تحصل على صلاحيات الروت، دون الحاجة إلى libsu أو IPC.\n- **وحدة تعديل النواة (Kernel Patch Module)** متوفرة.\n\n## ما هي وحدة تعديل النواة (Kernel Patch Module)؟\nبعض الشيفرات تعمل ضمن مساحة النواة، مشابهة لـ LKM (وحدات نواة قابلة للتحميل).  \nبالإضافة إلى ذلك، توفر KPM القدرة على تنفيذ inline-hook و syscall-table-hook ضمن مساحة النواة.\n\nلمزيد من المعلومات، راجع [كيفية كتابة KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)\n\n## العلاقة بين أباتش وKernelPatch\nيعتمد أباتش على KernelPatch، ويرث جميع قدراته، وتم توسيعه ليشمل ميزات إضافية.  \nيمكنك تثبيت KernelPatch فقط، لكنك لن تستطيع استخدام وحدات ماجيسك معه.\n\n[تعرف أكثر على KernelPatch](https://github.com/bmax121/KernelPatch)\n\n## ما هو SuperKey؟\nيضيف KernelPatch نداء نظامي (syscall) جديد يمنح كافة الصلاحيات للتطبيقات والبرامج في مساحة المستخدم (userspace)، وهذا النداء يسمى **SuperCall**.  \nعندما يحاول تطبيق أو برنامج استدعاء **SuperCall**، يجب أن يقدم بيانات اعتماد وصول تُعرف باسم **SuperKey**.  \nيتم تنفيذ **SuperCall** بنجاح فقط إذا كانت **SuperKey** صحيحة، وإن لم تكن كذلك فلن يتأثر المستدعي.\n\n## ماذا عن SELinux؟\n- لا يقوم KernelPatch بتعديل سياق SELinux، بل يتجاوزه من خلال hook.  \n  هذا يسمح بعمل روت لخيط (thread) داخل التطبيق دون الحاجة لاستخدام libsu لبدء عملية جديدة ثم إجراء IPC، مما يجعله مريحًا جدًا.\n- بالإضافة إلى ذلك، يستخدم أباتش أداة magiskpolicy مباشرة لتوفير دعم إضافي لـ SELinux.\n"
  },
  {
    "path": "docs/az/faq_az.md",
    "content": "# TSS\n\n\n## APatch nədir?\nAPatch, hər ikisinin ən yaxşısını birləşdirən Magisk və ya KernelSU-ya bənzər kök həllidir.\nO, Magisk-in `boot.img` vasitəsilə rahat və asan quraşdırma metodunu KernelSU-nun güclü nüvə yamaqlamaq qabiliyyətləri ilə birləşdirir.\n\n\n## APatch və Magisk arasındakı fərq nədir?\n- Magisk başlanğıc sistemini nüvə imajınızın ramdiskindəki yamaq ilə dəyişdirir, APatch isə nüvəni birbaşa yamaqlayır.\n\n\n## APatch vs KernelSU\n- KernelSU cihazınızın nüvəsi üçün həmişə OEM tərəfindən təmin edilməyən mənbə kodunu tələb edir. APAtch yalnız sizin stok `boot.img` ilə işləyir.\n\n\n## APatch vs Magisk, KernelSU\n- APatch istəyə bağlı olaraq SELinux-u dəyişdirməməyə imkan verir, bu o deməkdir ki, Android proqramı köklənə bilər, libsu və IPC zəruri deyil.\n- **Nüvə Yamaq Modulu** təmin edilmişdir.\n\n\n## Nüvə Yamaq Modulu nədir?\nBəzi kodlar Yüklənəbilən Nüvə Modulları (LKM) kimi Nüvə Məkanında işləyir.\n\nƏlavə olaraq, KPM nüvə məkanında daxili-çəngəl, sistem-zəngi-cədvəli-çəngəlləri etmək imkanı verir.\n\nƏtraflı məlumat üçün [KPM necə yazılır](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md) bölməsinə baxın.\n\n\n## APatch və NüvəYamağı arasındakı əlaqə\n\nAPatch NüvəYamağından asılıdır, onun bütün imkanlarını miras alır və genişləndirilib.\n\nSiz yalnızca NüvəYamağı quraşdıra bilərsiniz, lakin bu, Magisk modullarından istifadə etməyə imkan verməyəcək və superistifadəçi idarəçiliyindən istifadə etmək üçün AndroidYamağını quraşdırmalı və sonra onu silməlisiniz.\n\n[NüvəYamağı haqqında ətraflı öyrənin](https://github.com/bmax121/KernelPatch)\n\n\n## SuperAçar nədir?\nNüvəYamağı istifadəçi məkanındakı tətbiq və proqramlara bütün imkanları təmin etmək üçün yeni sistem zəngi (syscall) əlavə edir, bu sistem zəngi **SuperZəng** adlanır.\nTətbiq/proqram **SuperZəngi** işə salmağa çalışdıqda, o, **SuperAçar** kimi tanınan giriş etimadnaməsini təmin etməlidir.\n**SuperZəng** yalnız **SuperAçar** düzgün olduqda uğurla işə salına bilər və bu deyilsə, zəng edən şəxs təsirsiz qalacaq.\n\n\n## SELinux bəs?\n- NüvəYamağı SELinux kontekstini dəyişdirmir və çəngəl vasitəsilə SELinux-dan yan keçir.\n  Bu, yeni prosesə başlamaq və sonra IPC yerinə yetirmək üçün libsu-dan istifadə etmədən proqram kontekstində Android mövzusunu kökləməyə imkan verir.\n  Bu çox rahatdır.\n- Bundan əlavə, APatch əlavə SELinux dəstəyi təmin etmək üçün birbaşa magiskpolicy-dən istifadə edir.\n"
  },
  {
    "path": "docs/cn/ap_module.md",
    "content": "# 模块(APM)开发指南 {#introduction}\n\nAPatch 提供了一个模块机制（ AndroidPatch Module），它可以在保持系统分区完整性的同时达到修改系统分区的效果；这种机制通常被称之为 systemless。\n\nAPatch 的模块实现是从 [KernelSU](https://github.com/tiann/KernelSU) 模块复制并修改而来，感谢 KernelSU。  \n具体修改的代码对应位置：  \nKernelSU: [https://github.com/tiann/KernelSU/tree/main/userspace/ksud](https://github.com/tiann/KernelSU/tree/main/userspace/ksud)  \nAPatch: [https://github.com/bmax121/APatch/tree/main/apd](https://github.com/bmax121/APatch/tree/main/apd)\n\n以下的文档内容也是从 KernelSU 的文档复制并修改而来，其中大部分的内容是一致。需要注意的主要有以下几个地方\n\n1. 文件位置\n2. 环境变量\n3. SELinux 支持，APatch 直接使用了 magiskpolicy\n\nAPatch 的模块运作机制与 Magisk 几乎是一样的，如果你熟悉 Magisk 模块的开发，那么开发 APatch 的模块大同小异，你可以跳过下面有关模块的介绍，只需要了解 [APatch 模块与 Magisk 模块的异同](difference-with-magisk.md)。\n\n<!-- ## 模块界面\n\nAPatch 的模块支持显示界面并与用户交互，请参阅 [WebUI 文档](module-webui.md)。 -->\n\n## Busybox\n\nAPatch 提供了一个功能完备的 BusyBox 二进制文件（包括完整的SELinux支持）。可执行文件位于 `/data/adb/ap/bin/busybox`。\nAPatch 的 BusyBox 支持运行时可切换的 \"ASH Standalone Shell Mode\"。\n这种独立模式意味着在运行 BusyBox 的 ash shell 时，每个命令都会直接使用 BusyBox 中内置的应用程序，而不管 PATH 设置为什么。\n例如，`ls`、`rm`、`chmod` 等命令将不会使用 PATH 中设置的命令（在Android的情况下，默认情况下分别为 `/system/bin/ls`、`/system/bin/rm` 和 `/system/bin/chmod`），而是直接调用 BusyBox 内置的应用程序。\n这确保了脚本始终在可预测的环境中运行，并始终具有完整的命令套件，无论它运行在哪个Android版本上。\n要强制一个命令不使用BusyBox，你必须使用完整路径调用可执行文件。\n\n在 APatch 上下文中运行的每个 shell 脚本都将在 BusyBox 的 ash shell 中以独立模式运行。对于第三方开发者相关的内容，包括所有启动脚本和模块安装脚本。\n\n对于想要在 APatch 之外使用这个“独立模式”功能的用户，有两种启用方法:\n\n1. 设置环境变量 `ASH_STANDALONE` 为 `1`。例如：`ASH_STANDALONE=1 /data/adb/ap/bin/busybox sh <script>`\n2. 使用命令行选项切换：`/data/adb/ap/bin/busybox sh -o standalone <script>`\n\n为了确保所有后续的 `sh` shell 都在独立模式下执行，第一种是首选方法（这也是 APatch 和 APatch 管理器内部使用的方法），因为环境变量会被继承到子进程中。\n\n::: tip 与 KernelSU 的差异\n\nbusybox 的位置由 /data/adb/ksu/bin/busybox 改到了 /data/adb/ap/bin/busybox\n:::\n\n::: tip 与 Magisk 的差异\n\nAPatch 的 BusyBox 现在是直接使用 Magisk 项目编译的二进制文件，**感谢 Magisk！**\n因此，你完全不用担心 BusyBox 脚本与在 Magisk 和 APatch 之间的兼容问题，因为他们是完全一样的！\n:::\n\n## APatch 模块 {#APatch-modules}\n\nAPatch 模块就是一个放置在 `/data/adb/modules` 内且满足如下结构的文件夹：\n\n```txt\n/data/adb/modules\n├── .\n├── .\n|\n├── $MODID                  <--- 模块的文件夹名称与模块 ID 相同\n│   │\n│   │      *** 模块配置文件 ***\n│   │\n│   ├── module.prop         <--- 此文件保存模块相关的一些配置，如模块 ID、版本等\n│   │\n│   │      *** 模块内容 ***\n│   │\n│   ├── system              <--- 这个文件夹通常会被挂载到系统\n│   │   ├── ...\n│   │   ├── ...\n│   │   └── ...\n│   │\n│   │      *** 标记文件 ***\n│   │\n│   ├── skip_mount          <--- 如果这个文件存在，那么模块的 `/system` 将不会被挂载\n│   ├── disable             <--- 如果这个文件存在，那么模块会被禁用\n│   ├── remove              <--- 如果这个文件存在，下次重启的时候模块会被移除\n│   │\n│   │      *** 可选文件 ***\n│   │\n│   ├── post-fs-data.sh     <--- 这个脚本将会在 post-fs-data 模式下运行\n│   ├── post-mount.sh       <--- 这个脚本将会在 post-mount 模式下运行\n│   ├── service.sh          <--- 这个脚本将会在 late_start 服务模式下运行\n│   ├── boot-completed.sh   <--- 这个脚本将会在 Android 系统启动完毕后以服务模式运行\n|   ├── uninstall.sh        <--- 这个脚本将会在模块被卸载时运行\n|   ├── action.sh           <--- 这个脚本将会在管理器模块中点击 Action 时运行\n│   ├── system.prop         <--- 这个文件中指定的属性将会在系统启动时通过 resetprop 更改\n│   ├── sepolicy.rule       <--- 这个文件中的 SELinux 策略将会在系统启动时加载\n│   │\n│   │      *** 自动生成的目录，不要手动创建或者修改！ ***\n│   │\n│   ├── vendor              <--- A symlink to $MODID/system/vendor\n│   ├── product             <--- A symlink to $MODID/system/product\n│   ├── system_ext          <--- A symlink to $MODID/system/system_ext\n│   │\n│   │      *** Any additional files / folders are allowed ***\n│   │\n│   ├── ...\n│   └── ...\n|\n├── another_module\n│   ├── .\n│   └── .\n├── .\n├── .\n```\n\n::: tip 与 Magisk 的差异\nAPatch 没有内置的针对 Zygisk 的支持，因此模块中没有 Zygisk 相关的内容\n<!-- ，但你可以通过 [ZygiskNext](https://github.com/Dr-TSNG/ZygiskNext) 来支持 Zygisk 模块，此时 Zygisk 模块的内容与 Magisk 所支持的 Zygisk 是完全相同的。 -->\n:::\n\n### module.prop\n\nmodule.prop 是一个模块的配置文件，在 APatch 中如果模块中不包含此文件，那么它将不被认为是一个模块；此文件的格式如下：\n\n```txt\nid=<string>\nname=<string>\nversion=<string>\nversionCode=<int>\nauthor=<string>\ndescription=<string>\n```\n\n- id 必须与这个正则表达式匹配：`^[a-zA-Z][a-zA-Z0-9._-]+$` 例如：✓ `a_module`，✓ `a.module`，✓ `module-101`，✗ `a  module`，✗ `1_module`，✗ `-a-module`。这是您的模块的唯一标识符，发布后不应更改。\n- versionCode 必须是一个整数，用于比较版本。\n- 其他未在上面提到的内容可以是任何单行字符串。\n- 请确保使用 UNIX（LF）换行类型，而不是Windows（CR + LF）或 Macintosh（CR）。\n\n### Shell 脚本 {#shell-scripts}\n\n请阅读 [启动脚本](#boot-scripts) 一节，以了解 `post-fs-data.sh`, `post-mount.sh`, `service.sh` 和 `boot-completed.sh` 之间的区别。对于大多数模块开发者来说，如果您只需要运行一个启动脚本，`service.sh` 应该已经足够了。\n\n在您的模块的所有脚本中，请使用 `MODDIR=${0%/*}`来获取您的模块的基本目录路径；请勿在脚本中硬编码您的模块路径。\n\n:::tip 与 Magisk, KernelSU 的差异\n你可以通过环境变量 `APATCH` 来判断脚本是否运行在 APatch 中，如果运行在 APatch，这个值会被设置为 `true`。\n:::\n\n### `system` 目录 {#system-directories}\n\n这个目录的内容会在系统启动后，以 `overlayfs` 的方式叠加在系统的 `/system` 分区之上，这意味着：\n\n1. 系统中对应目录的同名文件会被此目录的文件覆盖。\n2. 系统中对应目录的同名文件夹会与此目录的文件夹合并。\n\n如果你想删掉系统原来目录某个文件或者文件夹，你需要在模块目录通过 `mknod filename c 0 0` 来创建一个 `filename` 的同名文件；这样 overlayfs 系统会自动 whiteout 等效删除此文件（`/system` 分区并没有被更改）。\n\n你也可以在 `customize.sh` 中声明一个名为 `REMOVE` 并且包含一系列目录的变量来执行删除操作，APatch 会自动为你在模块对应目录执行 `mknod <TARGET> c 0 0`。例如：\n\n```sh\nREMOVE=\"\n/system/app/YouTube\n/system/app/Bloatware\n\"\n```\n\n上面的这个列表将会执行： `mknod $MODPATH/system/app/YouTuBe c 0 0` 和 `mknod $MODPATH/system/app/Bloatware c 0 0`；并且 `/system/app/YouTube` 和 `/system/app/Bloatware` 将会在模块生效后被删除。\n\n如果你想替换掉系统的某个目录，你需要在模块目录创建一个相同路径的目录，然后为此目录设置此属性：`setfattr -n trusted.overlay.opaque -v y <TARGET>`；这样 overlayfs 系统会自动将系统内相应目录替换（`/system` 分区并没有被更改）。\n\n你可以在 `customize.sh` 中声明一个名为 `REPLACE` 并且包含一系列目录的变量来执行替换操作，APatch 会自动为你在模块对应目录执行相关操作。例如：\n\n```sh\nREPLACE=\"\n/system/app/YouTube\n/system/app/Bloatware\n\"\n```\n\n上面这个列表将会：自动创建目录 `$MODPATH/system/app/YouTube` 和 `$MODPATH//system/app/Bloatware`，然后执行 `setfattr -n trusted.overlay.opaque -v y $$MODPATH/system/app/YouTube` 和 `setfattr -n trusted.overlay.opaque -v y $$MODPATH/system/app/Bloatware`；并且 `/system/app/YouTube` 和 `/system/app/Bloatware` 将会在模块生效后替换为空目录。\n\n:::tip 与 Magisk 的差异\n\nAPatch 的 systemless 机制是通过内核的 overlayfs 实现的，而 Magisk 当前则是通过 magic mount (bind mount)，二者实现方式有着巨大的差异，但最终的目标实际上是一致的：不修改物理的 `/system` 分区但实现修改 `/system` 文件。\n:::\n\n如果你对 overlayfs 感兴趣，建议阅读 Linux Kernel 关于 [overlayfs 的文档](https://docs.kernel.org/filesystems/overlayfs.html)\n\n### system.prop\n\n这个文件的格式与 `build.prop` 完全相同：每一行都是 `[key]=[value]` 的形式。\n\n### sepolicy.rule\n\n如果您的模块需要一些额外的 SELinux 策略补丁，请将这些规则添加到此文件中。这个文件中的每一行都将被视为一个策略语句。\n\n## 模块安装包 {#module-installer}\n\nAPatch 的模块安装包就是一个可以通过 APatch 管理器 APP 刷入的 zip 文件，此 zip 文件的格式如下：\n\n```txt\nmodule.zip\n│\n├── customize.sh                       <--- (Optional, more details later)\n│                                           This script will be sourced by update-binary\n├── ...\n├── ...  /* 其他模块文件 */\n│\n```\n\n:::warning\nAPatch 模块不支持在 Recovery 中安装！！\n:::\n\n### 定制安装过程 {#customizing-installation}\n\n如果你想控制模块的安装过程，可以在模块的目录下创建一个名为 `customize.sh` 的文件，这个脚本将会在模块被解压后**导入**到当前 shell 中，如果你的模块需要根据设备的 API 版本或者设备构架做一些额外的操作，那这个脚本将非常有用。\n\n如果你想完全控制脚本的安装过程，你可以在 `customize.sh` 中声明 `SKIPUNZIP=1` 来跳过所有的默认安装步骤；此时，你需要自行处理所有安装过程（如解压模块，设置权限等）\n\n`customize.sh` 脚本以“独立模式”运行在 APatch 的 BusyBox `ash` shell 中。你可以使用如下变量和函数：\n\n#### 变量 {#variables}\n\n- `KERNELPATCH` (bool): 标记此脚本运行在 APatch 环境下，此变量的值将永远为 `true`\n- `KERNEL_VERSION` (hex): 从 KernelPatch 继承，内核版本号 (如： `50a01` 是指 5.10.1)\n- `KERNELPATCH_VERSION` (hex): 从 KernelPatch 继承，KernelPatch 版本号 (如： `a05` 是指 0.10.5)\n- `SUPERKEY` (string): 从 KernelPatch 继承，用于调用 kpatch 或者 supercall\n\n- `APATCH` (bool): 标记此脚本运行在 APatch 环境下，此变量的值将永远为 `true`\n- `APATCH_VER_CODE` (int): APatch 当前的版本号 (如. `10672`)\n- `APATCH_VER` (string): APatch 当前的版本名 (如. `10672`)\n\n- `BOOTMODE` (bool): 此变量在 APatch 中永远为 `true`\n- `MODPATH` (path): 当前模块的安装目录\n- `TMPDIR` (path): 可以存放临时文件的目录\n- `ZIPFILE` (path): 当前模块的安装包文件\n- `ARCH` (string): 设备的 CPU 构架，只有 `arm64`\n- `IS64BIT` (bool): 是否是 64 位设备\n- `API` (int): 当前设备的 Android API 版本 (如：Android 6.0 上为 `23`)\n\n::: warning\n`MAGISK_VER_CODE` 在 APatch 为 `27000`，`MAGISK_VER` 则为 `27.0`\n:::\n\n#### 函数 {#functions}\n\n```txt\nui_print <msg>\n    print <msg> to console\n    Avoid using 'echo' as it will not display in custom recovery's console\n\nabort <msg>\n    print error message <msg> to console and terminate the installation\n    Avoid using 'exit' as it will skip the termination cleanup steps\n\nset_perm <target> <owner> <group> <permission> [context]\n    if [context] is not set, the default is \"u:object_r:system_file:s0\"\n    this function is a shorthand for the following commands:\n       chown owner.group target\n       chmod permission target\n       chcon context target\n\nset_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context]\n    if [context] is not set, the default is \"u:object_r:system_file:s0\"\n    for all files in <directory>, it will call:\n       set_perm file owner group filepermission context\n    for all directories in <directory> (including itself), it will call:\n       set_perm dir owner group dirpermission context\n```\n\n## 启动脚本 {#boot-scripts}\n\n在 APatch 中，根据脚本运行模式的不同分为两种：post-fs-data 模式和 late_start 服务模式。\n\n- post-fs-data 模式\n    - 这个阶段是阻塞的。在执行完成之前或者 10 秒钟之后，启动过程会暂停。\n    - 脚本在任何模块被挂载之前运行。这使得模块开发者可以在模块被挂载之前动态地调整它们的模块。\n    - 这个阶段发生在 Zygote 启动之前。\n    - 使用 setprop 会导致启动过程死锁！请使用 `resetprop -n <prop_name> <prop_value>` 代替。\n    - **只有在必要时才在此模式下运行脚本**。\n\n- late_start 服务模式\n    - 这个阶段是非阻塞的。你的脚本会与其余的启动过程**并行**运行。\n    - **大多数脚本都建议在这种模式下运行**。\n\n在 APatch 中，启动脚本根据存放位置的不同还分为两种：通用脚本和模块脚本。\n\n- 通用脚本\n    - 放置在 `/data/adb/post-fs-data.d`, `/data/adb/post-mount.d`, `/data/adb/service.d` 或 `/data/adb/boot-completed.d` 中。\n    - 只有在脚本被设置为可执行（`chmod +x script.sh`）时才会被执行。\n    - 在 `post-fs-data.d` 中的脚本以 post-fs-data 模式运行，在 `service.d` 中的脚本以 late_start 服务模式运行。\n    - 模块**不应**在安装过程中添加通用脚本。\n\n- 模块脚本\n    - 放置在模块自己的文件夹中。\n    - 只有当模块被启用时才会执行。\n    - `post-fs-data.sh` 以 post-fs-data 模式运行，`post-mount.sh` 以 post-mount 模式运行，而 `service.sh` 则以 late_start 服务模式运行，`boot-completed` 在 Android 系统启动完毕后以服务模式运行。\n\n所有启动脚本都将在 APatch 的 BusyBox ash shell 中运行，并启用“独立模式”。  \n\n\n### 启动脚本的流程解疑 {#Boot-scripts-process-explanation}\n以下是 Android 的相关启动流程（部分省略），其中包括了 Apatch 的操作（带前导星号），应该能帮助你更好地理解这些启动脚本的用途：\n\n```txt\n0. BootLoader (nothing on sceen)\nload patched boot.img\n...\n\n1. kernel init (oem logo on screen)\nmount /dev, /dev/pts, /proc, /sys, etc.\nproperty-init -> read default props\nread init.rc\n...\nearly-init -> init -> late_init\nearly-fs\n   start vold\nfs\n  mount /vendor, /system, /persist, etc.\npost-fs-data\n  *safe mode check\n  *execute general scripts in post-fs-data.d/\n  *load sepolicy.rule -> magiskpolicy\n  *mount tmpfs, devpts\n  *execute module scripts post-fs-data.sh\n    **(Zygisk)./bin/zygisk-ptrace64 monitor\n  *(pre)load system.prop (same as `resetprop -n`)\n  *remount modules /system\n  *execute general scripts in post-mount.d/\n  *execute module scripts post-mount.sh\nzygote-start\nload_all_props_action\n  *execute resetprop (actual set props for resetprop with -n option)\n... -> boot\n  class_start core\n    start-service logd, console, vold, etc.\n  class_start main\n    start-service adb, netd, zygote, etc.\n\n2. kernel2user init (rom animation on screen, start by service bootanim)\n*execute general scripts in service.d/\n*execute module scripts service.sh\n*set props for resetprop without -p option\n  **(Zygisk) hook zygote (start zygiskd)\n  **(Zygisk) mount zygisksu/module.prop\nstart system apps (autostart)\n...\nboot complete (broadcast ACTION_LOCKED_BOOT_COMPLETED event)\n*execute general scripts in boot-completed.d/\n*execute module scripts boot-completed.sh\n\n3. User operable (lock screen)\ninput password to decrypt /data/data\n*actual set props for resetprop with -p option\nstart user apps (autostart)\n```\n\n如果你对 Android 的 init 语言感兴趣，推荐阅读[文档](https://android.googlesource.com/platform/system/core/+/master/init/README.md)\n"
  },
  {
    "path": "docs/cn/faq_cn.md",
    "content": "# 常见问题解答\n\n## 什么是APatch？\n\nAPatch是一种类似于Magisk或KernelSU的root解决方案，但APatch提供更多功能。\nAPatch分别结合了Magisk方便易用的通过`boot.img`安装的方法，和KernelSU强大的内核修补能力。\n\n## APatch与Magisk的区别？\n\n- Magisk对启动映像中的ramdisk进行补丁，以修改init系统。而APatch则直接修补Linux内核。\n\n## APatch与KernelSU的区别？\n\n- KernelSU需要您设备的内核的源代码，而OEM并不总是提供该源码。而APatch仅需要您的设备原本的`boot.img`。\n\n## APatch与Magisk、KernelSU的区别？\n\n- APatch可选择不修改SELinux，这意味着Android应用程序线程可以被root，无需libsu和IPC。\n- APatch提供**Kernel Patch Module（KP模块）**。\n\n## 什么是Kernel Patch Module（KP模块）？\n\n一些代码在内核空间运行，类似于Loadable Kernel Modules（LKM）。\n\n此外，KPM提供在内核空间进行内联hook、系统调用表hook的能力。\n\n更多相关信息，请参阅[如何编写KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)\n\n## APatch与KernelPatch的关系\n\nAPatch依赖于KernelPatch，继承了其所有功能并进行了扩展。\n\n您可以仅安装KernelPatch，但如此将不允许您使用Magisk模块。  \n要使用超级用户管理，您需要安装AndroidPatch，然后卸载KernelPatch。\n\n[了解更多关于KernelPatch的信息](https://github.com/bmax121/KernelPatch)\n\n## 什么是SuperKey（超级密钥）？\n\nKernelPatch 添加了一个新的系统调用（syscall），为应用程序和用户空间中的程序提供所有功能，此系统调用称为SuperCall。 \n当应用程序/程序尝试调用SuperCall时，它需要提供访问凭据，称为SuperKey。\n只有当SuperKey正确时，才能成功调用 SuperCall。否则，调用方将不受影响。\n\n## 关于SELinux如何处理？\n\n- KernelPatch不修改SELinux上下文，而是通过hook绕过SELinux。 这允许您在应用程序上下文中root Android线程，无需使用libsu启动新进程，然后执行IPC。这非常方便。\n- 此外，APatch直接利用magiskpolicy提供额外的SELinux支持。  \n"
  },
  {
    "path": "docs/cn_tw/faq_cn_tw.md",
    "content": "# 〈常見問題集〉\n\n\n## 什麼是 APatch？\nAPatch 為一套汲取 Magisk、KernelSU 優勢於一身的 Root 解決方案。\n不僅保留 Magisk 自身便捷、修補 `boot.img` 即用的特性，也有 KernelSU 強大的核心修補功能。\n\n\n## APatch 與 Magisk 的差別為何？\n- Magisk 會先調用 boot 修補鏡像的 ramdisk，再修改 init 系統；APatch 則經由修補鏡像，直接修改核心本身。\n\n\n## APatch vs KernelSU\n- KernelSU 依託 OEM 廠商提供的裝置核心原始碼，但並非每間廠商都會提供；而 APatch 只需修補原廠 `boot.img`。\n\n\n## APatch vs Magisk、KernelSU\n- APatch 可選擇不修改 SELinux，但仍讓應用程式執行緒調用 Root 權限。過程不需要 libsu 以及 IPC。\n- 支援**核心修補模組**。\n\n\n## 什麼是核心修補模組？\n**核心修補模組**為一套執行在核心空間的程式片段——類似於裝載式核心模組（LKM）——。\n\n包括 inline-hook、syscall-table-hook，核心修補模組也能做到。\n\n更多詳情，請參閱[〈如何編寫核心修補模組？〉](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)（英語）。\n\n\n## APatch 和 KernelPatch 的關係\n\nAPatch 基於 KernelPatch。繼承 KernelPatch 特性的基礎之上，新增更多功能。\n\n你也能選擇只安裝 KernelPatch，但這樣就沒辦法使用 Magisk 模組，且包括管理超級使用者權限在內的功能，你都必須解除安裝 KernelPatch 後再安裝 AndroidPatch。\n\n[深入了解 KernelPatch](https://github.com/bmax121/KernelPatch)\n\n\n## 什麼是超級密鑰？\n**超級密鑰**為 KernelPatch 上的系統呼叫（syscall）服務，旨在讓使用者空間內的程式也能套用修補變更；也稱作**超級呼叫**。當程式請求**超級呼叫**，需提供一份稱作**超級密鑰**的存取憑證。\n**超級呼叫**僅在**超級密鑰**正確無虞之下生效，反之則失效。\n\n\n## 那 SELinux 怎麼辦？\n- KernelPatch 不修改 SELinux 內容，而是使用 Hook 忽略 SELinux 層；\n  換句話說，應用程式內的 Android 執行緒可直接調用 Root 權限，而不用經過讓 libsu 新增運算排程、安排 IPC 等步驟。\n  可謂事半功倍。\n- 此外，由於 APatch 使用了 magiskpolicy，使你能有額外的 SELinux 支援。\n"
  },
  {
    "path": "docs/de/faq_de.md",
    "content": "# Häufig gestellte Fragen\n\n\n## Was ist APatch?\nAPatch ist eine Root-Lösung, ähnlich wie Magisk oder KernelSU, welche das Beste beider vereint.\nEs kombiniert Magisks bequeme und leichte Installationsmethode über `boot.img` mit KernelSUs starken Kernel-Korrektur-Fähigkeiten.\n\n\n## Was ist der Unterschied zwischen APatch und Magisk?\n- Magisk modifiziert das Init-System mit einer Korrektur in Ihrem boot image ramdisk, während APatch den Kernel direkt korrigiert.\n\n\n## APatch gegen KernelSU\n- KernelSU benötigt den Quellcode für dein Geräte-Kernel, welcher nicht immer von der OEM gegeben wird. APatch funktioniert allein mit Ihrem Standard-`boot.img`.\n\n\n## APatch gegen Magisk, KernelSU\n- APatch erlaubt Ihnen, optional, nicht SELinux zu modifizieren, was bedeutet, dass ein App-Kontext gerootet werden kann, sodass libsu und IPC nicht benötigt werden.\n- **Kernel Korrektur Modul** gegeben.\n\n\n## Was ist ein Kernel Korrigtur Modul?\nEtwas Code läuft im Kernelbereich, ähnlich zu Ladbaren Kernel-Modulen (LKM).\n\nDazu stellt KPM die Fähigkeit bereit, \"inline-hook\", \"syscall-table-hook\" im Kernelbereich zu machen.\n\nFür mehr Informationen, siehe [Wie schreibt man ein KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)\n\n\n## Beziehung zwischen APatch und KernelPatch\n\nAPatch benötigt KernelPatch, übernimmt all seine Fähigkeiten und wurde erweitert.\n\nSie können nur KernelPatch installieren, aber dies wird Ihnen nicht erlauben, Magisk-Module zu nutzen.\n\n[Lerne mehr über KernelPatch](https://github.com/bmax121/KernelPatch)\n\n\n## Was ist SuperKey?\nKernelPatch fügt einen neuen System-Abruf (syscall) hinzu, um alle Möglichkeiten, Apps und anderen Programmen im Benutzerbereich, bereitzustellen, dieser System-Abruf ist bekannt als **SuperCall**.\nWenn eine App / ein Programm versucht, **SuperCall** abzurufen, muss es ein Berechtigungsnachweis vorlegen, bekannt als **SuperKey**.\n**SuperCall** kann nur erfolgreich abgerufen werden, wenn der **SuperKey** korrekt ist und wenn nicht, dann bleibt der Rufer unbetroffen.\n\n\n## Was ist mit SELinux?\n- KernelPatch bearbeitet den SELinux-Kontext nicht und umgeht den SELinux über einen Haken.\n  Dies erlaubt Ihnen, einen Android-Kontext in dem App-Kontext, ohne dem Gebrauch, libsu zu nutzen, um einen neuen Prozess zu starten und darauf IPC auszuführen, zu rooten.\n  Dies ist bequem.\n- Dazu verwendet APatch direkt das Magiskkonzept, um weitere SELinux-Unterstützung bereitzustellen.\n"
  },
  {
    "path": "docs/en/faq.md",
    "content": "# FAQ\n\n\n## What is APatch?\nAPatch is a root solution similar to Magisk or KernelSU that unites the best of both.\nIt combines Magisk's convenient and easy install method through `boot.img` with KernelSU's powerful kernel patching abilities.\n\n\n## What's the difference between APatch and Magisk?\n- Magisk modifies the init system with a patch in your boot image's ramdisk, while APatch patches the kernel directly.\n\n\n## APatch vs KernelSU\n- KernelSU requires the source code for your device's kernel which is not always provided by the OEM. APatch works with just your stock `boot.img`.\n\n\n## APatch vs Magisk, KernelSU\n- APatch allows you to optionally not modify SELinux, this means that the APP thread can be rooted, libsu and IPC are not necessary.\n- **Kernel Patch Module** provided.\n\n\n## What is Kernel Patch Module?\nSome code runs in Kernel Space, similar to Loadable Kernel Modules (LKM).\n\nAdditionally, KPM provides the ability to do inline-hook, syscall-table-hook in kernel space.\n\nFor more information, see [How to write a KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)\n\n\n## Relationship between APatch and KernelPatch\n\nAPatch depends on KernelPatch, inherits all its capabilities, and has been expanded.\n\nYou can install KernelPatch only, but this will not allow you to use Magisk modules\n\n[Learn more about KernelPatch](https://github.com/bmax121/KernelPatch)\n\n\n## What is SuperKey?\nKernelPatch adds a new system call (syscall) to provide all capabilities to apps and programs in userspace, this syscall is referred to as **SuperCall**.\nWhen an app/program tries to invoke **SuperCall**, it needs to provide an access credential, known as the **SuperKey**.\n**SuperCall** can only be successfully invoked if the **SuperKey** is correct and if it's not the caller will remain unaffected.\n\n\n## How about SELinux?\n- KernelPatch doesn't modify the SELinux context and bypasses SELinux via a hook.\n  This allows you to root an Android thread within the app context without the need to use libsu to start a new process and then perform IPC.\n  This is very convenient.\n- In addition, APatch directly utilizes magiskpolicy to provide additional SELinux support.\n"
  },
  {
    "path": "docs/es/faq_es.md",
    "content": "# Preguntas frecuentes\n\n## ¿Qué es APatch?\nAPatch es una solución de root similar a Magisk o KernelSU que une lo mejor de ambos.\nCombina el método de instalación conveniente y fácil de Magisk a través de un patche en `boot.img` y las potentes capacidades de KernelSU para parchear el kernel.\n\n\n## Diferencias entre APatch y Magisk\n- Magisk modifica el sistema de init (el sistema que inicializa todos los subsistemas del dispositivo) con un parche en la ramdisk de tu imagen `boot.img`, mientras que APatch parchea el kernel directamente.\n\n\n## Diferencias entre APatch y KernelSU\n- KernelSU requiere el código fuente del kernel del dispositivo, que no siempre es brindado por el fabricante del mismo. APatch solo requiere la imagen `boot.img`\n\n\n## Diferencias entre APatch y ambas soluciones de root\n- APatch permite opcionalmente no modificar el contexto de SELinux. También da acceso root a las apps en su propio contexto, lo cual significa que no hay necesidad de usar libsu ni IPC.\n- Se añaden los **KPM** (Kernel Patch Modules), explicados abajo\n\n\n## ¿Qué es un Kernel Patch Module (KPM, Módulo de Parche del Kernel)?\nPermite implementar código personalizado que corra en kernelspace, es decir, en el mismo entorno que el kernel. Funciona similar a los módulos de kernel (los LKM, Loadable Kernel Modules) que se cargan con insmod/rmmod/modprobe/etc.\n\nAdemás, KPM permite hacer inline-hooks (\"engancharse\" a una función en el mismo lugar de memoria, he de ahí el \"inline\") y syscall-table-hook (modificar la tabla de syscalls)\n\nPara más información, lee [Como escribir un KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md) (en Inglés)\n\n\n## Relación entre APatch y KernelPatch\nAPatch depende de KernelPatch, hereda todas sus capacidades y las expande.\n\nPuedes instalar solo KernelPatch, pero esto no va a permitir que uses módulos de Magisk, y para poder administrar el acceso root vas a tener que instalar AndroidPatch y desinstalarlo.\n\n[Aprende más de KernelPatch](https://github.com/bmax121/KernelPatch) (en Inglés)\n\n\n## ¿Qué es SuperKey?\nKernelPatch agrega una nueva syscall (llamada al sistema) para dar todas las capacidades a apps y programas en userspace (el espacio del usuario fuera del kernel), y esta syscall se llama **SuperCall**.\nCuando una app o programa intenta llamar **SuperCall**, necesita proveer una credencial de acceso llamada **SuperKey**.\n**SuperCall** solo se puede llamar si se provee una **SuperKey** correcta, caso contrario la app/programa que lo llame quedará intacta.\n\n\n## ¿Y qué pasa con SELinux?\n- KernelPatch no modifica el contexto de SELinux y simplemente se lo salta a través de un hook, lo cual permite que des acceso root a un hilo de Android dentro del contexto de la aplicación sin necesidad de usar libsu para iniciar un nuevo proceso y luego comunicarte con él a través de IPC (Inter-Process Communication)\n- Además, APatch usa magiskpolicy directamente para obtener mayor soporte de SELinux. Solo esto va a ser detectado como Magisk, y cualquiera que lo desee puede intentar evitar esto ya que el problema ya está bastante claro.\n"
  },
  {
    "path": "docs/fr/faq_fr.md",
    "content": "## Foire aux questions (FAQ)\n\n## Qu'est-ce qu'APatch ?\n\nAPatch est une méthode de root, similaire à Magisk ou KernelSU, offrant encore plus de fonctionnalités.\n\n## Quelle est la différence entre APatch et Magisk ?\n\n- Magisk modifie init, tandis qu'APatch patche le noyau Linux.\n\n## Quelle est la différence entre APatch et KernelSU ?\n\n- KernelSU nécessite le code source. APatch n'a besoin que du fichier boot.img.\n\n## Quelle est la différence entre APatch, Magisk et KernelSU ?\n\n- Optionnellement, ne modifie pas SELinux. Root dans le contexte d'application Android, libsu et d'IPC non nécessaires\n- Fournit **Kernel Patch Module**\n\n## Qu'est-ce que Kernel Patch Module ?\n\nCertains codes s'exécutent dans l'espace du noyau, à l'instar des modules noyau chargeables (LKM, Loadable Kernel Modules).\n\nDe plus, KPM offre la possibilité d'effectuer des inline-hook, syscall-table-hook dans l'espace noyau.\n\n[Comment écrire un module KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/fr/module.md)\n\n## Relation entre APatch et KernelPatch\n\nAPatch dépend de KernelPatch, héritant de toutes ses fonctionnalités, et l'étendant.\n\nVous pouvez installer KernelPatch seul, mais cela ne vous permettra pas d'utiliser de module Magisk.\nPour utiliser la gestion super utilisateur, vous devez installer AndroidPatch puis le désinstaller.\n\n[En savoir plus sur KernelPatch](https://github.com/bmax121/KernelPatch)\n\n## Qu'est-ce que la clé (SuperKey) ?\n\nKernelPatch fournit toutes les fonctionnalités à l'espace utilisateur en effectuant un appel système appelé **SuperCall**.  \nL'appel du SuperCall nécessite le passage d'un type d'informations d'identification appelé **SuperKey**.  \nUn SuperCall ne peut être effectué avec succès que si la clé est correcte. Si la clé est incorrecte, l'appelant ne sera pas affecté.\n\n## Qu'en est-il de SELinux ?\n\n- KernelPatch ne modifie pas le contexte SELinux et contourne SELinux via des hooks.  \n  Cela vous permet de rooter un processus Android dans le contexte de applicatif, sans avoir à démarrer un nouveau processus avec libsu et ensuite exécuter l'IPC.\n- De plus, APatch fournit un support SELinux supplémentaire directement via magiskpolicy.  \n  Cependant, seul ce dernier sera détecté en tant que Magisk. Toute personne intéressée peut essayer de le contourner, le problème est déjà très clair.\n"
  },
  {
    "path": "docs/id/faq.md",
    "content": "# FAQ\n\n## Apa itu APatch?\nAPatch adalah solusi root yang mirip dengan Magisk atau KernelSU yang menyatukan yang terbaik dari keduanya.\nIa menggabungkan metode instalasi Magisk yang mudah dan praktis melalui `boot.img` dengan kemampuan patching kernel KernelSU yang hebat.\n\n## Apa perbedaan antara APatch dan Magisk?\n\n- Magisk memodifikasi sistem init dengan patch di ramdisk boot image Anda, sementara APatch menambal kernel secara langsung.\n\n## APatch vs KernelSU\n- KernelSU memerlukan kode sumber untuk kernel perangkat Anda yang tidak selalu disediakan oleh OEM. APatch hanya berfungsi dengan `boot.img` bawaan Anda.\n\n## APatch vs Magisk, KernelSU\n- APatch memungkinkan Anda untuk secara opsional tidak memodifikasi SELinux, ini berarti bahwa utas APP dapat di-root, libsu dan IPC tidak diperlukan.\n\n- **Modul Patch Kernel** disediakan.\n\n## Apa itu Modul Patch Kernel? Beberapa kode berjalan di Kernel Space, mirip dengan Loadable Kernel Modules (LKM).\n\nSelain itu, KPM menyediakan kemampuan untuk melakukan inline-hook, syscall-table-hook di kernel space.\n\nUntuk informasi selengkapnya, lihat [Cara menulis KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)\n\n## Hubungan antara APatch dan KernelPatch\n\nAPatch bergantung pada KernelPatch, mewarisi semua kemampuannya, dan telah diperluas.\n\nAnda hanya dapat menginstal KernelPatch, tetapi ini tidak akan memungkinkan Anda untuk menggunakan modul Magisk\n\n[Pelajari selengkapnya tentang KernelPatch](https://github.com/bmax121/KernelPatch)\n\n## Apa itu SuperKey?\nKernelPatch menambahkan panggilan sistem baru (syscall) untuk menyediakan semua kemampuan bagi aplikasi dan program di userspace, syscall ini disebut sebagai **SuperCall**. Saat aplikasi/program mencoba memanggil **SuperCall**, aplikasi/program tersebut perlu menyediakan kredensial akses, yang dikenal sebagai **SuperKey**.\n**SuperCall** hanya dapat dipanggil dengan sukses jika **SuperKey** benar dan jika tidak, pemanggil tidak akan terpengaruh.\n\n## Bagaimana dengan SELinux?\n- KernelPatch tidak mengubah konteks SELinux dan melewati SELinux melalui hook.\n\nIni memungkinkan Anda untuk melakukan root pada thread Android dalam konteks aplikasi tanpa perlu menggunakan libsu untuk memulai proses baru dan kemudian melakukan IPC.\n\nIni sangat praktis.\n\n- Selain itu, APatch secara langsung menggunakan magiskpolicy untuk menyediakan dukungan SELinux tambahan."
  },
  {
    "path": "docs/it/faq_it.md",
    "content": "# Domande frequenti\n\n## Cos'è APatch\n\nAPatch è una soluzione per il root simile a Magisk o KernelSU, ma offre funzionalità aggiuntive.\n\n## APatch vs Magisk\n\n- Magisk modifica l'init, mentre APatch patcha il kernel Linux.\n\n## APatch vs KernelSU\n\n- KernelSU richiede il codice sorgente del kernel, mentre per APatch è sufficiente solo il file boot.img.\n\n## APatch vs Magisk, KerenlSU\n\n- Opzionalmente, non modifica SELinux.\n- Consente di ottenere i permessi di root nel contesto dell'app Android, senza la necessità di libsu e IPC.\n- Possibilità di utilizzare **Kernel Patch Module**\n\n## Cos'è un Kernel Patch Module\n\nÈ del codice eseguito nello spazio del Kernel, simile ai Loadable Kernel Modules (LKM).\n\nInoltre, KPM fornisce la possibilità di effettuare inline-hook e syscall-table-hook nello spazio del kernel.\n\n[Come scrivere un KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)\n\n## Relazione tra APatch e KernelPatch\n\nAPatch dipende da KernelPatch, eredita tutte le sue capacità ed è stato ampliato.\n\nPuoi installare solo KernelPatch, ma ciò non consentirà l'uso dei moduli Magisk.\nPer gestire i permessi di root, è necessario installare AndroidPatch e successivamente disinstallarlo.\n\n[Scopri di più su KernelPatch](https://github.com/bmax121/KernelPatch)\n\n## Cos'è la SuperKey\n\nKernelPatch aggancia le chiamate di sistema per fornire tutte le capacità allo spazio utente, e questa chiamata di sistema è chiamata **SuperCall**.\nInvocare SuperCall richiede il passaggio di una credenziale, nota come **SuperKey**.\nSuperCall può essere invocato con successo solo quando la SuperKey è corretta; se la SuperKey è errata, chi effettua la chiamata rimane inalterato.\n\n## Riguardo a SELinux\n\n- KernelPatch non modifica il contesto SELinux e bypassa SELinux tramite hook,  \n  consentendo di ottenere i privilegi di root in un thread Android all'interno del contesto dell'app senza la necessità di utilizzare libsu per avviare un nuovo processo e quindi eseguire IPC.\n  Questo è molto conveniente.\n- Inoltre, APatch utilizza direttamente magiskpolicy per fornire ulteriore supporto SELinux.  \n  Tuttavia, solo questo sarà rilevato come Magisk. Chiunque sia interessato può cercare di bypassarlo; il problema è già abbastanza chiaro."
  },
  {
    "path": "docs/kr/faq_kr.md",
    "content": "# FAQ\n\n\n## APatch가 뭔가요?\nAPatch는 Magisk와 KernelSU와 유사한 루팅툴로, 두 가지의 장점을 결합하였습니다.\n`boot.img`을 통해 설치하는 Magisk의 편리하고 간편한 방법과 강력한 커널 패치 기능을 제공하는 KernelSU를 결합하였습니다.\n\n\n## APatch와 Magisk의 차이점은 무엇인가요?\n- Magisk는 부트 이미지의 램디스크에 패치를 적용하여 초기 시스템을 수정하는 반면, APatch는 커널을 직접 패치합니다.\n\n\n## APatch vs KernelSU\n- KernelSU는 기기의 커널 소스 코드가 필요하지만 OEM에서 항상 제공하지는 않습니다. 반면, APatch는 단지 여러분의 기본 `boot.img`만으로 작동합니다.\n\n\n## APatch vs Magisk, KernelSU\n- APatch는 선택적으로 SELinux를 수정하지 않을 수 있어, APP 스레드를 루팅할 수 있으며, libsu와 IPC가 필요하지 않습니다.\n- **커널 패치 모듈**을 제공합니다..\n\n\n## 커널 패치 모듈이 뭔가요?\n커널 패치 모듈은 Loadable Kernel Modules (LKM)과 유사하게 커널 공간에서 실행되는 코드입니다.\n\n또한, KPM은 커널에서 인라인 훅과 시스템 콜 테이블 훅을 수행할 수 있습니다.\n\n자세한 정보는 [KPM 작성 방법](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)에서 확인하세요.\n\n\n## APatch와 KernelPatch의 관계\n\nAPatch는 KernelPatch에 의존하며, 모든 기능을 상속받고 확장되었습니다.\n\nKernelPatch만 설치할 수도 있지만, 이 경우 Magisk 모듈을 사용할 수 없습니다.\n\n[KernelPatch에 대해 더 알아보기](https://github.com/bmax121/KernelPatch)\n\n\n## SuperKey가 뭔가요?\nKernelPatch는 사용자 공간의 앱 및 프로그램에 모든 기능을 제공하는 새로운 시스템 콜 (syscall)을 추가하며, 이것을 **SuperCall**이라고 합니다.\n앱이나 프로그램이 **SuperCall**를 호출하려고 할 때, 접근 자격증명인 **SuperKey**를 제공해야 합니다.\n**SuperCall**은 **SuperKey**가 정확하고 호출자에게 영향을 미치지 않을 경우에만 성공적으로 수행됩니다.\n\n\n## SELinux는 어떻게 다루나요?\n- KernelPatch는 SELinux 컨텍스트를 수정하지 않고 SELinux를 우회하는 훅을 사용합니다.\n  이를 통해 앱 컨텍스트 내에서 안드로이드 스레드를 루팅할 수 있으며, 새 프로세스를 시작하고 IPC를 수행하기 위해 libsu를 사용할 필요가 없습니다.\n  이 방법은 매우 편리합니다.\n- 또한, APatch는 추가적인 SELinux 지원을 제공하기 위해 직접 magiskpolicy를 활용합니다.\n"
  },
  {
    "path": "docs/pt_br/faq_pt_br.md",
    "content": "# Perguntas frequentes\n\n## O que é APatch?\n\nAPatch é uma solução root semelhante ao Magisk ou KernelSU que une o melhor de ambos. Ele combina o método de instalação fácil e conveniente do Magisk por meio do `boot.img` com as poderosas habilidades de patch de kernel do KernelSU.\n\n## Qual é a diferença entre APatch e Magisk?\n\n- Magisk modifica o sistema init com um patch no ramdisk da sua imagem de inicialização, enquanto o APatch corrige o kernel diretamente.\n\n## APatch vs KernelSU\n\n- KernelSU requer o código-fonte do kernel de seu dispositivo, que nem sempre é fornecido pelo OEM. APatch funciona apenas com seu `boot.img` stock.\n\n## APatch vs Magisk e KernelSU\n\n- APatch permite opcionalmente não modificar o SELinux, isso significa que o thread do app pode ser rooteado, libsu e IPC não são necessários.\n- **Módulo KernelPatch** fornecido.\n\n## O que é Módulo KernelPatch?\n\nAlguns códigos são executados no Kernel Space, semelhante ao Loadable Kernel Modules (LKM).\n\nAlém disso, o KPM fornece a capacidade de executar inline-hook e syscall-table-hook no Kernel Space.\n\nPara mais informações, veja [como escrever um KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md).\n\n## Relacionamento entre APatch e KernelPatch\n\nAPatch depende do KernelPatch. Ele herda todas as suas capacidades e foi expandido.\n\nVocê pode instalar apenas o KernelPatch, mas isso não permitirá o uso de módulos Magisk.\n\n[Saiba mais sobre o KernelPatch](https://github.com/bmax121/KernelPatch).\n\n## O que é SuperKey?\n\nKernelPatch conecta chamadas do sistema para fornecer todos os recursos ao espaço do usuário, e essa chamada do sistema é chamada de **SuperCall**. Invocar o SuperCall requer a passagem de uma credencial, conhecida como **SuperKey**. SuperCall só pode ser invocado com sucesso quando a SuperKey estiver correta. Se a SuperKey estiver incorreta, o chamador não será afetado.\n\n## E o SELinux?\n\n- KernelPatch não modifica o contexto do SELinux e ignora o SELinux via hook. Isso permite que você faça root em um thread do Android dentro do contexto do app sem a necessidade de usar libsu para iniciar um novo processo e então executar o IPC.\n- Além disso, o APatch utiliza diretamente o magiskpolicy para fornecer suporte adicional ao SELinux.\n"
  },
  {
    "path": "docs/ru/.gitkeep",
    "content": ""
  },
  {
    "path": "docs/ru/faq_ru.md",
    "content": "# Часто задаваемые вопросы\n\n\n## Что такое APatch?\nAPatch - это root решение, похожее на Magisk или KernelSU, которое объединяет лучшее из обоих.\nОно сочетает удобный и простой метод установки Magisk через `boot.img` с мощными возможностями исправления ядра KernelSU.\n\n## В чем разница между APatch и Magisk?\n- Magisk изменяет систему инициализации с помощью патча на RAM-диске вашего загрузочного образа, в то время как APatch вносит изменения непосредственно в ядро.\n\n\n## APatch против KernelSU\n- Для KernelSU требуется исходный код ядра вашего устройства, который не всегда предоставляется OEM-производителем. APatch работает напрямую с вашим исходным `boot.img`.\n\n\n## APatch против Magisk, KernelSU\n- APatch позволяет вам при желании не изменять SELinux. Это означает, что поток приложения может быть рутирован, в libsu и IPC нет необходимости.\n- **Kernel Patch Module** предоставляется.\n\n\n## Что такое Kernel Patch Module?\nНекоторый код выполняется в пространстве ядра, аналогично загружаемым модулям ядра (Loadable Kernel Modules, LKM).\n\nКроме того, KPM предоставляет возможность выполнять inline-hook, syscall-table-hook в пространстве ядра.\n\nДля получения дополнительной информации смотрите [Как написать KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)\n\n\n## Связь между APatch и KernelPatch\n\nAPatch основан на KernelPatch, унаследовал все его возможности и был расширен.\n\nВы можете установить только KernelPatch, но это не позволит вам использовать модули Magisk, а чтобы использовать управление суперпользователем, вам необходимо установить AndroidPatch, а затем удалить его.\n\n[Узнать больше о KernelPatch](https://github.com/bmax121/KernelPatch)\n\n\n## Что такое SuperKey?\nKernelPatch добавляет новый системный вызов (syscall) для предоставления всех возможностей приложениям и программам в пользовательском пространстве. Этот системный вызов называется **SuperCall**.\nКогда приложение/программа пытается вызвать **SuperCall**, ему необходимо предоставить учетные данные для доступа, называемые **SuperKey**.\n**SuperCall** может быть успешно вызван только в том случае, если **SuperKey** правильный, а в противном случае вызывающий объект останется незатронутым.\n\n\n## Что насчет SELinux?\n- KernelPatch не изменяет контекст SELinux и обходит SELinux с помощью перехвата.\n  Это позволяет вам рутировать поток Android в контексте приложения без необходимости использовать libsu для запуска нового процесса и последующего выполнения IPC.\n  Это очень удобно.\n- Кроме того, APatch напрямую использует magiskpolicy для обеспечения дополнительной поддержки SELinux.\n"
  },
  {
    "path": "docs/tr/faq_tr.md",
    "content": "# SSS\n\n## APatch nedir?\n\nAPatch, Magisk veya KernelSU benzeri ve her ikisinin de en iyi yönlerini birleştiren bir root çözümdür. Magisk'in `boot.img` aracılığıyla kullanışlı ve kolay kurulum yöntemini ve KernelSU'nun güçlü kernel yamalama yeteneklerini birleştirir.\n\n## APatch ve Magisk arasındaki fark nedir?\n\n- Magisk başlangıç sistemini kernel'in ramdisk'indeki bir yama ile değiştirirken; APatch kernel'i doğrudan yamalar.\n\n## APatch vs KernelSU\n\n- KernelSU, cihazınızın kernel'i için her zaman OEM tarafından sağlanmayan kaynak kodunu gerektirir. APatch yalnızca stok `boot.img` dosyanızla çalışır.\n\n## APatch vs Magisk, KernelSU\n\n- İsteğe bağlı olarak SELinux'u değiştirmez. Bu şu anlama gelir; android uygulama parçacığının root'lanması için libsu ve IPC'ye gerek yoktur.\n- **Kernel Patch (Yama) Modülü** sağlanır.\n\n## Kernel Patch (Yama) Modülü nedir?\n\nBazı kodlar, Yüklenebilir Kernel Modüllerinde (LKM) olduğu gibi Kernel Seviyesinde çalışır.\n\nEk olarak KPM, kernel sviyesinde satır içi kanca, sistem çağrısı-tablo kancası yapma yeteneği sağlar.\n\nDaha fazla bilgi için bkz [KPM nasıl yazılır?](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)\n\n## APatch and KernelPatch arasındaki ilişki\n\nAPatch, KernelPatch'e dayalıdır; onun tüm yeteneklerini devralır ve onu daha da geliştirmiştir.\n\nYalnızca KernelPatch'i kurabilirsiniz ancak bu magisk modüllerini kullanmanıza izin vermez,\nSuperuser yönetimini kullanmak için de AndroidPatch'i yüklemeniz ve ardından kaldırmanız gerekir.\n\n[KernelPatch hakkında daha fazlasını öğrenin](https://github.com/bmax121/KernelPatch)\n\n## Süper Anahtar nedir?\n\nKernelPatch, tüm yetenekleri kullanıcı alanına (userspace) sağlamak için sistem çağrılarını (syscall) kancalar ve bu sistem çağrısına **SuperCall** denir.  \nBir uygulama/program SuperCall'ı çağırmayı denediğinde, **Süper Anahtar** olarak bilinen bir kimlik bilgisinin iletilmesini gerektirir.\nSuperCall yalnızca Süper Anahtar doğru olduğunda başarılı bir şekilde çağrılabilir; Süper Anahtar hatalıysa çağıran bundan etkilenmez.\n\n## Peki ya SELinux?\n\n- KernelPatch, SELinux içeriğini değiştirmez ve SELinux'u kanca yoluyla atlamaz. Bu, yeni bir işlem başlatmak ve ardından IPC gerçekleştirmek için libsu kullanmanıza gerek kalmadan, uygulama bağlamında bir Android iş parçacığını rootlamanıza olanak tanır. Bu çok kullanışlıdır.\n- Ayrıca APatch, ek SELinux desteği sağlamak için doğrudan magiskpolicy'yi kullanır.\n"
  },
  {
    "path": "docs/uk/faq_uk.md",
    "content": "# Поширені запитання\n\n\n## Що таке APatch?\nAPatch - це root рішення, схоже на Magisk або KernelSU, яке поєднує найкраще з обох.\nВоно поєднує зручний і простий метод установки Magisk через boot.img з потужними можливостями виправлення ядра KernelSU.\n\n## У чому різниця між APatch та Magisk?\n- Magisk змінює систему ініціалізації за допомогою патча на RAM диску вашого завантажувального образу, в той час як APatch вносить зміни безпосередньо в ядро.\n\n\n## APatch проти KernelSU\n- Для KernelSU потрібен вихідний код ядра вашого пристрою, який не завжди надається OEM-виробником. APatch працює безпосередньо з вашим вихідним `boot.img`.\n\n\n## APatch проти Magisk, KernelSU\n- APatch дозволяє вам за бажання не змінювати SELinux. Це означає, що потік програми може бути рутований, в libsu і IPC немає необхідності.\n- **Kernel Patch Module** надається.\n\n\n## Що таке Kernel Patch Module?\nДеякий код виконується у просторі ядра, аналогічно модулям ядра (Loadable Kernel Modules, LKM).\n\nКрім того, KPM надає можливість виконувати inline-hook, syscall-table-hook у просторі ядра.\n\nДля отримання додаткової інформації дивіться [Як написати KPM](https://github.com/bmax121/KernelPatch/blob/main/doc/module.md)\n\n\n## Зв'язок між APatch та KernelPatch\n\nAPatch заснований на KernelPatch, успадкував усі його можливості та був розширений.\n\nВи можете встановити тільки KernelPatch, але це не дозволить вам використовувати модулі Magisk, а щоб використовувати керування суперкористувачем, вам необхідно встановити AndroidPatch, а потім видалити його.\n\n[Дізнатись більше про KernelPatch](https://github.com/bmax121/KernelPatch)\n\n\n## Що таке SuperKey?\nKernelPatch додає новий системний дзвінок (syscall) для надання всіх можливостей додаткам і програмам в просторі користувача. Цей системний виклик називається **SuperCall**.\nКоли програма намагається викликати **SuperCall**, їй необхідно надати облікові дані для доступу, які називають **SuperKey**.\n**SuperCall** може бути успішно викликаний тільки в тому випадку, якщо **SuperKey** правильний, а в іншому випадку об'єкт, що викликає, не змінюється.\n\n\n## Як щодо SELinux?\n- KernelPatch не змінює контекст SELinux та обходить SELinux за допомогою перехоплення.\n  Це дозволяє вам рутувати потік Android у контексті програми без необхідності використовувати libsu для запуску нового процесу та подальшого виконання IPC.\n  Це дуже зручно.\n- Крім того, APatch безпосередньо використовує magiskpolicy для забезпечення додаткової підтримки SELinux.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/full_description.txt",
    "content": "The patching of Android kernel and Android system.\n<ul>\n<li>A new kernel-based root solution for Android devices.</li>\n<li>APM: Support for modules similar to Magisk.</li>\n<li>KPM: Support for modules that allow you to inject any code into the kernel (Requires kernel function <code>inline-hook</code> and <code>syscall-table-hook</code> enabled).</li>\n<li>APatch relies on KernelPatch.</li>\n<li>The APatch UI and the APModule source code have been derived and modified from KernelSU.</li>\n</ul>\n<ul>\n<li>Only supports the ARM64 architecture.</li>\n<li>Only supports Android kernel versions 3.18 - 6.1</li>\n</ul>\nSupport for Samsung devices with security protection: Planned\nKernel configs:\n<ul>\n<li>\n<code>CONFIG_KALLSYMS=y</code> and <code>CONFIG_KALLSYMS_ALL=y</code>\n</li>\n<li>\n<code>CONFIG_KALLSYMS=y</code> and <code>CONFIG_KALLSYMS_ALL=n</code>: Initial support\n</li>\n</ul>\nThe <strong>SuperKey</strong> has higher privileges than root access.\nWeak or compromised keys can lead to unauthorized control of your device.\nIt is critical to use robust keys and safeguard them from exposure to maintain the security of your device.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/short_description.txt",
    "content": "The patching of Android kernel and Android system\n"
  },
  {
    "path": "gradle/libs.versions.toml",
    "content": "[versions]\nagp = \"9.0.0\"\nkotlin = \"2.3.10\"\nksp = \"2.3.5\"\ncompose-bom = \"2026.01.01\"\nlifecycle = \"2.10.0\"\ncompose-destination = \"2.3.0\"\nlibsu = \"6.0.0\"\ncompose-material3 = \"1.5.0-alpha13\"\nsheets-compose-dialogs = \"1.3.0\"\n\n[plugins]\nagp-app = { id = \"com.android.application\", version.ref = \"agp\" }\nksp = { id = \"com.google.devtools.ksp\", version.ref = \"ksp\" }\nlsplugin-apksign = { id = \"org.lsposed.lsplugin.apksign\", version = \"1.4\" }\nlsplugin-resopt = { id = \"org.lsposed.lsplugin.resopt\", version = \"1.6\" }\nkotlin = { id = \"org.jetbrains.kotlin.android\", version.ref = \"kotlin\" }\nkotlin-compose-compiler = { id = \"org.jetbrains.kotlin.plugin.compose\", version.ref = \"kotlin\" }\n\n[libraries]\nandroidx-appcompat = { group = \"androidx.appcompat\", name = \"appcompat\", version = \"1.7.1\" }\nandroidx-activity-compose = { group = \"androidx.activity\", name = \"activity-compose\", version = \"1.12.3\" }\nandroidx-core-splashscreen = { group = \"androidx.core\", name = \"core-splashscreen\", version = \"1.2.0\" }\nandroidx-webkit = { group = \"androidx.webkit\", name = \"webkit\", version = \"1.15.0\" }\n\nandroidx-compose-bom = { group = \"androidx.compose\", name = \"compose-bom\", version.ref = \"compose-bom\" }\nandroidx-compose-material-icons-extended = { group = \"androidx.compose.material\", name = \"material-icons-extended\" }\nandroidx-compose-material3 = { group = \"androidx.compose.material3\", name = \"material3\", version.ref = \"compose-material3\" }\nandroidx-compose-ui = { group = \"androidx.compose.ui\", name = \"ui\" }\nandroidx-compose-ui-test-manifest = { group = \"androidx.compose.ui\", name = \"ui-test-manifest\" }\nandroidx-compose-ui-tooling = { group = \"androidx.compose.ui\", name = \"ui-tooling\" }\nandroidx-compose-ui-tooling-preview = { group = \"androidx.compose.ui\", name = \"ui-tooling-preview\" }\nandroidx-compose-runtime-livedata = { group = \"androidx.compose.runtime\", name = \"runtime-livedata\" }\n\nandroidx-lifecycle-runtime-ktx = { group = \"androidx.lifecycle\", name = \"lifecycle-runtime-ktx\", version.ref = \"lifecycle\" }\nandroidx-lifecycle-runtime-compose = { group = \"androidx.lifecycle\", name = \"lifecycle-runtime-compose\", version.ref = \"lifecycle\" }\nandroidx-lifecycle-viewmodel-compose = { group = \"androidx.lifecycle\", name = \"lifecycle-viewmodel-compose\", version.ref = \"lifecycle\" }\n\ncom-github-topjohnwu-libsu-core = { group = \"com.github.topjohnwu.libsu\", name = \"core\", version.ref = \"libsu\" }\ncom-github-topjohnwu-libsu-service = { group = \"com.github.topjohnwu.libsu\", name = \"service\", version.ref = \"libsu\" }\ncom-github-topjohnwu-libsu-nio = { group = \"com.github.topjohnwu.libsu\", name = \"nio\", version.ref = \"libsu\" }\ncom-github-topjohnwu-libsu-io = { group = \"com.github.topjohnwu.libsu\", name = \"io\", version.ref = \"libsu\" }\n\ndev-rikka-rikkax-parcelablelist = { module = \"dev.rikka.rikkax.parcelablelist:parcelablelist\", version = \"2.0.1\" }\n\nio-coil-kt-coil-compose = { group = \"io.coil-kt\", name = \"coil-compose\", version = \"2.7.0\" }\n\nkotlinx-coroutines-core = { module = \"org.jetbrains.kotlinx:kotlinx-coroutines-core\", version = \"1.10.2\" }\n\nme-zhanghai-android-appiconloader-coil = { group = \"me.zhanghai.android.appiconloader\", name = \"appiconloader-coil\", version = \"1.5.0\" }\n\ncompose-destinations-core = { group = \"io.github.raamcosta.compose-destinations\", name = \"core\", version.ref = \"compose-destination\" }\ncompose-destinations-ksp = { group = \"io.github.raamcosta.compose-destinations\", name = \"ksp\", version.ref = \"compose-destination\" }\n\nsheet-compose-dialogs-core = { group = \"com.maxkeppeler.sheets-compose-dialogs\", name = \"core\", version.ref = \"sheets-compose-dialogs\" }\nsheet-compose-dialogs-list = { group = \"com.maxkeppeler.sheets-compose-dialogs\", name = \"list\", version.ref = \"sheets-compose-dialogs\" }\nsheet-compose-dialogs-input = { group = \"com.maxkeppeler.sheets-compose-dialogs\", name = \"input\", version.ref = \"sheets-compose-dialogs\" }\n\nmarkdown = { group = \"io.noties.markwon\", name = \"core\", version = \"4.6.2\" }\n\nini4j = { group = \"org.ini4j\", name = \"ini4j\", version = \"0.5.4\" }\n\ncxx = { module = \"org.lsposed.libcxx:libcxx\", version = \"29.0.14206865\" }\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-9.3.1-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. For more details, visit\n# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app's APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\n# Enables namespacing of each library's R class so that its R class includes only the\n# resources declared in the library itself and none from the library's dependencies,\n# thereby reducing the size of the R class for that library\nandroid.nonTransitiveRClass=true\nandroid.experimental.enableNewResourceShrinker.preciseShrinking=true\nandroid.enableAppCompileTimeRClass=true\nksp.useKSP2=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\\n' \"$PWD\" ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -jar \"$APP_HOME/gradle/wrapper/gradle-wrapper.jar\" \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n@rem SPDX-License-Identifier: Apache-2.0\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -jar \"%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\" %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "scripts/update_binary.sh",
    "content": "#!/bin/sh\n\nTMPDIR=/dev/tmp\nrm -rf $TMPDIR\nmkdir -p $TMPDIR 2>/dev/null\n\nexport BBBIN=$TMPDIR/busybox\nunzip -o \"$3\" \"busybox\" -d $TMPDIR >&2\n\nfor arch in  \"arm64-v8a\" ; do\n  unzip -o \"$3\" \"lib/$arch/libbusybox.so\" -d $TMPDIR >&2\n  libpath=\"$TMPDIR/lib/$arch/libbusybox.so\"\n  chmod 755 $libpath\n  if [ -x $libpath ] && $libpath >/dev/null 2>&1; then\n    mv -f $libpath $BBBIN\n    break\n  fi\ndone\n$BBBIN rm -rf $TMPDIR/lib\n\nexport INSTALLER=$TMPDIR/install\n$BBBIN mkdir -p $INSTALLER\n$BBBIN unzip -o \"$3\" \"assets/*\" \"META-INF/com/google/*\" \"lib/*\" \"META-INF/com/google/*\" -x \"lib/*/libbusybox.so\" -d $INSTALLER >&2\nexport ASH_STANDALONE=1\nif echo \"$3\" | $BBBIN grep -q \"uninstall\"; then\n  exec $BBBIN sh \"$INSTALLER/assets/UninstallAP.sh\" \"$@\"\nelif echo \"$3\" | $BBBIN grep -q \"uninstaller\"; then\n  exec $BBBIN sh \"$INSTALLER/assets/UninstallAP.sh\" \"$@\"\nelse\n  exec $BBBIN sh \"$INSTALLER/assets/InstallAP.sh\" \"$@\"\nfi"
  },
  {
    "path": "scripts/update_script.sh",
    "content": "######################\n# APatch Empty script\n# Check update-binary\n######################\n\n"
  },
  {
    "path": "settings.gradle.kts",
    "content": "@file:Suppress(\"UnstableApiUsage\")\n\npluginManagement {\n    repositories {\n        gradlePluginPortal()\n        google()\n        mavenCentral()\n    }\n}\n\nplugins {\n    id(\"org.gradle.toolchains.foojay-resolver-convention\") version \"1.0.0\"\n}\n\ndependencyResolutionManagement {\n    repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS\n    repositories {\n        google()\n        mavenCentral()\n        maven(\"https://jitpack.io\")\n    }\n}\n\nrootProject.name = \"APatch\"\ninclude(\":app\")\n"
  }
]