diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..45cf84fd
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,3 @@
+./docker
+./github
+*.md
diff --git a/.github/assets/sponsors/emerge-tools-vertical-black.svg b/.github/assets/sponsors/emerge-tools-vertical-black.svg
new file mode 100644
index 00000000..7a27559f
--- /dev/null
+++ b/.github/assets/sponsors/emerge-tools-vertical-black.svg
@@ -0,0 +1 @@
+
diff --git a/.github/assets/sponsors/emerge-tools-vertical-white.svg b/.github/assets/sponsors/emerge-tools-vertical-white.svg
new file mode 100644
index 00000000..310e2e32
--- /dev/null
+++ b/.github/assets/sponsors/emerge-tools-vertical-white.svg
@@ -0,0 +1 @@
+
diff --git a/.github/assets/sponsors/sourcetoad-horizontal.svg b/.github/assets/sponsors/sourcetoad-horizontal.svg
new file mode 100644
index 00000000..2c8c55e0
--- /dev/null
+++ b/.github/assets/sponsors/sourcetoad-horizontal.svg
@@ -0,0 +1,217 @@
+
+
diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml
index e646dce5..2fe6ed30 100644
--- a/.github/workflows/analyze.yml
+++ b/.github/workflows/analyze.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 12247ab0..77d76a13 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -10,6 +10,7 @@ on:
- 'brut.apktool/apktool-lib/src/main/resources/**'
- 'brut.apktool/apktool-lib/src/test/**'
- '.github/workflows/**'
+ - 'gradle/libs.versions.toml'
- 'gradle/wrapper/**'
- 'gradlew'
- 'gradlew.bat'
@@ -27,7 +28,7 @@ jobs:
matrix:
file: [ aapt_64, aapt2_64 ]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Verify Executable
run: ${{ env.BINARY_PATH }}/macosx/${{ matrix.file }} version
- name: Output Static
@@ -39,7 +40,7 @@ jobs:
matrix:
file: [ aapt, aapt_64, aapt2, aapt2_64 ]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Verify Executable
run: ${{ env.BINARY_PATH }}/linux/${{ matrix.file }} version
- name: Output Static
@@ -51,7 +52,7 @@ jobs:
matrix:
file: [ aapt.exe, aapt_64.exe, aapt2.exe, aapt2_64.exe ]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Verify Executable
run: ${{ env.BINARY_PATH }}/windows/${{ matrix.file }} version
- name: Output Static
@@ -70,13 +71,13 @@ jobs:
os: [ ubuntu-latest, macOS-latest, windows-latest ]
java: [ 8, 11, 17, 18, 19, 20 ]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: ${{ matrix.java }}
- name: Build and test
- uses: gradle/gradle-build-action@v2.7.1
+ uses: gradle/gradle-build-action@v2.9.0
with:
arguments: build shadowJar proguard
@@ -87,7 +88,7 @@ jobs:
needs:
- build-and-test-with-Java-8-and-later
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-java@v3
@@ -95,8 +96,9 @@ jobs:
distribution: 'zulu'
java-version: 17
- name: Build
- uses: gradle/gradle-build-action@v2.7.1
+ uses: gradle/gradle-build-action@v2.9.0
with:
+ dependency-graph: generate-and-submit
arguments: build shadowJar proguard
- name: Upload
uses: actions/upload-artifact@v3
diff --git a/.github/workflows/docker-beta.yml b/.github/workflows/docker-beta.yml
new file mode 100644
index 00000000..08ce80f4
--- /dev/null
+++ b/.github/workflows/docker-beta.yml
@@ -0,0 +1,47 @@
+name: Build and push docker (beta)
+
+on:
+ pull_request:
+ branches: [master]
+ types: [closed]
+
+env:
+ REGISTRY: ghcr.io
+ IMAGE_NAME: ibotpeaches/apktool
+
+jobs:
+
+ build_and_push:
+ name: Build and push
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Log in to the Container registry
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Get hash
+ id: hash
+ run: echo "APKTOOL_HASH=$(echo $GITHUB_SHA | cut -c 1-6)" >> $GITHUB_ENV
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v4
+ with:
+ context: .
+ platforms: linux/amd64
+ file: ./docker/Dockerfile
+ push: true
+ tags: |
+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.APKTOOL_HASH }}
+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:beta
+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:master
diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml
new file mode 100644
index 00000000..ed979bbc
--- /dev/null
+++ b/.github/workflows/docker-release.yml
@@ -0,0 +1,50 @@
+name: Build and push docker (release)
+
+on:
+ release:
+ types: [published]
+
+env:
+ REGISTRY: ghcr.io
+ IMAGE_NAME: ibotpeaches/apktool
+
+jobs:
+ build_and_push:
+ name: Build and push
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Log in to the Container registry
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Get hash
+ id: hash
+ run: echo "APKTOOL_HASH=$(echo $GITHUB_SHA | cut -c 1-6)" >> $GITHUB_ENV
+
+ - name: Get release tag
+ id: tag
+ run: echo "APKTOOL_TAG=$(echo ${GITHUB_REF:-no-tag} |sed 's|refs/tags/||g')" >> $GITHUB_ENV
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v4
+ with:
+ context: .
+ platforms: linux/amd64
+ file: ./docker/Dockerfile
+ push: true
+ tags: |
+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.APKTOOL_HASH }}
+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.APKTOOL_TAG }}
+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:prod
+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
index 3fad6652..592a77cb 100644
--- a/.github/workflows/gradle.yml
+++ b/.github/workflows/gradle.yml
@@ -16,7 +16,7 @@ jobs:
validate-gradle-wrapper:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
diff --git a/INTERNAL.md b/INTERNAL.md
index f8189920..13be348e 100644
--- a/INTERNAL.md
+++ b/INTERNAL.md
@@ -251,8 +251,8 @@ we aren't building the entire AOSP package, the initial build is to just see if
We check out a certain tag or branch. Currently we use
- * aapt2 - `master`.
- * aapt1 - `master`.
+ * aapt2 - `android-14.0.0_r2`.
+ * aapt1 - `android-14.0.0_r2`.
### Including our modified `frameworks/base` package.
diff --git a/README.md b/README.md
index f0b88302..7d26c9f8 100644
--- a/README.md
+++ b/README.md
@@ -12,14 +12,6 @@ It is NOT intended for piracy and other non-legal uses. It could be used for loc
- [Project Page](https://ibotpeaches.github.io/Apktool/)
- [#apktool on libera.chat](https://web.libera.chat/)
-#### Sponsored by
-
-* [Sourcetoad](https://www.sourcetoad.com/cool-tools/apktool/) - helping with a weekly sponsorship for continued improvement and maintenance of the project.
-
-#### IDE of Choice
-
-* [JetBrains IntelliJ](https://www.jetbrains.com/idea/)
-
#### Security Vulnerabilities
If you discover a security vulnerability within Apktool, please send an e-mail to Connor Tumbleson at connor.tumbleson(at)gmail.com. All security vulnerabilities will be promptly addressed.
@@ -29,9 +21,35 @@ If you discover a security vulnerability within Apktool, please send an e-mail t
- [Downloads Mirror](https://connortumbleson.com/apktool/)
- [How to Build](https://ibotpeaches.github.io/Apktool/build/)
- [Documentation](https://ibotpeaches.github.io/Apktool/documentation/)
+- [Use in Docker](./docker/README.md)
- [Bug Reports](https://github.com/iBotPeaches/Apktool/issues)
- [Changelog/Information](https://ibotpeaches.github.io/Apktool/changes/)
- [XDA Post](https://forum.xda-developers.com/t/util-dec-2-2020-apktool-tool-for-reverse-engineering-apk-files.1755243/)
- [Source (Github)](https://github.com/iBotPeaches/Apktool)
- [Source (Bitbucket)](https://bitbucket.org/iBotPeaches/apktool/)
+
+## Sponsors
+
+Special thanks goes to the following sponsors:
+
+### Sourcetoad
+[Sourcetoad](https://sourcetoad.com/) is an award-winning software and app development firm committed to the co-creation of technology solutions that solve complex business problems, delight users, and help our clients achieve their goals.
+
+
+
+
+
+
+
+### Emerge Tools
+
+[Emerge Tools](https://www.emergetools.com) is a suite of revolutionary products designed to supercharge mobile apps and the teams that build them.
+
+
+
+
+
+
+
+
diff --git a/brut.apktool/apktool-cli/build.gradle.kts b/brut.apktool/apktool-cli/build.gradle.kts
index 722e8924..f9070836 100644
--- a/brut.apktool/apktool-cli/build.gradle.kts
+++ b/brut.apktool/apktool-cli/build.gradle.kts
@@ -1,10 +1,9 @@
import proguard.gradle.ProGuardTask
-val commonsCliVersion: String by rootProject.extra
val apktoolVersion: String by rootProject.extra
plugins {
- id("com.github.johnrengelman.shadow")
+ alias(libs.plugins.shadow)
application
}
@@ -14,12 +13,12 @@ plugins {
buildscript {
dependencies {
// Proguard doesn't support plugin DSL - https://github.com/Guardsquare/proguard/issues/225
- classpath("com.guardsquare:proguard-gradle:7.3.2")
+ classpath(libs.proguard)
}
}
dependencies {
- implementation("commons-cli:commons-cli:$commonsCliVersion")
+ implementation(libs.commons.cli)
implementation(project(":brut.apktool:apktool-lib"))
}
diff --git a/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java b/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java
index 396406aa..e10ed961 100644
--- a/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java
+++ b/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java
@@ -55,7 +55,7 @@ public class Main {
CommandLine commandLine;
// load options
- _Options();
+ _options();
try {
commandLine = parser.parse(allOptions, args, false);
@@ -167,6 +167,34 @@ public class Main {
if (cli.hasOption("m") || cli.hasOption("match-original")) {
config.analysisMode = true;
}
+ if (cli.hasOption("resm") || cli.hasOption("res-mode") || cli.hasOption("resolve-resources-mode")) {
+ String mode = cli.getOptionValue("resm");
+ if (mode == null) {
+ mode = cli.getOptionValue("res-mode");
+ }
+ if (mode == null) {
+ mode = cli.getOptionValue("resolve-resources-mode");
+ }
+
+ switch (mode) {
+ case "remove":
+ case "delete":
+ config.setDecodeResolveMode(Config.DECODE_RES_RESOLVE_REMOVE);
+ break;
+ case "dummy":
+ case "dummies":
+ config.setDecodeResolveMode(Config.DECODE_RES_RESOLVE_DUMMY);
+ break;
+ case "keep":
+ case "preserve":
+ config.setDecodeResolveMode(Config.DECODE_RES_RESOLVE_RETAIN);
+ break;
+ default:
+ System.err.println("Unknown resolve resources mode: " + mode);
+ System.err.println("Expect: 'remove', 'dummy' or 'keep'.");
+ System.exit(1);
+ }
+ }
File outDir;
if (cli.hasOption("o") || cli.hasOption("output")) {
@@ -239,11 +267,13 @@ public class Main {
if (cli.hasOption("nc") || cli.hasOption("no-crunch")) {
config.noCrunch = true;
}
+ if (cli.hasOption("use-aapt1")) {
+ config.useAapt2 = false;
+ }
- // Temporary flag to enable the use of aapt2. This will transform in time to a use-aapt1 flag, which will be
- // legacy and eventually removed.
- if (cli.hasOption("use-aapt2")) {
- config.useAapt2 = true;
+ if (cli.hasOption("use-aapt1") && cli.hasOption("use-aapt2")) {
+ System.err.println("You can only use one of --use-aapt1 or --use-aapt2.");
+ System.exit(1);
}
File outFile;
@@ -300,9 +330,7 @@ public class Main {
System.out.println(ApktoolProperties.getVersion());
}
- private static void _Options() {
-
- // create options
+ private static void _options() {
Option versionOption = Option.builder("version")
.longOpt("version")
.desc("Print the version.")
@@ -409,6 +437,13 @@ public class Main {
.desc("Skip changes detection and build all files.")
.build();
+ Option resolveResModeOption = Option.builder("resm")
+ .longOpt("resource-mode")
+ .desc("Sets the resolve resources mode. Possible values are: 'remove' (default), 'dummy' or 'keep'.")
+ .hasArg(true)
+ .argName("mode")
+ .build();
+
Option aaptOption = Option.builder("a")
.longOpt("aapt")
.hasArg(true)
@@ -416,9 +451,14 @@ public class Main {
.desc("Load aapt from specified location.")
.build();
+ Option aapt1Option = Option.builder()
+ .longOpt("use-aapt1")
+ .desc("Use aapt binary instead of aapt2 during the build step.")
+ .build();
+
Option aapt2Option = Option.builder()
.longOpt("use-aapt2")
- .desc("Use aapt2 binary instead of aapt1 during the build step.")
+ .desc("Use aapt2 binary instead of aapt during the build step.")
.build();
Option originalOption = Option.builder("c")
@@ -469,13 +509,14 @@ public class Main {
decodeOptions.addOption(apiLevelOption);
decodeOptions.addOption(noAssetOption);
decodeOptions.addOption(forceManOption);
+ decodeOptions.addOption(resolveResModeOption);
buildOptions.addOption(apiLevelOption);
buildOptions.addOption(debugBuiOption);
buildOptions.addOption(netSecConfOption);
buildOptions.addOption(aaptOption);
buildOptions.addOption(originalOption);
- buildOptions.addOption(aapt2Option);
+ buildOptions.addOption(aapt1Option);
buildOptions.addOption(noCrunchOption);
}
@@ -525,6 +566,7 @@ public class Main {
allOptions.addOption(debugDecOption);
allOptions.addOption(noDbgOption);
allOptions.addOption(forceManOption);
+ allOptions.addOption(resolveResModeOption);
allOptions.addOption(noAssetOption);
allOptions.addOption(keepResOption);
allOptions.addOption(debugBuiOption);
@@ -533,6 +575,7 @@ public class Main {
allOptions.addOption(originalOption);
allOptions.addOption(verboseOption);
allOptions.addOption(quietOption);
+ allOptions.addOption(aapt1Option);
allOptions.addOption(aapt2Option);
allOptions.addOption(noCrunchOption);
allOptions.addOption(onlyMainClassesOption);
@@ -547,7 +590,7 @@ public class Main {
}
private static void usage() {
- _Options();
+ _options();
HelpFormatter formatter = new HelpFormatter();
formatter.setWidth(120);
@@ -592,11 +635,18 @@ public class Main {
return;
}
- Handler handler = new Handler(){
+ Handler handler = new Handler() {
@Override
public void publish(LogRecord record) {
if (getFormatter() == null) {
- setFormatter(new SimpleFormatter());
+ setFormatter(new Formatter() {
+ @Override
+ public String format(LogRecord record) {
+ return record.getLevel().toString().charAt(0) + ": "
+ + record.getMessage()
+ + System.getProperty("line.separator");
+ }
+ });
}
try {
@@ -616,6 +666,7 @@ public class Main {
reportError(null, exception, ErrorManager.FORMAT_FAILURE);
}
}
+
@Override
public void close() throws SecurityException {}
@Override
@@ -627,15 +678,6 @@ public class Main {
if (verbosity == Verbosity.VERBOSE) {
handler.setLevel(Level.ALL);
logger.setLevel(Level.ALL);
- } else {
- handler.setFormatter(new Formatter() {
- @Override
- public String format(LogRecord record) {
- return record.getLevel().toString().charAt(0) + ": "
- + record.getMessage()
- + System.getProperty("line.separator");
- }
- });
}
}
diff --git a/brut.apktool/apktool-lib/build.gradle.kts b/brut.apktool/apktool-lib/build.gradle.kts
index 349c5705..ab393934 100644
--- a/brut.apktool/apktool-lib/build.gradle.kts
+++ b/brut.apktool/apktool-lib/build.gradle.kts
@@ -1,13 +1,3 @@
-val baksmaliVersion: String by rootProject.extra
-val smaliVersion: String by rootProject.extra
-val xmlpullVersion: String by rootProject.extra
-val guavaVersion: String by rootProject.extra
-val commonsLangVersion: String by rootProject.extra
-val commonsIoVersion: String by rootProject.extra
-val commonsTextVersion: String by rootProject.extra
-val junitVersion: String by rootProject.extra
-val xmlunitVersion: String by rootProject.extra
-
val gitRevision: String by rootProject.extra
val apktoolVersion: String by rootProject.extra
@@ -53,16 +43,16 @@ dependencies {
api(project(":brut.j.util"))
api(project(":brut.j.common"))
- implementation("com.android.tools.smali:smali-baksmali:$baksmaliVersion")
- implementation("com.android.tools.smali:smali:$smaliVersion")
- implementation("xpp3:xpp3:$xmlpullVersion")
- implementation("com.google.guava:guava:$guavaVersion")
- implementation("org.apache.commons:commons-lang3:$commonsLangVersion")
- implementation("commons-io:commons-io:$commonsIoVersion")
- implementation("org.apache.commons:commons-text:$commonsTextVersion")
+ implementation(libs.baksmali)
+ implementation(libs.smali)
+ implementation(libs.xmlpull)
+ implementation(libs.guava)
+ implementation(libs.commons.lang3)
+ implementation(libs.commons.io)
+ implementation(libs.commons.text)
- testImplementation("junit:junit:$junitVersion")
- testImplementation("org.xmlunit:xmlunit-legacy:$xmlunitVersion")
+ testImplementation(libs.junit)
+ testImplementation(libs.xmlunit)
compileOnly(files(androidJarPath))
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java
index 31ad6b1b..492d52f6 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java
@@ -92,6 +92,7 @@ public class ApkDecoder {
} catch (BrutException ex) {
throw new AndrolibException(ex);
}
+ //noinspection ResultOfMethodCallIgnored
outDir.mkdirs();
LOGGER.info("Using Apktool " + ApktoolProperties.getVersion() + " on " + mApkInfo.apkFileName);
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Config.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Config.java
index 9aad41e1..2ffba37d 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Config.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Config.java
@@ -23,6 +23,7 @@ import java.io.File;
import java.util.logging.Logger;
public class Config {
+ private static Config instance = null;
private final static Logger LOGGER = Logger.getLogger(Config.class.getName());
public final static short DECODE_SOURCES_NONE = 0x0000;
@@ -38,6 +39,10 @@ public class Config {
public final static short DECODE_ASSETS_NONE = 0x0000;
public final static short DECODE_ASSETS_FULL = 0x0001;
+ public final static short DECODE_RES_RESOLVE_REMOVE = 0x0000;
+ public final static short DECODE_RES_RESOLVE_DUMMY = 0x0001;
+ public final static short DECODE_RES_RESOLVE_RETAIN = 0x0002;
+
// Build options
public boolean forceBuildAll = false;
public boolean forceDeleteFramework = false;
@@ -46,7 +51,7 @@ public class Config {
public boolean verbose = false;
public boolean copyOriginalFiles = false;
public boolean updateFiles = false;
- public boolean useAapt2 = false;
+ public boolean useAapt2 = true;
public boolean noCrunch = false;
public int forceApi = 0;
@@ -55,6 +60,7 @@ public class Config {
public short decodeResources = DECODE_RESOURCES_FULL;
public short forceDecodeManifest = FORCE_DECODE_MANIFEST_NONE;
public short decodeAssets = DECODE_ASSETS_FULL;
+ public short decodeResolveMode = DECODE_RES_RESOLVE_REMOVE;
public int apiLevel = 0;
public boolean analysisMode = false;
public boolean forceDelete = false;
@@ -72,8 +78,23 @@ public class Config {
return this.useAapt2 || this.aaptVersion == 2;
}
- private Config() {
+ public boolean isDecodeResolveModeUsingDummies() {
+ return decodeResolveMode == DECODE_RES_RESOLVE_DUMMY;
+ }
+ public boolean isDecodeResolveModeRemoving() {
+ return decodeResolveMode == DECODE_RES_RESOLVE_REMOVE;
+ }
+
+ private Config() {
+ instance = this;
+ }
+
+ public static Config getInstance() {
+ if (instance == null) {
+ instance = new Config();
+ }
+ return instance;
}
private void setDefaultFrameworkDirectory() {
@@ -105,6 +126,13 @@ public class Config {
decodeSources = mode;
}
+ public void setDecodeResolveMode(short mode) throws AndrolibException {
+ if (mode != DECODE_RES_RESOLVE_REMOVE && mode != DECODE_RES_RESOLVE_DUMMY && mode != DECODE_RES_RESOLVE_RETAIN) {
+ throw new AndrolibException("Invalid decode resources mode");
+ }
+ decodeResolveMode = mode;
+ }
+
public void setDecodeResources(short mode) throws AndrolibException {
if (mode != DECODE_RESOURCES_NONE && mode != DECODE_RESOURCES_FULL) {
throw new AndrolibException("Invalid decode resources mode");
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/ApkInfo.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/ApkInfo.java
index 99faee09..e7866360 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/ApkInfo.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/ApkInfo.java
@@ -191,6 +191,7 @@ public class ApkInfo implements YamlSerializable {
return ResConfigFlags.SDK_TIRAMISU;
case "UPSIDEDOWNCAKE":
case "UPSIDE_DOWN_CAKE":
+ return ResConfigFlags.SDK_UPSIDEDOWN_CAKE;
case "VANILLAICECREAM":
case "VANILLA_ICE_CREAM":
return ResConfigFlags.SDK_DEVELOPMENT;
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java
index 2c4ae0f8..1d27b77e 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java
@@ -32,6 +32,7 @@ public class ResConfigFlags {
public final byte keyboard;
public final byte navigation;
public final byte inputFlags;
+ public final byte grammaticalInflection;
public final short screenWidth;
public final short screenHeight;
@@ -70,6 +71,7 @@ public class ResConfigFlags {
keyboard = KEYBOARD_ANY;
navigation = NAVIGATION_ANY;
inputFlags = KEYSHIDDEN_ANY | NAVHIDDEN_ANY;
+ grammaticalInflection = GRAMMATICAL_GENDER_ANY;
screenWidth = 0;
screenHeight = 0;
sdkVersion = 0;
@@ -91,7 +93,7 @@ public class ResConfigFlags {
public ResConfigFlags(short mcc, short mnc, char[] language,
char[] region, byte orientation,
byte touchscreen, int density, byte keyboard, byte navigation,
- byte inputFlags, short screenWidth, short screenHeight,
+ byte inputFlags, byte grammaticalInflection, short screenWidth, short screenHeight,
short sdkVersion, byte screenLayout, byte uiMode,
short smallestScreenWidthDp, short screenWidthDp,
short screenHeightDp, char[] localeScript, char[] localeVariant,
@@ -149,6 +151,7 @@ public class ResConfigFlags {
this.keyboard = keyboard;
this.navigation = navigation;
this.inputFlags = inputFlags;
+ this.grammaticalInflection = grammaticalInflection;
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
this.sdkVersion = sdkVersion;
@@ -198,6 +201,18 @@ public class ResConfigFlags {
}
ret.append(getLocaleString());
+ switch (grammaticalInflection) {
+ case GRAMMATICAL_GENDER_NEUTER:
+ ret.append("-neuter");
+ break;
+ case GRAMMATICAL_GENDER_FEMININE:
+ ret.append("-feminine");
+ break;
+ case GRAMMATICAL_GENDER_MASCULINE:
+ ret.append("-masculine");
+ break;
+ }
+
switch (screenLayout & MASK_LAYOUTDIR) {
case SCREENLAYOUT_LAYOUTDIR_RTL:
ret.append("-ldrtl");
@@ -421,6 +436,9 @@ public class ResConfigFlags {
}
private short getNaturalSdkVersionRequirement() {
+ if (grammaticalInflection != 0) {
+ return SDK_UPSIDEDOWN_CAKE;
+ }
if ((uiMode & MASK_UI_MODE_TYPE) == UI_MODE_TYPE_VR_HEADSET || (colorMode & COLOR_WIDE_MASK) != 0 || ((colorMode & COLOR_HDR_MASK) != 0)) {
return SDK_OREO;
}
@@ -550,6 +568,7 @@ public class ResConfigFlags {
public final static byte SDK_S = 31;
public final static byte SDK_S_V2 = 32;
public final static byte SDK_TIRAMISU = 33;
+ public final static byte SDK_UPSIDEDOWN_CAKE = 34;
// AOSP has this as 10,000 for dev purposes.
// platform_frameworks_base/commit/c7a1109a1fe0771d4c9b572dcf178e2779fc4f2d
@@ -590,6 +609,11 @@ public class ResConfigFlags {
public final static short SCREENLAYOUT_ROUND_NO = 0x1;
public final static short SCREENLAYOUT_ROUND_YES = 0x2;
+ public final static byte GRAMMATICAL_GENDER_ANY = 0;
+ public final static byte GRAMMATICAL_GENDER_NEUTER = 1;
+ public final static byte GRAMMATICAL_GENDER_FEMININE = 2;
+ public final static byte GRAMMATICAL_GENDER_MASCULINE = 3;
+
public final static byte KEYBOARD_ANY = 0;
public final static byte KEYBOARD_NOKEYS = 1;
public final static byte KEYBOARD_QWERTY = 2;
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResSpec.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResSpec.java
index 338a4e9c..c12b8240 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResSpec.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResResSpec.java
@@ -105,6 +105,10 @@ public class ResResSpec {
return mType;
}
+ public boolean isDummyResSpec() {
+ return getName().startsWith("APKTOOL_DUMMY_");
+ }
+
public void addResource(ResResource res) throws AndrolibException {
addResource(res, false);
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java
index f4341d18..1c29ef4f 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java
@@ -70,6 +70,10 @@ public class ResTable {
return mConfig.analysisMode;
}
+ public Config getConfig() {
+ return mConfig;
+ }
+
public boolean isMainPkgLoaded() {
return mMainPkgLoaded;
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTypeSpec.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTypeSpec.java
index 72a97d50..f1b0cd24 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTypeSpec.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTypeSpec.java
@@ -23,9 +23,11 @@ import java.util.*;
public final class ResTypeSpec {
public static final String RES_TYPE_NAME_ARRAY = "array";
- public static final String RES_TYPE_NAME_PLURALS = "plurals";
- public static final String RES_TYPE_NAME_STYLES = "style";
public static final String RES_TYPE_NAME_ATTR = "attr";
+ public static final String RES_TYPE_NAME_ATTR_PRIVATE = "^attr-private";
+ public static final String RES_TYPE_NAME_PLURALS = "plurals";
+ public static final String RES_TYPE_NAME_STRING = "string";
+ public static final String RES_TYPE_NAME_STYLES = "style";
private final String mName;
private final Map mResSpecs = new LinkedHashMap<>();
@@ -46,7 +48,7 @@ public final class ResTypeSpec {
}
public boolean isString() {
- return mName.equalsIgnoreCase("string");
+ return mName.equalsIgnoreCase(RES_TYPE_NAME_STRING);
}
public ResResSpec getResSpec(String name) throws AndrolibException {
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/arsc/FlagItem.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/arsc/FlagItem.java
new file mode 100644
index 00000000..4c2dfb4a
--- /dev/null
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/arsc/FlagItem.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 Ryszard Wiśniewski
+ * Copyright (C) 2010 Connor Tumbleson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package brut.androlib.res.data.arsc;
+
+import brut.androlib.exceptions.AndrolibException;
+import brut.androlib.res.data.value.ResReferenceValue;
+
+public class FlagItem {
+ public final ResReferenceValue ref;
+ public final int flag;
+ public String value;
+
+ public FlagItem(ResReferenceValue ref, int flag) {
+ this.ref = ref;
+ this.flag = flag;
+ }
+
+ public String getValue() throws AndrolibException {
+ if (value == null) {
+ if (ref.referentIsNull()) {
+ return String.format("APKTOOL_MISSING_0x%08x", ref.getRawIntValue());
+ }
+ value = ref.getReferent().getName();
+ }
+ return value;
+ }
+}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResArrayValue.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResArrayValue.java
index 732d2e2d..2b1e2046 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResArrayValue.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResArrayValue.java
@@ -91,6 +91,4 @@ public class ResArrayValue extends ResBagValue implements ResValuesXmlSerializab
private final ResScalarValue[] mItems;
private final String[] AllowedArrayTypes = {"string", "integer"};
-
- public static final int BAG_KEY_ARRAY_START = 0x02000000;
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResAttr.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResAttr.java
index f47b2243..982a78c5 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResAttr.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResAttr.java
@@ -26,8 +26,7 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
- ResAttr(ResReferenceValue parentVal, int type, Integer min, Integer max,
- Boolean l10n) {
+ ResAttr(ResReferenceValue parentVal, int type, Integer min, Integer max, Boolean l10n) {
super(parentVal);
mType = type;
mMin = min;
@@ -64,38 +63,39 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
public static ResAttr factory(ResReferenceValue parent,
Duo[] items, ResValueFactory factory,
ResPackage pkg) throws AndrolibException {
-
- int type = ((ResIntValue) items[0].m2).getValue();
- int scalarType = type & 0xffff;
Integer min = null, max = null;
Boolean l10n = null;
int i;
for (i = 1; i < items.length; i++) {
switch (items[i].m1) {
case BAG_KEY_ATTR_MIN:
- min = ((ResIntValue) items[i].m2).getValue();
+ min = (items[i].m2).getRawIntValue();
continue;
case BAG_KEY_ATTR_MAX:
- max = ((ResIntValue) items[i].m2).getValue();
+ max = (items[i].m2).getRawIntValue();
continue;
case BAG_KEY_ATTR_L10N:
- l10n = ((ResIntValue) items[i].m2).getValue() != 0;
+ l10n = (items[i].m2).getRawIntValue() != 0;
continue;
}
break;
}
+ // #2806 - Make sure we handle int-based values and not just ResIntValue
+ int rawValue = items[0].m2.getRawIntValue();
+ int scalarType = rawValue & 0xffff;
+
if (i == items.length) {
return new ResAttr(parent, scalarType, min, max, l10n);
}
- Duo[] attrItems = new Duo[items.length - i];
+ Duo[] attrItems = new Duo[items.length - i];
int j = 0;
for (; i < items.length; i++) {
int resId = items[i].m1;
pkg.addSynthesizedRes(resId);
- attrItems[j++] = new Duo<>(factory.newReference(resId, null), (ResIntValue) items[i].m2);
+ attrItems[j++] = new Duo<>(factory.newReference(resId, null), items[i].m2);
}
- switch (type & 0xff0000) {
+ switch (rawValue & 0xff0000) {
case TYPE_ENUM:
return new ResEnumAttr(parent, scalarType, min, max, l10n, attrItems);
case TYPE_FLAGS:
@@ -145,7 +145,6 @@ public class ResAttr extends ResBagValue implements ResValuesXmlSerializable {
private final Integer mMax;
private final Boolean mL10n;
- public static final int BAG_KEY_ATTR_TYPE = 0x01000000;
private static final int BAG_KEY_ATTR_MIN = 0x01000001;
private static final int BAG_KEY_ATTR_MAX = 0x01000002;
private static final int BAG_KEY_ATTR_L10N = 0x01000003;
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResBagValue.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResBagValue.java
index faa36f81..ea77c39e 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResBagValue.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResBagValue.java
@@ -36,18 +36,15 @@ public class ResBagValue extends ResValue implements ResValuesXmlSerializable {
ResResource res) throws IOException, AndrolibException {
String type = res.getResSpec().getType().getName();
if ("style".equals(type)) {
- new ResStyleValue(mParent, new Duo[0], null)
- .serializeToResValuesXml(serializer, res);
+ new ResStyleValue(mParent, new Duo[0], null).serializeToResValuesXml(serializer, res);
return;
}
if ("array".equals(type)) {
- new ResArrayValue(mParent, new Duo[0]).serializeToResValuesXml(
- serializer, res);
+ new ResArrayValue(mParent, new Duo[0]).serializeToResValuesXml(serializer, res);
return;
}
if ("plurals".equals(type)) {
- new ResPluralsValue(mParent, new Duo[0]).serializeToResValuesXml(
- serializer, res);
+ new ResPluralsValue(mParent, new Duo[0]).serializeToResValuesXml(serializer, res);
return;
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResEnumAttr.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResEnumAttr.java
index 1cffc3b6..d8ffced4 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResEnumAttr.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResEnumAttr.java
@@ -25,10 +25,11 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
+import java.util.logging.Logger;
public class ResEnumAttr extends ResAttr {
ResEnumAttr(ResReferenceValue parent, int type, Integer min, Integer max,
- Boolean l10n, Duo[] items) {
+ Boolean l10n, Duo[] items) {
super(parent, type, min, max, l10n);
mItems = items;
}
@@ -46,15 +47,21 @@ public class ResEnumAttr extends ResAttr {
}
@Override
- protected void serializeBody(XmlSerializer serializer, ResResource res)
- throws AndrolibException, IOException {
- for (Duo duo : mItems) {
- int intVal = duo.m2.getValue();
+ protected void serializeBody(XmlSerializer serializer, ResResource res) throws AndrolibException, IOException {
+ for (Duo duo : mItems) {
+ int intVal = duo.m2.getRawIntValue();
+
+ // #2836 - Support skipping items if the resource cannot be identified.
ResResSpec m1Referent = duo.m1.getReferent();
+ if (m1Referent == null && shouldRemoveUnknownRes()) {
+ LOGGER.fine(String.format("null enum reference: m1=0x%08x(%s), m2=0x%08x(%s)",
+ duo.m1.getRawIntValue(), duo.m1.getType(), duo.m2.getRawIntValue(), duo.m2.getType()));
+ continue;
+ }
serializer.startTag(null, "enum");
serializer.attribute(null, "name",
- m1Referent != null ? m1Referent.getName() : "@null"
+ m1Referent != null ? m1Referent.getName() : String.format("APKTOOL_MISSING_0x%08x", duo.m1.getRawIntValue())
);
serializer.attribute(null, "value", String.valueOf(intVal));
serializer.endTag(null, "enum");
@@ -65,8 +72,8 @@ public class ResEnumAttr extends ResAttr {
String value2 = mItemsCache.get(value);
if (value2 == null) {
ResReferenceValue ref = null;
- for (Duo duo : mItems) {
- if (duo.m2.getValue() == value) {
+ for (Duo duo : mItems) {
+ if (duo.m2.getRawIntValue() == value) {
ref = duo.m1;
break;
}
@@ -79,6 +86,8 @@ public class ResEnumAttr extends ResAttr {
return value2;
}
- private final Duo[] mItems;
+ private final Duo[] mItems;
private final Map mItemsCache = new HashMap<>();
+
+ private static final Logger LOGGER = Logger.getLogger(ResEnumAttr.class.getName());
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResFlagsAttr.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResFlagsAttr.java
index d69ea509..c37519f6 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResFlagsAttr.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResFlagsAttr.java
@@ -17,28 +17,31 @@
package brut.androlib.res.data.value;
import brut.androlib.exceptions.AndrolibException;
+import brut.androlib.res.data.ResResSpec;
import brut.androlib.res.data.ResResource;
+import brut.androlib.res.data.arsc.FlagItem;
import brut.util.Duo;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.Arrays;
+import java.util.logging.Logger;
public class ResFlagsAttr extends ResAttr {
ResFlagsAttr(ResReferenceValue parent, int type, Integer min, Integer max,
- Boolean l10n, Duo[] items) {
+ Boolean l10n, Duo[] items) {
super(parent, type, min, max, l10n);
mItems = new FlagItem[items.length];
for (int i = 0; i < items.length; i++) {
- mItems[i] = new FlagItem(items[i].m1, items[i].m2.getValue());
+ mItems[i] = new FlagItem(items[i].m1, items[i].m2.getRawIntValue());
}
}
@Override
public String convertToResXmlFormat(ResScalarValue value)
throws AndrolibException {
- if(value instanceof ResReferenceValue) {
+ if (value instanceof ResReferenceValue) {
return value.encodeAsResXml();
}
if (!(value instanceof ResIntValue)) {
@@ -70,13 +73,19 @@ public class ResFlagsAttr extends ResAttr {
}
@Override
- protected void serializeBody(XmlSerializer serializer, ResResource res)
- throws AndrolibException, IOException {
+ protected void serializeBody(XmlSerializer serializer, ResResource res) throws AndrolibException, IOException {
for (FlagItem item : mItems) {
+ ResResSpec referent = item.ref.getReferent();
+
+ // #2836 - Support skipping items if the resource cannot be identified.
+ if (referent == null && shouldRemoveUnknownRes()) {
+ LOGGER.fine(String.format("null flag reference: 0x%08x(%s)", item.ref.getValue(), item.ref.getType()));
+ continue;
+ }
+
serializer.startTag(null, "flag");
serializer.attribute(null, "name", item.getValue());
- serializer.attribute(null, "value",
- String.format("0x%08x", item.flag));
+ serializer.attribute(null, "value", String.format("0x%08x", item.flag));
serializer.endTag(null, "flag");
}
}
@@ -130,24 +139,5 @@ public class ResFlagsAttr extends ResAttr {
private FlagItem[] mZeroFlags;
private FlagItem[] mFlags;
- private static class FlagItem {
- public final ResReferenceValue ref;
- public final int flag;
- public String value;
-
- public FlagItem(ResReferenceValue ref, int flag) {
- this.ref = ref;
- this.flag = flag;
- }
-
- public String getValue() throws AndrolibException {
- if (value == null) {
- if (ref.referentIsNull()) {
- return "@null";
- }
- value = ref.getReferent().getName();
- }
- return value;
- }
- }
+ private static final Logger LOGGER = Logger.getLogger(ResFlagsAttr.class.getName());
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResPluralsValue.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResPluralsValue.java
index 50b3cda5..34e90a42 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResPluralsValue.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResPluralsValue.java
@@ -25,10 +25,8 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
-public class ResPluralsValue extends ResBagValue implements
- ResValuesXmlSerializable {
- ResPluralsValue(ResReferenceValue parent,
- Duo[] items) {
+public class ResPluralsValue extends ResBagValue implements ResValuesXmlSerializable {
+ ResPluralsValue(ResReferenceValue parent, Duo[] items) {
super(parent);
mItems = new ResScalarValue[6];
@@ -59,6 +57,5 @@ public class ResPluralsValue extends ResBagValue implements
private final ResScalarValue[] mItems;
public static final int BAG_KEY_PLURALS_START = 0x01000004;
- public static final int BAG_KEY_PLURALS_END = 0x01000009;
private static final String[] QUANTITY_MAP = new String[] { "other", "zero", "one", "two", "few", "many" };
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResScalarValue.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResScalarValue.java
index 21978f77..30ee763b 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResScalarValue.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResScalarValue.java
@@ -81,6 +81,11 @@ public abstract class ResScalarValue extends ResIntBasedValue implements
}
}
+ // Dummy attributes should be - with type attribute
+ if (res.getResSpec().isDummyResSpec()) {
+ item = true;
+ }
+
// Android does not allow values (false) for ids.xml anymore
// https://issuetracker.google.com/issues/80475496
// But it decodes as a ResBoolean, which makes no sense. So force it to empty
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResStringValue.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResStringValue.java
index e9ccc684..0cbb49b4 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResStringValue.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResStringValue.java
@@ -25,7 +25,6 @@ import java.io.IOException;
import java.util.regex.Pattern;
public class ResStringValue extends ResScalarValue {
-
public ResStringValue(String value, int rawValue) {
this(value, rawValue, "string");
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResStyleValue.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResStyleValue.java
index ab8dc271..397431bf 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResStyleValue.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResStyleValue.java
@@ -26,10 +26,8 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.logging.Logger;
-public class ResStyleValue extends ResBagValue implements
- ResValuesXmlSerializable {
- ResStyleValue(ResReferenceValue parent,
- Duo[] items, ResValueFactory factory) {
+public class ResStyleValue extends ResBagValue implements ResValuesXmlSerializable {
+ ResStyleValue(ResReferenceValue parent, Duo[] items, ResValueFactory factory) {
super(parent);
mItems = new Duo[items.length];
@@ -53,7 +51,7 @@ public class ResStyleValue extends ResBagValue implements
ResResSpec spec = mItem.m1.getReferent();
if (spec == null) {
- LOGGER.fine(String.format("null reference: m1=0x%08x(%s), m2=0x%08x(%s)",
+ LOGGER.fine(String.format("null style reference: m1=0x%08x(%s), m2=0x%08x(%s)",
mItem.m1.getRawIntValue(), mItem.m1.getType(), mItem.m2.getRawIntValue(), mItem.m2.getType()));
continue;
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValue.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValue.java
index 1d12f497..dec2394e 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValue.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValue.java
@@ -16,6 +16,10 @@
*/
package brut.androlib.res.data.value;
-public class ResValue {
+import brut.androlib.Config;
+public class ResValue {
+ public boolean shouldRemoveUnknownRes() {
+ return Config.getInstance().isDecodeResolveModeRemoving();
+ }
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValueFactory.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValueFactory.java
index 99e6811c..052621e0 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValueFactory.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/value/ResValueFactory.java
@@ -80,39 +80,29 @@ public class ResValueFactory {
return new ResStringValue(value, rawValue);
}
- public ResBagValue bagFactory(int parent, Duo[] items, ResTypeSpec resTypeSpec) throws AndrolibException {
+ public ResBagValue bagFactory(int parent, Duo[] items, ResTypeSpec resTypeSpec)
+ throws AndrolibException {
ResReferenceValue parentVal = newReference(parent, null);
if (items.length == 0) {
return new ResBagValue(parentVal);
}
- int key = items[0].m1;
- if (key == ResAttr.BAG_KEY_ATTR_TYPE) {
- return ResAttr.factory(parentVal, items, this, mPackage);
- }
-
String resTypeName = resTypeSpec.getName();
- // Android O Preview added an unknown enum for c. This is hardcoded as 0 for now.
- if (ResTypeSpec.RES_TYPE_NAME_ARRAY.equals(resTypeName)
- || key == ResArrayValue.BAG_KEY_ARRAY_START || key == 0) {
- return new ResArrayValue(parentVal, items);
+ switch (resTypeName) {
+ case ResTypeSpec.RES_TYPE_NAME_ATTR:
+ case ResTypeSpec.RES_TYPE_NAME_ATTR_PRIVATE:
+ return ResAttr.factory(parentVal, items, this, mPackage);
+ case ResTypeSpec.RES_TYPE_NAME_ARRAY:
+ return new ResArrayValue(parentVal, items);
+ case ResTypeSpec.RES_TYPE_NAME_PLURALS:
+ return new ResPluralsValue(parentVal, items);
+ default:
+ if (resTypeName.startsWith(ResTypeSpec.RES_TYPE_NAME_STYLES)) {
+ return new ResStyleValue(parentVal, items, this);
+ }
+ throw new AndrolibException("unsupported res type name for bags. Found: " + resTypeName);
}
-
- if (ResTypeSpec.RES_TYPE_NAME_PLURALS.equals(resTypeName) ||
- (key >= ResPluralsValue.BAG_KEY_PLURALS_START && key <= ResPluralsValue.BAG_KEY_PLURALS_END)) {
- return new ResPluralsValue(parentVal, items);
- }
-
- if (ResTypeSpec.RES_TYPE_NAME_ATTR.equals(resTypeName)) {
- return new ResAttr(parentVal, 0, null, null, null);
- }
-
- if (resTypeName.startsWith(ResTypeSpec.RES_TYPE_NAME_STYLES)) {
- return new ResStyleValue(parentVal, items, this);
- }
-
- throw new AndrolibException("unsupported res type name for bags. Found: " + resTypeName);
}
public ResReferenceValue newReference(int resID, String rawValue) {
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java
index 38c20897..75d2fe62 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java
@@ -59,11 +59,11 @@ public class ARSCDecoder {
mIn = new ExtCountingDataInput(new LittleEndianDataInputStream(arscStream));
mResTable = resTable;
mKeepBroken = keepBroken;
+ mMissingResSpecMap = new LinkedHashMap<>();
}
private ResPackage[] readResourceTable() throws IOException, AndrolibException {
Set pkgs = new LinkedHashSet<>();
-
ResTypeSpec typeSpec;
int chunkNumber = 1;
@@ -118,6 +118,10 @@ public class ARSCDecoder {
}
}
+ if (mResTable.getConfig().isDecodeResolveModeUsingDummies() && mPkg != null && mPkg.getResSpecCount() > 0) {
+ addMissingResSpecs();
+ }
+
return pkgs.toArray(new ResPackage[0]);
}
@@ -207,7 +211,7 @@ public class ARSCDecoder {
mHeader.checkForUnreadHeader(mIn);
for (int i = 0; i < count; i++) {
- LOGGER.fine(String.format("Skipping staged alias stagedId (%h) finalId: %h", mIn.readInt(), mIn.readInt()));
+ LOGGER.fine(String.format("Staged alias: 0x%08x -> 0x%08x", mIn.readInt(), mIn.readInt()));
}
}
@@ -256,10 +260,16 @@ public class ARSCDecoder {
private ResType readTableType() throws IOException, AndrolibException {
checkChunkType(ARSCHeader.XML_TYPE_TYPE);
int typeId = mIn.readUnsignedByte() - mTypeIdOffset;
+
+ // #3311 - Some older applications have no TYPE_SPEC chunks, but still define TYPE chunks.
if (mResTypeSpecs.containsKey(typeId)) {
- mResId = (0xff000000 & mResId) | mResTypeSpecs.get(typeId).getId() << 16;
mTypeSpec = mResTypeSpecs.get(typeId);
+ } else {
+ mTypeSpec = new ResTypeSpec(mTypeNames.getString(typeId - 1), typeId);
+ addTypeSpec(mTypeSpec);
+ mPkg.addType(mTypeSpec);
}
+ mResId = (0xff000000 & mResId) | mTypeSpec.getId() << 16;
int typeFlags = mIn.readByte();
mIn.skipBytes(2); // reserved
@@ -270,16 +280,21 @@ public class ARSCDecoder {
mHeader.checkForUnreadHeader(mIn);
+ boolean isOffset16 = (typeFlags & TABLE_TYPE_FLAG_OFFSET16) != 0;
+ boolean isSparse = (typeFlags & TABLE_TYPE_FLAG_SPARSE) != 0;
+
// Be sure we don't poison mResTable by marking the application as sparse
// Only flag the ResTable as sparse if the main package is not loaded.
- if ((typeFlags & 0x01) != 0 && !mResTable.isMainPkgLoaded()) {
+ if (isSparse && !mResTable.isMainPkgLoaded()) {
mResTable.setSparseResources(true);
}
HashMap entryOffsetMap = new LinkedHashMap<>();
for (int i = 0; i < entryCount; i++) {
- if ((typeFlags & 0x01) != 0) {
+ if (isSparse) {
entryOffsetMap.put(mIn.readUnsignedShort(), mIn.readUnsignedShort());
+ } else if (isOffset16) {
+ entryOffsetMap.put(i, mIn.readUnsignedShort());
} else {
entryOffsetMap.put(i, mIn.readInt());
}
@@ -295,11 +310,13 @@ public class ARSCDecoder {
}
mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);
+ int noEntry = isOffset16 ? NO_ENTRY_OFFSET16 : NO_ENTRY;
for (int i : entryOffsetMap.keySet()) {
mResId = (mResId & 0xffff0000) | i;
int offset = entryOffsetMap.get(i);
- if (offset == NO_ENTRY) {
+ if (offset == noEntry) {
+ mMissingResSpecMap.put(mResId, typeId);
continue;
}
@@ -315,6 +332,8 @@ public class ARSCDecoder {
EntryData entryData = readEntryData();
if (entryData != null) {
readEntry(entryData);
+ } else {
+ mMissingResSpecMap.put(mResId, typeId);
}
}
@@ -329,17 +348,35 @@ public class ARSCDecoder {
private EntryData readEntryData() throws IOException, AndrolibException {
short size = mIn.readShort();
- if (size < 0) {
- throw new AndrolibException("Entry size is under 0 bytes.");
+ short flags = mIn.readShort();
+
+ boolean isComplex = (flags & ENTRY_FLAG_COMPLEX) != 0;
+ boolean isCompact = (flags & ENTRY_FLAG_COMPACT) != 0;
+
+ if (size < 0 && !isCompact) {
+ throw new AndrolibException("Entry size is under 0 bytes and not compactly packed.");
}
- short flags = mIn.readShort();
int specNamesId = mIn.readInt();
- if (specNamesId == NO_ENTRY) {
+ if (specNamesId == NO_ENTRY && !isCompact) {
return null;
}
- ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue() : readComplexEntry();
+ // #3366 - In a compactly packed entry, the key index is the size & type is higher 8 bits on flags.
+ // We assume a size of 8 bytes for compact entries and the specNamesId is the data itself encoded.
+ ResValue value;
+ if (isCompact) {
+ byte type = (byte) ((flags >> 8) & 0xFF);
+ value = readCompactValue(type, specNamesId);
+
+ // To keep code below happy - we know if compact that the size has the key index encoded.
+ specNamesId = size;
+ } else if (isComplex) {
+ value = readComplexEntry();
+ } else {
+ value = readValue();
+ }
+
// #2824 - In some applications the res entries are duplicated with the 2nd being malformed.
// AOSP skips this, so we will do the same.
if (value == null) {
@@ -402,6 +439,12 @@ public class ARSCDecoder {
resId = mIn.readInt();
resValue = readValue();
+ // #2824 - In some applications the res entries are duplicated with the 2nd being malformed.
+ // AOSP skips this, so we will do the same.
+ if (resValue == null) {
+ continue;
+ }
+
if (!(resValue instanceof ResScalarValue)) {
resValue = new ResStringValue(resValue.toString(), resValue.getRawIntValue());
}
@@ -411,6 +454,12 @@ public class ARSCDecoder {
return factory.bagFactory(parent, items, mTypeSpec);
}
+ private ResIntBasedValue readCompactValue(byte type, int data) throws AndrolibException {
+ return type == TypedValue.TYPE_STRING
+ ? mPkg.getValueFactory().factory(mTableStrings.getHTML(data), data)
+ : mPkg.getValueFactory().factory(type, data, null);
+ }
+
private ResIntBasedValue readValue() throws IOException, AndrolibException {
int size = mIn.readShort();
if (size < 8) {
@@ -464,11 +513,12 @@ public class ARSCDecoder {
byte keyboard = 0;
byte navigation = 0;
byte inputFlags = 0;
+ byte grammaticalInflection = 0;
if (size >= 20) {
keyboard = mIn.readByte();
navigation = mIn.readByte();
inputFlags = mIn.readByte();
- mIn.skipBytes(1); // inputPad0
+ grammaticalInflection = mIn.readByte();
read = 20;
}
@@ -526,6 +576,7 @@ public class ARSCDecoder {
}
int exceedingKnownSize = size - KNOWN_CONFIG_BYTES;
+
if (exceedingKnownSize > 0) {
byte[] buf = new byte[exceedingKnownSize];
read += exceedingKnownSize;
@@ -550,7 +601,7 @@ public class ARSCDecoder {
return new ResConfigFlags(mcc, mnc, language, country,
orientation, touchscreen, density, keyboard, navigation,
- inputFlags, screenWidth, screenHeight, sdkVersion,
+ inputFlags, grammaticalInflection, screenWidth, screenHeight, sdkVersion,
screenLayout, uiMode, smallestScreenWidthDp, screenWidthDp,
screenHeightDp, localeScript, localeVariant, screenLayout2,
colorMode, localeNumberingSystem, isInvalid, size);
@@ -589,6 +640,30 @@ public class ARSCDecoder {
mResTypeSpecs.put(resTypeSpec.getId(), resTypeSpec);
}
+ private void addMissingResSpecs() throws AndrolibException {
+ for (int resId : mMissingResSpecMap.keySet()) {
+ int typeId = mMissingResSpecMap.get(resId);
+ String resName = "APKTOOL_DUMMY_" + Integer.toHexString(resId);
+ ResID id = new ResID(resId);
+ ResResSpec spec = new ResResSpec(id, resName, mPkg, mResTypeSpecs.get(typeId));
+
+ // If we already have this resID don't add it again.
+ if (! mPkg.hasResSpec(id)) {
+ mPkg.addResSpec(spec);
+ spec.getType().addResSpec(spec);
+ ResType resType = mPkg.getOrCreateConfig(new ResConfigFlags());
+
+ // We are going to make dummy attributes a null reference (@null) now instead of a boolean false.
+ // This is because aapt2 is stricter when it comes to what we can put in an application.
+ ResValue value = new ResReferenceValue(mPkg, 0, "");
+
+ ResResource res = new ResResource(resType, spec, value);
+ resType.addResource(res);
+ spec.addResource(res);
+ }
+ }
+ }
+
private ARSCHeader nextChunk() throws IOException {
return mHeader = ARSCHeader.read(mIn);
}
@@ -614,15 +689,21 @@ public class ARSCDecoder {
private ResType mType;
private int mResId;
private int mTypeIdOffset = 0;
+ private final HashMap mMissingResSpecMap;
private final HashMap mResTypeSpecs = new HashMap<>();
private final static short ENTRY_FLAG_COMPLEX = 0x0001;
private final static short ENTRY_FLAG_PUBLIC = 0x0002;
private final static short ENTRY_FLAG_WEAK = 0x0004;
+ private final static short ENTRY_FLAG_COMPACT = 0x0008;
+
+ private final static short TABLE_TYPE_FLAG_SPARSE = 0x01;
+ private final static short TABLE_TYPE_FLAG_OFFSET16 = 0x02;
private static final int KNOWN_CONFIG_BYTES = 64;
private static final int NO_ENTRY = 0xFFFFFFFF;
+ private static final int NO_ENTRY_OFFSET16 = 0xFFFF;
private static final Logger LOGGER = Logger.getLogger(ARSCDecoder.class.getName());
}
diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/xml/ResXmlPatcher.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/xml/ResXmlPatcher.java
index 53cdf52c..0acd9328 100644
--- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/xml/ResXmlPatcher.java
+++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/xml/ResXmlPatcher.java
@@ -365,7 +365,7 @@ public final class ResXmlPatcher {
* @throws SAXException
* @throws ParserConfigurationException
*/
- private static Document loadDocument(File file)
+ public static Document loadDocument(File file)
throws IOException, SAXException, ParserConfigurationException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
diff --git a/brut.apktool/apktool-lib/src/main/resources/brut/androlib/android-framework.jar b/brut.apktool/apktool-lib/src/main/resources/brut/androlib/android-framework.jar
index 02854940..76974147 100644
Binary files a/brut.apktool/apktool-lib/src/main/resources/brut/androlib/android-framework.jar and b/brut.apktool/apktool-lib/src/main/resources/brut/androlib/android-framework.jar differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt b/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt
index 7036ca4e..ef14966a 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2 b/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2
index cc74c93a..4ba1e9fc 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2 and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2 differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2_64 b/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2_64
index 8705475f..a27b4b45 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2_64 and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt2_64 differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt_64 b/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt_64
index eb11fef5..6129b00a 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt_64 and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/linux/aapt_64 differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt2_64 b/brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt2_64
index a06b16f9..c9747ae5 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt2_64 and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt2_64 differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt_64 b/brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt_64
index e5eaa78b..8c2b9ee4 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt_64 and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/macosx/aapt_64 differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt.exe b/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt.exe
index a45deb20..c50197f4 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt.exe and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt.exe differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2.exe b/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2.exe
index 21a2b115..f8b25f07 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2.exe and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2.exe differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2_64.exe b/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2_64.exe
index 8eb97245..0c8690e4 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2_64.exe and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt2_64.exe differ
diff --git a/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt_64.exe b/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt_64.exe
index 9f667d55..3c9e54b7 100755
Binary files a/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt_64.exe and b/brut.apktool/apktool-lib/src/main/resources/prebuilt/windows/aapt_64.exe differ
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/BaseTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/BaseTest.java
index acc8785c..12d3a351 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/BaseTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/BaseTest.java
@@ -22,6 +22,7 @@ import brut.directory.ExtFile;
import brut.directory.FileDirectory;
import org.custommonkey.xmlunit.*;
import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
@@ -155,6 +156,17 @@ public class BaseTest {
}
}
+ protected static int getStringEntryCount(Document doc, String key) {
+ int count = 0;
+ Element resources = doc.getDocumentElement();
+ for (int i = 0; i < resources.getChildNodes().getLength(); i++) {
+ if (resources.getChildNodes().item(i).getNodeName().equals(key)) {
+ count++;
+ }
+ }
+ return count;
+ }
+
protected static ExtFile sTmpDir;
protected static ExtFile sTestOrigDir;
protected static ExtFile sTestNewDir;
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/TestUtils.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/TestUtils.java
index b2b9d2a5..855326ff 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/TestUtils.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/TestUtils.java
@@ -18,15 +18,19 @@ package brut.androlib;
import brut.androlib.exceptions.AndrolibException;
import brut.androlib.res.Framework;
+import brut.androlib.res.xml.ResXmlPatcher;
import brut.common.BrutException;
import brut.directory.DirUtil;
import brut.directory.Directory;
import brut.directory.FileDirectory;
import brut.util.OS;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
+import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
@@ -77,6 +81,14 @@ public abstract class TestUtils {
}
}
+ public static Document getDocumentFromFile(File file) throws BrutException {
+ try {
+ return ResXmlPatcher.loadDocument(file);
+ } catch (ParserConfigurationException | SAXException | IOException ex) {
+ throw new BrutException(ex);
+ }
+ }
+
public static void copyResourceDir(Class> class_, String dirPath, File out) throws BrutException {
if (!out.exists()) {
out.mkdirs();
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/AndroidOreoNotSparseTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/AndroidOreoNotSparseTest.java
index fbbc5b2d..e13deccd 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/AndroidOreoNotSparseTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/AndroidOreoNotSparseTest.java
@@ -47,6 +47,7 @@ public class AndroidOreoNotSparseTest extends BaseTest {
LOGGER.info("Building not_sparse.apk...");
Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
new ApkBuilder(config, sTestNewDir).build(testApk);
}
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/AndroidOreoSparseTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/AndroidOreoSparseTest.java
index 0acfe7aa..94619167 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/AndroidOreoSparseTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/AndroidOreoSparseTest.java
@@ -47,6 +47,7 @@ public class AndroidOreoSparseTest extends BaseTest {
LOGGER.info("Building sparse.apk...");
Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
new ApkBuilder(config, sTestNewDir).build(testApk);
}
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/BuildAndDecodeJarTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/BuildAndDecodeJarTest.java
index ef858865..2de35510 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/BuildAndDecodeJarTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/BuildAndDecodeJarTest.java
@@ -16,10 +16,7 @@
*/
package brut.androlib.aapt1;
-import brut.androlib.ApkBuilder;
-import brut.androlib.ApkDecoder;
-import brut.androlib.BaseTest;
-import brut.androlib.TestUtils;
+import brut.androlib.*;
import brut.directory.ExtFile;
import brut.common.BrutException;
import brut.util.OS;
@@ -44,7 +41,9 @@ public class BuildAndDecodeJarTest extends BaseTest {
LOGGER.info("Building testjar.jar...");
File testJar = new File(sTmpDir, "testjar.jar");
- new ApkBuilder(sTestOrigDir).build(testJar);
+ Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
+ new ApkBuilder(config, sTestOrigDir).build(testJar);
LOGGER.info("Decoding testjar.jar...");
ApkDecoder apkDecoder = new ApkDecoder(testJar);
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/BuildAndDecodeTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/BuildAndDecodeTest.java
index 99117e21..316b9644 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/BuildAndDecodeTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/BuildAndDecodeTest.java
@@ -16,10 +16,7 @@
*/
package brut.androlib.aapt1;
-import brut.androlib.ApkBuilder;
-import brut.androlib.ApkDecoder;
-import brut.androlib.BaseTest;
-import brut.androlib.TestUtils;
+import brut.androlib.*;
import brut.androlib.apk.ApkInfo;
import brut.common.BrutException;
import brut.directory.ExtFile;
@@ -52,7 +49,9 @@ public class BuildAndDecodeTest extends BaseTest {
LOGGER.info("Building testapp.apk...");
File testApk = new File(sTmpDir, "testapp.apk");
- new ApkBuilder(sTestOrigDir).build(testApk);
+ Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
+ new ApkBuilder(config, sTestOrigDir).build(testApk);
LOGGER.info("Decoding testapp.apk...");
ApkDecoder apkDecoder = new ApkDecoder(testApk);
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/DebugTagRetainedTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/DebugTagRetainedTest.java
index 1ae1d68c..9c63aa29 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/DebugTagRetainedTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/DebugTagRetainedTest.java
@@ -48,6 +48,7 @@ public class DebugTagRetainedTest extends BaseTest {
LOGGER.info("Building issue1235.apk...");
Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
config.debugMode = true;
File testApk = new File(sTmpDir, "issue1235.apk");
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/DefaultBaksmaliVariableTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/DefaultBaksmaliVariableTest.java
index 2173efcf..ccdd9b1c 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/DefaultBaksmaliVariableTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/DefaultBaksmaliVariableTest.java
@@ -16,10 +16,7 @@
*/
package brut.androlib.aapt1;
-import brut.androlib.ApkBuilder;
-import brut.androlib.ApkDecoder;
-import brut.androlib.BaseTest;
-import brut.androlib.TestUtils;
+import brut.androlib.*;
import brut.common.BrutException;
import brut.directory.ExtFile;
import brut.util.OS;
@@ -46,7 +43,9 @@ public class DefaultBaksmaliVariableTest extends BaseTest {
LOGGER.info("Building issue1481.jar...");
File testJar = new File(sTmpDir, "issue1481.jar");
- new ApkBuilder(sTestOrigDir).build(testJar);
+ Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
+ new ApkBuilder(config, sTestOrigDir).build(testJar);
LOGGER.info("Decoding issue1481.jar...");
ApkDecoder apkDecoder = new ApkDecoder(testJar);
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/EmptyResourcesArscTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/EmptyResourcesArscTest.java
index fc37fff9..240d3040 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/EmptyResourcesArscTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/EmptyResourcesArscTest.java
@@ -50,6 +50,7 @@ public class EmptyResourcesArscTest {
LOGGER.info("Building issue1730.apk...");
Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
new ApkBuilder(config, sTestNewDir).build(testApk);
}
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/decode/ExternalEntityTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/ExternalEntityTest.java
similarity index 93%
rename from brut.apktool/apktool-lib/src/test/java/brut/androlib/decode/ExternalEntityTest.java
rename to brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/ExternalEntityTest.java
index 60232eca..4c673958 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/decode/ExternalEntityTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/ExternalEntityTest.java
@@ -14,12 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package brut.androlib.decode;
+package brut.androlib.aapt1;
-import brut.androlib.ApkBuilder;
-import brut.androlib.ApkDecoder;
-import brut.androlib.BaseTest;
-import brut.androlib.TestUtils;
+import brut.androlib.*;
import brut.directory.ExtFile;
import brut.common.BrutException;
import brut.util.OS;
@@ -43,7 +40,9 @@ public class ExternalEntityTest extends BaseTest {
LOGGER.info("Building doctype.apk...");
File testApk = new File(sTestOrigDir, "doctype.apk");
- new ApkBuilder(sTestOrigDir).build(testApk);
+ Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
+ new ApkBuilder(config, sTestOrigDir).build(testApk);
LOGGER.info("Decoding doctype.apk...");
ApkDecoder apkDecoder = new ApkDecoder(testApk);
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/LargeIntsInManifestTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/LargeIntsInManifestTest.java
index 3481dc23..c8e4574c 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/LargeIntsInManifestTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/LargeIntsInManifestTest.java
@@ -16,10 +16,7 @@
*/
package brut.androlib.aapt1;
-import brut.androlib.ApkBuilder;
-import brut.androlib.ApkDecoder;
-import brut.androlib.BaseTest;
-import brut.androlib.TestUtils;
+import brut.androlib.*;
import brut.directory.ExtFile;
import brut.common.BrutException;
import brut.util.OS;
@@ -54,8 +51,10 @@ public class LargeIntsInManifestTest extends BaseTest {
apkDecoder.decode(outDir);
// build issue767
+ Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
ExtFile testApk = new ExtFile(sTmpDir, apk + ".out");
- new ApkBuilder(testApk).build(null);
+ new ApkBuilder(config, testApk).build(null);
String newApk = apk + ".out" + File.separator + "dist" + File.separator + apk;
// decode issue767 again
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/ProviderAttributeTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/ProviderAttributeTest.java
index abc724dd..35a9ba9a 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/ProviderAttributeTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/ProviderAttributeTest.java
@@ -16,10 +16,7 @@
*/
package brut.androlib.aapt1;
-import brut.androlib.ApkBuilder;
-import brut.androlib.ApkDecoder;
-import brut.androlib.BaseTest;
-import brut.androlib.TestUtils;
+import brut.androlib.*;
import brut.directory.ExtFile;
import brut.common.BrutException;
import brut.util.OS;
@@ -62,7 +59,9 @@ public class ProviderAttributeTest extends BaseTest {
// build issue636
ExtFile testApk = new ExtFile(sTmpDir, apk + ".out");
- new ApkBuilder(testApk).build(null);
+ Config config = Config.getDefaultConfig();
+ config.useAapt2 = false;
+ new ApkBuilder(config, testApk).build(null);
String newApk = apk + ".out" + File.separator + "dist" + File.separator + apk;
assertTrue(fileExists(newApk));
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/SharedLibraryTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/SharedLibraryTest.java
index bc59d963..bc7b44f2 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/SharedLibraryTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/SharedLibraryTest.java
@@ -81,6 +81,7 @@ public class SharedLibraryTest extends BaseTest {
Config config = Config.getDefaultConfig();
config.frameworkDirectory = sTmpDir.getAbsolutePath();
config.frameworkTag = "shared";
+ config.useAapt2 = false;
// install library/framework
new Framework(config).installFramework(new File(sTmpDir + File.separator + library));
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/UnknownCompressionTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/UnknownCompressionTest.java
index dda7c3c5..5e087db2 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/UnknownCompressionTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt1/UnknownCompressionTest.java
@@ -42,6 +42,7 @@ public class UnknownCompressionTest extends BaseTest {
String apk = "deflated_unknowns.apk";
Config config = Config.getDefaultConfig();
config.frameworkDirectory = sTmpDir.getAbsolutePath();
+ config.useAapt2 = false;
sTestOrigDir = new ExtFile(sTmpDir, apk);
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/BuildAndDecodeTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/BuildAndDecodeTest.java
index d5720829..a0aa8048 100644
--- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/BuildAndDecodeTest.java
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/aapt2/BuildAndDecodeTest.java
@@ -86,6 +86,12 @@ public class BuildAndDecodeTest extends BaseTest {
compareValuesFiles("values-b+iw+660/strings.xml");
}
+ @Test
+ public void valuesGrammaticalGenderTest() throws BrutException {
+ compareValuesFiles("values-neuter/strings.xml");
+ compareValuesFiles("values-feminine/strings.xml");
+ }
+
@Test
public void valuesBcp47LanguageScriptRegionVariantTest() throws BrutException {
compareValuesFiles("values-b+ast+Latn+IT+AREVELA/strings.xml");
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/decode/CompactResourceTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/decode/CompactResourceTest.java
new file mode 100644
index 00000000..5b4ad679
--- /dev/null
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/decode/CompactResourceTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 Ryszard Wiśniewski
+ * Copyright (C) 2010 Connor Tumbleson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package brut.androlib.decode;
+
+import brut.androlib.*;
+import brut.directory.ExtFile;
+import brut.common.BrutException;
+import brut.util.OS;
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.*;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import static org.junit.Assert.*;
+
+public class CompactResourceTest extends BaseTest {
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ TestUtils.cleanFrameworkFile();
+ sTmpDir = new ExtFile(OS.createTempDirectory());
+ TestUtils.copyResourceDir(CompactResourceTest.class, "decode/issue3366/", sTmpDir);
+ }
+
+ @AfterClass
+ public static void afterClass() throws BrutException {
+ OS.rmdir(sTmpDir);
+ }
+
+ @Test
+ public void checkIfDecodeSucceeds() throws BrutException, IOException, ParserConfigurationException, SAXException {
+ String apk = "issue3366.apk";
+ File testApk = new File(sTmpDir, apk);
+
+ // decode issue3366.apk
+ ApkDecoder apkDecoder = new ApkDecoder(testApk);
+ sTestOrigDir = new ExtFile(sTmpDir + File.separator + apk + ".out");
+
+ File outDir = new File(sTmpDir + File.separator + apk + ".out");
+ apkDecoder.decode(outDir);
+
+ Document doc = loadDocument(new File(sTestOrigDir + "/res/values/strings.xml"));
+ assertEquals(1002, getStringEntryCount(doc, "string"));
+
+ Config config = Config.getDefaultConfig();
+ LOGGER.info("Building duplicatedex.apk...");
+ new ApkBuilder(config, sTestOrigDir).build(testApk);
+ }
+}
diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/decode/ResourceModeTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/decode/ResourceModeTest.java
new file mode 100644
index 00000000..1fbe855d
--- /dev/null
+++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/decode/ResourceModeTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 Ryszard Wiśniewski
+ * Copyright (C) 2010 Connor Tumbleson
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package brut.androlib.decode;
+
+import brut.androlib.ApkDecoder;
+import brut.androlib.BaseTest;
+import brut.androlib.Config;
+import brut.androlib.TestUtils;
+import brut.directory.ExtFile;
+import brut.common.BrutException;
+import brut.util.OS;
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.*;
+import org.w3c.dom.Document;
+
+import static org.junit.Assert.*;
+
+public class ResourceModeTest extends BaseTest {
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ TestUtils.cleanFrameworkFile();
+ sTmpDir = new ExtFile(OS.createTempDirectory());
+ TestUtils.copyResourceDir(ResourceModeTest.class, "decode/issue2836/", sTmpDir);
+ }
+
+ @AfterClass
+ public static void afterClass() throws BrutException {
+ OS.rmdir(sTmpDir);
+ }
+
+ @Test
+ public void checkDecodingModeAsRemove() throws BrutException, IOException {
+ String apk = "issue2836.apk";
+
+ Config config = Config.getDefaultConfig();
+ config.setDecodeResolveMode(Config.DECODE_RES_RESOLVE_REMOVE);
+
+ // decode issue2836.apk
+ ApkDecoder apkDecoder = new ApkDecoder(config, new File(sTmpDir + File.separator + apk));
+ sTestOrigDir = new ExtFile(sTmpDir + File.separator + apk + "remove.out");
+
+ File outDir = new File(sTmpDir + File.separator + apk + "remove.out");
+ apkDecoder.decode(outDir);
+
+ File stringsXml = new File(sTestOrigDir,"res/values/strings.xml");
+ assertTrue(stringsXml.isFile());
+
+ File attrXml = new File(sTestOrigDir,"res/values/attrs.xml");
+ Document attrDocument = TestUtils.getDocumentFromFile(attrXml);
+ assertEquals(3, attrDocument.getElementsByTagName("enum").getLength());
+
+ File colorXml = new File(sTestOrigDir,"res/values/colors.xml");
+ Document colorDocument = TestUtils.getDocumentFromFile(colorXml);
+ assertEquals(8, colorDocument.getElementsByTagName("color").getLength());
+ assertEquals(0, colorDocument.getElementsByTagName("item").getLength());
+
+ File publicXml = new File(sTestOrigDir,"res/values/public.xml");
+ Document publicDocument = TestUtils.getDocumentFromFile(publicXml);
+ assertEquals(21, publicDocument.getElementsByTagName("public").getLength());
+ }
+
+ @Test
+ public void checkDecodingModeAsDummies() throws BrutException, IOException {
+ String apk = "issue2836.apk";
+
+ Config config = Config.getDefaultConfig();
+ config.setDecodeResolveMode(Config.DECODE_RES_RESOLVE_DUMMY);
+
+ // decode issue2836.apk
+ ApkDecoder apkDecoder = new ApkDecoder(config, new File(sTmpDir + File.separator + apk));
+ sTestOrigDir = new ExtFile(sTmpDir + File.separator + apk + "dummies.out");
+
+ File outDir = new File(sTmpDir + File.separator + apk + "dummies.out");
+ apkDecoder.decode(outDir);
+
+ File stringsXml = new File(sTestOrigDir,"res/values/strings.xml");
+ assertTrue(stringsXml.isFile());
+
+ File attrXml = new File(sTestOrigDir,"res/values/attrs.xml");
+ Document attrDocument = TestUtils.getDocumentFromFile(attrXml);
+ assertEquals(4, attrDocument.getElementsByTagName("enum").getLength());
+
+ File colorXml = new File(sTestOrigDir,"res/values/colors.xml");
+ Document colorDocument = TestUtils.getDocumentFromFile(colorXml);
+ assertEquals(8, colorDocument.getElementsByTagName("color").getLength());
+ assertEquals(1, colorDocument.getElementsByTagName("item").getLength());
+
+ File publicXml = new File(sTestOrigDir,"res/values/public.xml");
+ Document publicDocument = TestUtils.getDocumentFromFile(publicXml);
+ assertEquals(22, publicDocument.getElementsByTagName("public").getLength());
+ }
+
+ @Test
+ public void checkDecodingModeAsLeave() throws BrutException, IOException {
+ String apk = "issue2836.apk";
+
+ Config config = Config.getDefaultConfig();
+ config.setDecodeResolveMode(Config.DECODE_RES_RESOLVE_RETAIN);
+
+ // decode issue2836.apk
+ ApkDecoder apkDecoder = new ApkDecoder(config, new File(sTmpDir + File.separator + apk));
+ sTestOrigDir = new ExtFile(sTmpDir + File.separator + apk + "leave.out");
+
+ File outDir = new File(sTmpDir + File.separator + apk + "leave.out");
+ apkDecoder.decode(outDir);
+
+ File stringsXml = new File(sTestOrigDir,"res/values/strings.xml");
+ assertTrue(stringsXml.isFile());
+
+ File attrXml = new File(sTestOrigDir,"res/values/attrs.xml");
+ Document attrDocument = TestUtils.getDocumentFromFile(attrXml);
+ assertEquals(4, attrDocument.getElementsByTagName("enum").getLength());
+
+ File colorXml = new File(sTestOrigDir,"res/values/colors.xml");
+ Document colorDocument = TestUtils.getDocumentFromFile(colorXml);
+ assertEquals(8, colorDocument.getElementsByTagName("color").getLength());
+ assertEquals(0, colorDocument.getElementsByTagName("item").getLength());
+
+ File publicXml = new File(sTestOrigDir,"res/values/public.xml");
+ Document publicDocument = TestUtils.getDocumentFromFile(publicXml);
+ assertEquals(21, publicDocument.getElementsByTagName("public").getLength());
+ }
+}
diff --git a/brut.apktool/apktool-lib/src/test/resources/aapt1/testapp/res/values-mcc001/arrays.xml b/brut.apktool/apktool-lib/src/test/resources/aapt1/testapp/res/values-mcc001/arrays.xml
index 141babbe..697a79d5 100644
--- a/brut.apktool/apktool-lib/src/test/resources/aapt1/testapp/res/values-mcc001/arrays.xml
+++ b/brut.apktool/apktool-lib/src/test/resources/aapt1/testapp/res/values-mcc001/arrays.xml
@@ -35,4 +35,7 @@
- res/
- view/
+
+ - MIICXAIBAAKBgQCjcGqTkOq0CR3rTx0ZSQSIdTrDrFAYl29611xN8aVgMQIWtDB/lD0W5TpKPuU9iaiG/sSn/VYt6EzN7Sr332jj7cyl2WrrHI6ujRswNy4HojMuqtfab5FFDpRmCuvl35fge18OvoQTJELhhJ1EvJ5KUeZiuJ3u3YyMnxxXzLuKbQIDAQABAoGAPrNDz7TKtaLBvaIuMaMXgBopHyQd3jFKbT/tg2Fu5kYm3PrnmCoQfZYXFKCoZUFIS/G1FBVWWGpD/MQ9tbYZkKpwuH+t2rGndMnLXiTC296/s9uix7gsjnT4Naci5N6EN9pVUBwQmGrYUTHFc58ThtelSiPARX7LSU2ibtJSv8ECQQDWBRrrAYmbCUN7ra0DFT6SppaDtvvuKtb+mUeKbg0B8U4y4wCIK5GH8EyQSwUWcXnNBO05rlUPbifsDLv/u82lAkEAw39sTJ0KmJJyaChqvqAJ8guulKlgucQJ0Et9ppZyet9iVwNKX/aW9UlwGBMQdafQ36nd1QMEA8AbAw4D+hw/KQJBANJbHDUGQtk2hrSmZNoV5HXB9Uiq7v4N71k5ER8XwgM5yVGs2tX8dMM3RhnBEtQXXs9LW1uJZSOQcv7JGXNnhN0CQBZenzrJAWxh3XtznHtBfsHWelyCYRIAj4rpCHCmaGUM6IjCVKFUawOYKp5mmAyObkUZf8ue87emJLEdynC1CLkCQHduNjP1hemAGWrd6v8BHhE3kKtcK6KHsPvJR5dOfzbdHAqVePERhISfN6cwZt5p8B3/JUwSR8el66DF7Jm57BM=
+
diff --git a/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-feminine/strings.xml b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-feminine/strings.xml
new file mode 100644
index 00000000..df52143f
--- /dev/null
+++ b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-feminine/strings.xml
@@ -0,0 +1,4 @@
+
+
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
\ No newline at end of file
diff --git a/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-neuter/strings.xml b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-neuter/strings.xml
new file mode 100644
index 00000000..df52143f
--- /dev/null
+++ b/brut.apktool/apktool-lib/src/test/resources/aapt2/testapp/res/values-neuter/strings.xml
@@ -0,0 +1,4 @@
+
+
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+
\ No newline at end of file
diff --git a/brut.apktool/apktool-lib/src/test/resources/decode/issue2836/issue2836.apk b/brut.apktool/apktool-lib/src/test/resources/decode/issue2836/issue2836.apk
new file mode 100644
index 00000000..367304fd
Binary files /dev/null and b/brut.apktool/apktool-lib/src/test/resources/decode/issue2836/issue2836.apk differ
diff --git a/brut.apktool/apktool-lib/src/test/resources/decode/issue3366/issue3366.apk b/brut.apktool/apktool-lib/src/test/resources/decode/issue3366/issue3366.apk
new file mode 100644
index 00000000..0bccfb8b
Binary files /dev/null and b/brut.apktool/apktool-lib/src/test/resources/decode/issue3366/issue3366.apk differ
diff --git a/brut.j.dir/build.gradle.kts b/brut.j.dir/build.gradle.kts
index 2792b209..d4865c80 100644
--- a/brut.j.dir/build.gradle.kts
+++ b/brut.j.dir/build.gradle.kts
@@ -1,7 +1,5 @@
-val commonsIoVersion: String by rootProject.extra
-
dependencies {
implementation(project(":brut.j.common"))
implementation(project(":brut.j.util"))
- implementation("commons-io:commons-io:$commonsIoVersion")
+ implementation(libs.commons.io)
}
diff --git a/brut.j.dir/src/main/java/brut/directory/AbstractDirectory.java b/brut.j.dir/src/main/java/brut/directory/AbstractDirectory.java
index ef7ddf50..ecd5da77 100644
--- a/brut.j.dir/src/main/java/brut/directory/AbstractDirectory.java
+++ b/brut.j.dir/src/main/java/brut/directory/AbstractDirectory.java
@@ -267,8 +267,7 @@ public abstract class AbstractDirectory implements Directory {
protected abstract AbstractDirectory createDirLocal(String name) throws DirectoryException;
protected abstract void removeFileLocal(String name);
-
- private class ParsedPath {
+ private static class ParsedPath {
public final String dir;
public final String subpath;
public ParsedPath(String dir, String subpath) {
@@ -277,7 +276,7 @@ public abstract class AbstractDirectory implements Directory {
}
}
- private class SubPath {
+ private static class SubPath {
public final AbstractDirectory dir;
public final String path;
diff --git a/brut.j.util/build.gradle.kts b/brut.j.util/build.gradle.kts
index b717cd3b..1f3a9234 100644
--- a/brut.j.util/build.gradle.kts
+++ b/brut.j.util/build.gradle.kts
@@ -1,8 +1,5 @@
-val commonsIoVersion: String by rootProject.extra
-val guavaVersion: String by rootProject.extra
-
dependencies {
implementation(project(":brut.j.common"))
- implementation("commons-io:commons-io:$commonsIoVersion")
- implementation("com.google.guava:guava:$guavaVersion")
+ implementation(libs.commons.io)
+ implementation(libs.guava)
}
diff --git a/build.gradle.kts b/build.gradle.kts
index ae8ad636..268ff87c 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,18 +1,7 @@
import java.io.ByteArrayOutputStream
-val baksmaliVersion by extra("3.0.3")
-val commonsCliVersion by extra("1.5.0")
-val commonsIoVersion by extra("2.13.0")
-val commonsLangVersion by extra("3.13.0")
-val commonsTextVersion by extra("1.10.0")
-val guavaVersion by extra("32.0.1-jre")
-val junitVersion by extra("4.13.2")
-val smaliVersion by extra("3.0.3")
-val xmlpullVersion by extra("1.1.4c")
-val xmlunitVersion by extra("2.9.1")
-
-val version = "2.8.2"
-val suffix = "6"
+val version = "2.9.1"
+val suffix = "SNAPSHOT"
// Strings embedded into the build.
var gitRevision by extra("")
@@ -66,17 +55,12 @@ if ("release" !in gradle.startParameter.taskNames) {
}
plugins {
- id("com.github.johnrengelman.shadow") version "8.1.1"
+ alias(libs.plugins.shadow)
`java-library`
`maven-publish`
signing
}
-java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
-}
-
tasks.withType {
options.compilerArgs.add("-Xlint:-options")
options.compilerArgs.add("--release 8")
@@ -95,6 +79,11 @@ subprojects {
apply(plugin = "java")
apply(plugin = "java-library")
+ java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
val mavenProjects = arrayOf("apktool-lib", "apktool-cli", "brut.j.common", "brut.j.util", "brut.j.dir")
if (project.name in mavenProjects) {
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 00000000..a4bc12ae
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,62 @@
+# BUILDER
+# =====================================================
+FROM ibm-semeru-runtimes:open-17-jdk-jammy AS builder
+
+COPY . /build
+WORKDIR /build
+RUN \
+ # Apktool
+ ./gradlew build shadowJar proguard
+
+RUN \
+ # Relocate for easier copying
+ JAR=$(find /build/brut.apktool/apktool-cli/build/libs/apktool-*.jar |grep -v cli-all) &&\
+ mv ${JAR} /build/apktool.jar
+
+# BASE
+# =====================================================
+FROM ibm-semeru-runtimes:open-17-jre-jammy AS base
+
+# Latest version as of 2023.10.01
+# Ref: https://developer.android.com/studio/index.html#command-line-tools-only
+ARG COMMAND_LINE_TOOLS_VERSION=10406996
+
+ARG ANDROID_SDK_ROOT=/opt/android-sdk
+
+COPY --from=builder /build/apktool.jar /usr/local/bin/apktool.jar
+COPY --from=builder /build/scripts/linux/apktool /usr/local/bin/apktool
+
+RUN \
+ # Update
+ apt-get update &&\
+ \
+ # Apktool final setup
+ chmod +x /usr/local/bin/apktool /usr/local/bin/apktool.jar &&\
+ \
+ # Android SDK
+ apt-get install -y --no-install-recommends \
+ ca-certificates \
+ curl \
+ zipalign \
+ git \
+ openssl \
+ wget \
+ unzip \
+ sdkmanager &&\
+ curl -o /tmp/tools.zip https://dl.google.com/android/repository/commandlinetools-linux-${COMMAND_LINE_TOOLS_VERSION}_latest.zip &&\
+ mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools &&\
+ unzip -q /tmp/tools.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools &&\
+ mv ${ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools ${ANDROID_SDK_ROOT}/cmdline-tools/latest &&\
+ rm -v /tmp/tools.zip &&\
+ mkdir -p /root/.android/ && touch /root/.android/repositories.cfg &&\
+ yes | sdkmanager --licenses &&\
+ export BUILD_TOOLS_VERSION=$(sdkmanager --list |grep build-tools |grep -v rc |awk '{print $1}' |sed 's/build-tools;//g' |sort |tail -n1) &&\
+ sdkmanager --install "build-tools;${BUILD_TOOLS_VERSION}" &&\
+ ln -s ${ANDROID_SDK_ROOT}/build-tools/${BUILD_TOOLS_VERSION} /opt/bin &&\
+ \
+ # Cleanup
+ rm -rf /var/lib/apt/lists/*
+
+ENV PATH ${PATH}:/opt/bin
+
+CMD ["/usr/local/bin/apktool"]
\ No newline at end of file
diff --git a/docker/README.md b/docker/README.md
new file mode 100644
index 00000000..f0bdbdf1
--- /dev/null
+++ b/docker/README.md
@@ -0,0 +1,27 @@
+# Apktool in Docker
+We provide an easy way to leverage `apktool`, along with common Android tools such as `zipalign` and `apksigner`, all from within Docker.
+
+## Building the Docker image
+To use the image, pull or build with the included Dockerfile:
+```bash
+docker pull ghcr.io/ibotpeaches/apktool:latest
+# OR
+docker build -t apktool:local .
+```
+
+## Using the Docker image
+The best way to use the image is to create aliases to run the internal commands. Replace `ghcr.io/ibotpeaches/apktool:latest` with `apktool:local` if you have built the image locally.
+```bash
+alias apktool="docker run --rm -ti --name=apktool -v \"${PWD}:${PWD}\" -w \"${PWD}\" ghcr.io/ibotpeaches/apktool:latest apktool"
+alias zipalign="docker run --rm -ti --name=zipalign -v \"${PWD}:${PWD}\" -w \"${PWD}\" ghcr.io/ibotpeaches/apktool:latest zipalign"
+alias apksigner="docker run --rm -ti --name=apksigner -v \"${PWD}:${PWD}\" -w \"${PWD}\" ghcr.io/ibotpeaches/apktool:latest apksigner"
+```
+
+## Running the commands
+You can then utilize these commands as you would if they were natively installed:
+```bash
+apktool d My.apk -o MyFolder
+apktool b MyFolder -o MyNew.apk
+zipalign -p -f 4 MyNew.apk MyNewAligned.apk
+apksigner sign --ks My.keystore MyNewAligned.apk
+```
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 00000000..611f22ae
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,29 @@
+[versions]
+baksmali = "3.0.3"
+commons_io = "2.14.0"
+commons_cli = "1.5.0"
+commons_lang3 = "3.13.0"
+commons_text = "1.10.0"
+guava = "32.0.1-jre"
+junit = "4.13.2"
+proguard = "7.3.2"
+shadow = "8.1.1"
+smali = "3.0.3"
+xmlpull = "1.1.4c"
+xmlunit = "2.9.1"
+
+[libraries]
+baksmali = { module = "com.android.tools.smali:smali-baksmali", version.ref = "baksmali" }
+commons_cli = { module = "commons-cli:commons-cli", version.ref = "commons_cli"}
+commons_io = { module = "commons-io:commons-io", version.ref = "commons_io" }
+commons_lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commons_lang3" }
+commons_text = { module = "org.apache.commons:commons-text", version.ref = "commons_text" }
+guava = { module = "com.google.guava:guava", version.ref = "guava" }
+junit = { module = "junit:junit", version.ref = "junit" }
+proguard = { module = "com.guardsquare:proguard-gradle", version.ref = "proguard" }
+smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
+xmlpull = { module = "xpp3:xpp3", version.ref = "xmlpull" }
+xmlunit = { module = "org.xmlunit:xmlunit-legacy", version.ref = "xmlunit" }
+
+[plugins]
+shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
diff --git a/scripts/windows/apktool.bat b/scripts/windows/apktool.bat
index 08adf635..ee2d4da3 100755
--- a/scripts/windows/apktool.bat
+++ b/scripts/windows/apktool.bat
@@ -39,4 +39,4 @@ if "%ATTR:~0,1%"=="-" if "%~x1"==".apk" (
"%java_exe%" -jar -Xmx1024M -Duser.language=en -Dfile.encoding=UTF8 -Djdk.util.zip.disableZip64ExtraFieldValidation=true -Djdk.nio.zipfs.allowDotZipEntry=true "%~dp0%BASENAME%%max%.jar" %fastCommand% %*
rem Pause when ran non interactively
-for /f "tokens=2" %%# in ("%cmdcmdline%") do if /i "%%#" equ "/c" pause
+for %%i in (%cmdcmdline%) do if /i "%%~i"=="/c" pause & exit /b
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 9fffe0ae..db82a26b 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,2 +1,8 @@
rootProject.name = "apktool-cli"
include("brut.j.common", "brut.j.util", "brut.j.dir", "brut.apktool:apktool-lib", "brut.apktool:apktool-cli")
+
+dependencyResolutionManagement {
+ versionCatalogs {
+ create("libs") {}
+ }
+}